Bug 417561, disable tagging of Talkback now we have prebuilt packages, r=rhelmer
[mozilla-1.9.git] / layout / generic / nsObjectFrame.cpp
blobe206865b25b98ded1f5b21bfcbc6e66149c289ab
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>
32 * Alternatively, the contents of this file may be used under the terms of
33 * either of the GNU General Public License Version 2 or later (the "GPL"),
34 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 * in which case the provisions of the GPL or the LGPL are applicable instead
36 * of those above. If you wish to allow use of your version of this file only
37 * under the terms of either the GPL or the LGPL, and not to allow others to
38 * use your version of this file under the terms of the MPL, indicate your
39 * decision by deleting the provisions above and replace them with the notice
40 * and other provisions required by the GPL or the LGPL. If you do not delete
41 * the provisions above, a recipient may use your version of this file under
42 * the terms of any one of the MPL, the GPL or the LGPL.
44 * ***** END LICENSE BLOCK ***** */
46 /* rendering objects for replaced elements implemented by a plugin */
48 #include "nscore.h"
49 #include "nsCOMPtr.h"
50 #include "nsPresContext.h"
51 #include "nsIPresShell.h"
52 #include "nsWidgetsCID.h"
53 #include "nsIView.h"
54 #include "nsIViewManager.h"
55 #include "nsIDOMKeyListener.h"
56 #include "nsIPluginHost.h"
57 #include "nsplugin.h"
58 #include "nsString.h"
59 #include "nsReadableUtils.h"
60 #include "prmem.h"
61 #include "nsGkAtoms.h"
62 #include "nsIAppShell.h"
63 #include "nsIDocument.h"
64 #include "nsINodeInfo.h"
65 #include "nsIURL.h"
66 #include "nsNetUtil.h"
67 #include "nsIPluginInstanceOwner.h"
68 #include "plstr.h"
69 #include "nsILinkHandler.h"
70 #ifdef OJI
71 #include "nsIJVMPluginTagInfo.h"
72 #endif
73 #include "nsIEventListener.h"
74 #include "nsIScrollableView.h"
75 #include "nsIScrollPositionListener.h"
76 #include "nsITimer.h"
77 #include "nsIDocShellTreeItem.h"
78 #include "nsIDocShellTreeOwner.h"
79 #include "nsDocShellCID.h"
80 #include "nsIWebBrowserChrome.h"
81 #include "nsIDOMElement.h"
82 #include "nsIDOMNodeList.h"
83 #include "nsIDOMHTMLObjectElement.h"
84 #include "nsIDOMHTMLEmbedElement.h"
85 #include "nsIDOMHTMLAppletElement.h"
86 #include "nsIDOMWindow.h"
87 #include "nsIDOMDocumentEvent.h"
88 #include "nsIDOMMouseListener.h"
89 #include "nsIDOMMouseMotionListener.h"
90 #include "nsIDOMFocusListener.h"
91 #include "nsIDOMContextMenuListener.h"
92 #include "nsIDOMDragListener.h"
93 #include "nsIDOMEventTarget.h"
94 #include "nsIDOMNSEvent.h"
95 #include "nsIPrivateDOMEvent.h"
96 #include "nsIDocumentEncoder.h"
97 #include "nsXPIDLString.h"
98 #include "nsIDOMRange.h"
99 #include "nsIPluginWidget.h"
100 #include "nsGUIEvent.h"
101 #include "nsIRenderingContext.h"
102 #include "npapi.h"
103 #include "nsTransform2D.h"
104 #include "nsIImageLoadingContent.h"
105 #include "nsIObjectLoadingContent.h"
106 #include "nsPIDOMWindow.h"
107 #include "nsContentUtils.h"
108 #include "nsDisplayList.h"
109 #include "nsAttrName.h"
110 #include "nsDataHashtable.h"
112 // headers for plugin scriptability
113 #include "nsIScriptGlobalObject.h"
114 #include "nsIScriptContext.h"
115 #include "nsIXPConnect.h"
116 #include "nsIXPCScriptable.h"
117 #include "nsIClassInfo.h"
119 #include "nsObjectFrame.h"
120 #include "nsIObjectFrame.h"
121 #include "nsPluginNativeWindow.h"
122 #include "nsPIPluginHost.h"
123 #include "nsIPluginDocument.h"
125 #include "nsThreadUtils.h"
127 #include "gfxContext.h"
129 #ifdef XP_WIN
130 #include "gfxWindowsNativeDrawing.h"
131 #endif
133 // accessibility support
134 #ifdef ACCESSIBILITY
135 #include "nsIAccessibilityService.h"
136 #endif
138 #ifdef MOZ_LOGGING
139 #define FORCE_PR_LOG 1 /* Allow logging in the release build */
140 #endif /* MOZ_LOGGING */
141 #include "prlog.h"
143 #include <errno.h>
145 #include "nsContentCID.h"
146 static NS_DEFINE_CID(kRangeCID, NS_RANGE_CID);
148 #ifdef XP_MACOSX
149 #include "gfxQuartzNativeDrawing.h"
150 #endif
152 #ifdef MOZ_X11
153 #include <X11/Xlib.h>
154 /* X headers suck */
155 enum { XKeyPress = KeyPress };
156 #ifdef KeyPress
157 #undef KeyPress
158 #endif
159 #include "gfxXlibNativeRenderer.h"
160 #ifdef MOZ_WIDGET_GTK2
161 #include <gdk/gdkwindow.h>
162 #include <gdk/gdkx.h>
163 #endif
164 #endif
166 #ifdef XP_WIN
167 #include <wtypes.h>
168 #include <winuser.h>
169 #endif
171 #ifdef CreateEvent // Thank you MS.
172 #undef CreateEvent
173 #endif
175 #ifdef PR_LOGGING
176 static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame");
177 #endif /* PR_LOGGING */
179 // 1020 / 60
180 #define NORMAL_PLUGIN_DELAY 17
182 // low enough to avoid audio skipping/delays
183 #define HIDDEN_PLUGIN_DELAY 100
185 // special class for handeling DOM context menu events because for
186 // some reason it starves other mouse events if implemented on the
187 // same class
188 class nsPluginDOMContextMenuListener : public nsIDOMContextMenuListener,
189 public nsIEventListener
191 public:
192 nsPluginDOMContextMenuListener();
193 virtual ~nsPluginDOMContextMenuListener();
195 NS_DECL_ISUPPORTS
197 NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent);
199 nsresult Init(nsIContent* aContent);
200 nsresult Destroy(nsIContent* aContent);
202 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent)
204 return NS_OK;
206 nsEventStatus ProcessEvent(const nsGUIEvent& anEvent)
208 return nsEventStatus_eConsumeNoDefault;
213 class nsPluginInstanceOwner : public nsIPluginInstanceOwner,
214 public nsIPluginTagInfo2,
215 #ifdef OJI
216 public nsIJVMPluginTagInfo,
217 #endif
218 public nsIEventListener,
219 public nsITimerCallback,
220 public nsIDOMMouseListener,
221 public nsIDOMMouseMotionListener,
222 public nsIDOMKeyListener,
223 public nsIDOMFocusListener,
224 public nsIScrollPositionListener,
225 public nsIDOMDragListener
228 public:
229 nsPluginInstanceOwner();
230 virtual ~nsPluginInstanceOwner();
232 NS_DECL_ISUPPORTS
234 //nsIPluginInstanceOwner interface
236 NS_IMETHOD SetInstance(nsIPluginInstance *aInstance);
238 NS_IMETHOD GetInstance(nsIPluginInstance *&aInstance);
240 NS_IMETHOD GetWindow(nsPluginWindow *&aWindow);
242 NS_IMETHOD GetMode(nsPluginMode *aMode);
244 NS_IMETHOD CreateWidget(void);
246 NS_IMETHOD GetURL(const char *aURL, const char *aTarget, void *aPostData,
247 PRUint32 aPostDataLen, void *aHeadersData,
248 PRUint32 aHeadersDataLen, PRBool isFile = PR_FALSE);
250 NS_IMETHOD ShowStatus(const char *aStatusMsg);
252 NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
254 NS_IMETHOD GetDocument(nsIDocument* *aDocument);
256 NS_IMETHOD InvalidateRect(nsPluginRect *invalidRect);
258 NS_IMETHOD InvalidateRegion(nsPluginRegion invalidRegion);
260 NS_IMETHOD ForceRedraw();
262 NS_IMETHOD GetValue(nsPluginInstancePeerVariable variable, void *value);
264 //nsIPluginTagInfo interface
266 NS_IMETHOD GetAttributes(PRUint16& n, const char*const*& names,
267 const char*const*& values);
269 NS_IMETHOD GetAttribute(const char* name, const char* *result);
271 //nsIPluginTagInfo2 interface
273 NS_IMETHOD GetTagType(nsPluginTagType *result);
275 NS_IMETHOD GetTagText(const char* *result);
277 NS_IMETHOD GetParameters(PRUint16& n, const char*const*& names, const char*const*& values);
279 NS_IMETHOD GetParameter(const char* name, const char* *result);
281 NS_IMETHOD GetDocumentBase(const char* *result);
283 NS_IMETHOD GetDocumentEncoding(const char* *result);
285 NS_IMETHOD GetAlignment(const char* *result);
287 NS_IMETHOD GetWidth(PRUint32 *result);
289 NS_IMETHOD GetHeight(PRUint32 *result);
291 NS_IMETHOD GetBorderVertSpace(PRUint32 *result);
293 NS_IMETHOD GetBorderHorizSpace(PRUint32 *result);
295 NS_IMETHOD GetUniqueID(PRUint32 *result);
297 NS_IMETHOD GetDOMElement(nsIDOMElement* *result);
299 #ifdef OJI
300 //nsIJVMPluginTagInfo interface
302 NS_IMETHOD GetCode(const char* *result);
304 NS_IMETHOD GetCodeBase(const char* *result);
306 NS_IMETHOD GetArchive(const char* *result);
308 NS_IMETHOD GetName(const char* *result);
310 NS_IMETHOD GetMayScript(PRBool *result);
312 #endif /* OJI */
314 /** nsIDOMMouseListener interfaces
315 * @see nsIDOMMouseListener
317 NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
318 NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
319 NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
320 NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
321 NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
322 NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
323 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
324 /* END interfaces from nsIDOMMouseListener*/
326 // nsIDOMMouseListener intefaces
327 NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent);
328 NS_IMETHOD DragMove(nsIDOMEvent* aMouseEvent) { return NS_OK; }
330 // nsIDOMKeyListener interfaces
331 NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
332 NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
333 NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
334 // end nsIDOMKeyListener interfaces
336 // nsIDOMFocuListener interfaces
337 NS_IMETHOD Focus(nsIDOMEvent * aFocusEvent);
338 NS_IMETHOD Blur(nsIDOMEvent * aFocusEvent);
340 // nsIDOMDragListener interfaces
341 NS_IMETHOD DragEnter(nsIDOMEvent* aMouseEvent);
342 NS_IMETHOD DragOver(nsIDOMEvent* aMouseEvent);
343 NS_IMETHOD DragExit(nsIDOMEvent* aMouseEvent);
344 NS_IMETHOD DragDrop(nsIDOMEvent* aMouseEvent);
345 NS_IMETHOD DragGesture(nsIDOMEvent* aMouseEvent);
346 NS_IMETHOD Drag(nsIDOMEvent* aMouseEvent);
347 NS_IMETHOD DragEnd(nsIDOMEvent* aMouseEvent);
350 nsresult Destroy();
352 void PrepareToStop(PRBool aDelayedStop);
354 //nsIEventListener interface
355 nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
357 #ifdef XP_WIN
358 void Paint(const nsRect& aDirtyRect, HDC ndc);
359 #elif defined(XP_MACOSX)
360 void Paint(const nsRect& aDirtyRect);
361 #elif defined(MOZ_X11)
362 void Paint(nsIRenderingContext& aRenderingContext,
363 const nsRect& aDirtyRect);
364 #endif
366 // nsITimerCallback interface
367 NS_DECL_NSITIMERCALLBACK
369 void CancelTimer();
370 void StartTimer(unsigned int aDelay);
372 // nsIScrollPositionListener interface
373 NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
374 NS_IMETHOD ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
376 //locals
378 nsresult Init(nsPresContext* aPresContext, nsObjectFrame* aFrame,
379 nsIContent* aContent);
381 nsPluginPort* GetPluginPort();
382 void ReleasePluginPort(nsPluginPort * pluginPort);
384 void SetPluginHost(nsIPluginHost* aHost);
386 #ifdef XP_MACOSX
387 NPDrawingModel GetDrawingModel();
388 WindowRef FixUpPluginWindow(PRInt32 inPaintState);
389 void GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord* origEvent, EventRecord& aMacEvent);
390 #endif
392 void SetOwner(nsObjectFrame *aOwner)
394 mOwner = aOwner;
397 private:
398 void FixUpURLS(const nsString &name, nsAString &value);
400 nsPluginNativeWindow *mPluginWindow;
401 nsCOMPtr<nsIPluginInstance> mInstance;
402 nsObjectFrame *mOwner;
403 nsCOMPtr<nsIContent> mContent;
404 nsCString mDocumentBase;
405 char *mTagText;
406 nsCOMPtr<nsIWidget> mWidget;
407 nsCOMPtr<nsITimer> mPluginTimer;
408 nsCOMPtr<nsIPluginHost> mPluginHost;
409 PRPackedBool mContentFocused;
410 PRPackedBool mWidgetVisible; // used on Mac to store our widget's visible state
412 // If true, destroy the widget on destruction. Used when plugin stop
413 // is being delayed to a safer point in time.
414 PRPackedBool mDestroyWidget;
415 PRUint16 mNumCachedAttrs;
416 PRUint16 mNumCachedParams;
417 char **mCachedAttrParamNames;
418 char **mCachedAttrParamValues;
420 // pointer to wrapper for nsIDOMContextMenuListener
421 nsRefPtr<nsPluginDOMContextMenuListener> mCXMenuListener;
423 nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
424 nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent);
425 nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
427 nsresult EnsureCachedAttrParamArrays();
429 #ifdef MOZ_X11
430 class Renderer : public gfxXlibNativeRenderer {
431 public:
432 Renderer(nsPluginWindow* aWindow, nsIPluginInstance* aInstance,
433 const nsIntRect& aDirtyRect)
434 : mWindow(aWindow), mInstance(aInstance), mDirtyRect(aDirtyRect)
436 virtual nsresult NativeDraw(Display* dpy, Drawable drawable, Visual* visual,
437 short offsetX, short offsetY,
438 XRectangle* clipRects, PRUint32 numClipRects);
439 private:
440 nsPluginWindow* mWindow;
441 nsIPluginInstance* mInstance;
442 const nsIntRect& mDirtyRect;
444 #endif
448 #if defined(XP_WIN) || (defined(DO_DIRTY_INTERSECT) && defined(XP_MACOSX)) || defined(MOZ_X11)
449 static void ConvertAppUnitsToPixels(const nsPresContext& aPresContext, const nsRect& aTwipsRect, nsIntRect& aPixelRect);
450 #endif
452 // Mac specific code to fix up port position and clip during paint
453 #ifdef XP_MACOSX
455 #ifdef DO_DIRTY_INTERSECT
456 // convert relative coordinates to absolute
457 static void ConvertRelativeToWindowAbsolute(nsIFrame* aFrame, nsPoint& aRel, nsPoint& aAbs, nsIWidget *&aContainerWidget);
458 #endif
460 enum { ePluginPaintIgnore, ePluginPaintEnable, ePluginPaintDisable };
462 #endif // XP_MACOSX
464 nsObjectFrame::nsObjectFrame(nsStyleContext* aContext)
465 : nsObjectFrameSuper(aContext)
467 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
468 ("Created new nsObjectFrame %p\n", this));
471 nsObjectFrame::~nsObjectFrame()
473 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
474 ("nsObjectFrame %p deleted\n", this));
477 NS_IMETHODIMP
478 nsObjectFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
480 NS_PRECONDITION(aInstancePtr, "null out param");
482 if (aIID.Equals(NS_GET_IID(nsIObjectFrame))) {
483 *aInstancePtr = static_cast<nsIObjectFrame*>(this);
484 return NS_OK;
487 return nsObjectFrameSuper::QueryInterface(aIID, aInstancePtr);
490 NS_IMETHODIMP_(nsrefcnt) nsObjectFrame::AddRef(void)
492 NS_WARNING("not supported for frames");
493 return 1;
496 NS_IMETHODIMP_(nsrefcnt) nsObjectFrame::Release(void)
498 NS_WARNING("not supported for frames");
499 return 1;
502 #ifdef ACCESSIBILITY
503 NS_IMETHODIMP nsObjectFrame::GetAccessible(nsIAccessible** aAccessible)
505 nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
507 if (accService) {
508 return accService->CreateHTMLObjectFrameAccessible(this, aAccessible);
511 return NS_ERROR_FAILURE;
514 #ifdef XP_WIN
515 NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
517 *aPort = (HWND) mInstanceOwner->GetPluginPort();
518 return NS_OK;
520 #endif
521 #endif
524 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
525 static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
527 // #define DO_DIRTY_INTERSECT 1 // enable dirty rect intersection during paint
529 NS_IMETHODIMP
530 nsObjectFrame::Init(nsIContent* aContent,
531 nsIFrame* aParent,
532 nsIFrame* aPrevInFlow)
534 mInstantiating = PR_FALSE;
536 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
537 ("Initializing nsObjectFrame %p for content %p\n", this, aContent));
539 return nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow);
542 void
543 nsObjectFrame::Destroy()
545 NS_ASSERTION(!mInstantiating, "about to crash due to bug 136927");
547 // we need to finish with the plugin before native window is destroyed
548 // doing this in the destructor is too late.
549 StopPluginInternal(PR_TRUE);
551 nsObjectFrameSuper::Destroy();
554 NS_IMETHODIMP
555 nsObjectFrame::DidSetStyleContext()
557 if (HasView()) {
558 nsIView* view = GetView();
559 nsIViewManager* vm = view->GetViewManager();
560 if (vm) {
561 nsViewVisibility visibility =
562 IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
563 vm->SetViewVisibility(view, visibility);
567 return nsObjectFrameSuper::DidSetStyleContext();
570 nsIAtom*
571 nsObjectFrame::GetType() const
573 return nsGkAtoms::objectFrame;
576 #ifdef DEBUG
577 NS_IMETHODIMP
578 nsObjectFrame::GetFrameName(nsAString& aResult) const
580 return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
582 #endif
584 nsresult
585 nsObjectFrame::CreateWidgetForView(nsIView* aView)
587 // Bug 179822: Create widget and allow non-unicode SubClass
588 nsWidgetInitData initData;
589 initData.mUnicode = PR_FALSE;
590 return aView->CreateWidget(kWidgetCID, &initData);
593 nsresult
594 nsObjectFrame::CreateWidget(nscoord aWidth,
595 nscoord aHeight,
596 PRBool aViewOnly)
598 nsIView* view = GetView();
599 NS_ASSERTION(view, "Object frames must have views");
600 if (!view) {
601 return NS_OK; //XXX why OK? MMP
604 nsIViewManager* viewMan = view->GetViewManager();
605 // mark the view as hidden since we don't know the (x,y) until Paint
606 // XXX is the above comment correct?
607 viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
609 //this is ugly. it was ripped off from didreflow(). MMP
610 // Position and size view relative to its parent, not relative to our
611 // parent frame (our parent frame may not have a view).
613 nsIView* parentWithView;
614 nsPoint origin;
615 nsRect r(0, 0, mRect.width, mRect.height);
617 GetOffsetFromView(origin, &parentWithView);
618 viewMan->ResizeView(view, r);
619 viewMan->MoveViewTo(view, origin.x, origin.y);
621 if (!aViewOnly && !view->HasWidget()) {
622 nsresult rv = CreateWidgetForView(view);
623 if (NS_FAILED(rv)) {
624 return NS_OK; //XXX why OK? MMP
629 // Here we set the background color for this widget because some plugins will use
630 // the child window background color when painting. If it's not set, it may default to gray
631 // Sometimes, a frame doesn't have a background color or is transparent. In this
632 // case, walk up the frame tree until we do find a frame with a background color
633 for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
634 const nsStyleBackground* background = frame->GetStyleBackground();
635 if (!background->IsTransparent()) { // make sure we got an actual color
636 nsIWidget* win = view->GetWidget();
637 if (win)
638 win->SetBackgroundColor(background->mBackgroundColor);
639 break;
645 if (!IsHidden()) {
646 viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
649 return NS_OK;
652 #define EMBED_DEF_WIDTH 240
653 #define EMBED_DEF_HEIGHT 200
655 /* virtual */ nscoord
656 nsObjectFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
658 nscoord result = 0;
660 if (!IsHidden(PR_FALSE)) {
661 nsIAtom *atom = mContent->Tag();
662 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
663 result = nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH);
667 DISPLAY_MIN_WIDTH(this, result);
668 return result;
671 /* virtual */ nscoord
672 nsObjectFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
674 return nsObjectFrame::GetMinWidth(aRenderingContext);
677 void
678 nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext,
679 const nsHTMLReflowState& aReflowState,
680 nsHTMLReflowMetrics& aMetrics)
682 // By default, we have no area
683 aMetrics.width = 0;
684 aMetrics.height = 0;
686 if (IsHidden(PR_FALSE)) {
687 return;
690 aMetrics.width = aReflowState.ComputedWidth();
691 aMetrics.height = aReflowState.ComputedHeight();
693 // for EMBED and APPLET, default to 240x200 for compatibility
694 nsIAtom *atom = mContent->Tag();
695 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
696 if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
697 aMetrics.width = PR_MIN(PR_MAX(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH),
698 aReflowState.mComputedMinWidth),
699 aReflowState.mComputedMaxWidth);
701 if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
702 aMetrics.height = PR_MIN(PR_MAX(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT),
703 aReflowState.mComputedMinHeight),
704 aReflowState.mComputedMaxHeight);
707 #if defined (MOZ_WIDGET_GTK2)
708 // We need to make sure that the size of the object frame does not
709 // exceed the maximum size of X coordinates. See bug #225357 for
710 // more information. In theory Gtk2 can handle large coordinates,
711 // but underlying plugins can't.
712 aMetrics.height = PR_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.height);
713 aMetrics.width = PR_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.width);
714 #endif
717 // At this point, the width has an unconstrained value only if we have
718 // nothing to go on (no width set, no information from the plugin, nothing).
719 // Make up a number.
720 if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
721 aMetrics.width =
722 (aReflowState.mComputedMinWidth != NS_UNCONSTRAINEDSIZE) ?
723 aReflowState.mComputedMinWidth : 0;
726 // At this point, the height has an unconstrained value only in two cases:
727 // a) We are in standards mode with percent heights and parent is auto-height
728 // b) We have no height information at all.
729 // In either case, we have to make up a number.
730 if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
731 aMetrics.height =
732 (aReflowState.mComputedMinHeight != NS_UNCONSTRAINEDSIZE) ?
733 aReflowState.mComputedMinHeight : 0;
736 // XXXbz don't add in the border and padding, because we screw up our
737 // plugin's size and positioning if we do... Eventually we _do_ want to
738 // paint borders, though! At that point, we will need to adjust the desired
739 // size either here or in Reflow.... Further, we will need to fix Paint() to
740 // call the superclass in all cases.
743 NS_IMETHODIMP
744 nsObjectFrame::Reflow(nsPresContext* aPresContext,
745 nsHTMLReflowMetrics& aMetrics,
746 const nsHTMLReflowState& aReflowState,
747 nsReflowStatus& aStatus)
749 DO_GLOBAL_REFLOW_COUNT("nsObjectFrame");
750 DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
752 // Get our desired size
753 GetDesiredSize(aPresContext, aReflowState, aMetrics);
754 aMetrics.mOverflowArea = nsRect(0, 0,
755 aMetrics.width, aMetrics.height);
757 // delay plugin instantiation until all children have
758 // arrived. Otherwise there may be PARAMs or other stuff that the
759 // plugin needs to see that haven't arrived yet.
760 if (!GetContent()->IsDoneAddingChildren()) {
761 aStatus = NS_FRAME_COMPLETE;
762 return NS_OK;
765 // if we are printing or print previewing, bail for now
766 if (aPresContext->Medium() == nsGkAtoms::print) {
767 aStatus = NS_FRAME_COMPLETE;
768 return NS_OK;
771 FixupWindow(nsSize(aMetrics.width, aMetrics.height));
773 aStatus = NS_FRAME_COMPLETE;
775 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
776 return NS_OK;
779 nsresult
780 nsObjectFrame::InstantiatePlugin(nsIPluginHost* aPluginHost,
781 const char* aMimeType,
782 nsIURI* aURI)
784 // If you add early return(s), be sure to balance this call to
785 // appShell->SuspendNative() with additional call(s) to
786 // appShell->ReturnNative().
787 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
788 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
789 if (appShell) {
790 appShell->SuspendNative();
793 NS_PRECONDITION(!mInstantiating, "How did that happen?");
794 mInstantiating = PR_TRUE;
796 NS_ASSERTION(mContent, "We should have a content node.");
798 nsIDocument* doc = mContent->GetOwnerDoc();
799 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
801 nsresult rv;
802 if (pDoc) { /* full-page mode */
803 nsCOMPtr<nsIStreamListener> stream;
804 rv = aPluginHost->InstantiateFullPagePlugin(aMimeType, aURI,
805 /* resulting stream listener */ *getter_AddRefs(stream),
806 mInstanceOwner);
807 if (NS_SUCCEEDED(rv))
808 pDoc->SetStreamListener(stream);
809 } else { /* embedded mode */
810 rv = aPluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI,
811 mInstanceOwner);
813 mInstantiating = PR_FALSE;
815 if (appShell) {
816 appShell->ResumeNative();
819 return rv;
822 void
823 nsObjectFrame::FixupWindow(const nsSize& aSize)
825 nsPresContext* presContext = PresContext();
827 if (!mInstanceOwner)
828 return;
830 nsPluginWindow *window;
831 mInstanceOwner->GetWindow(window);
833 NS_ENSURE_TRUE(window, /**/);
835 #ifdef XP_MACOSX
836 mInstanceOwner->FixUpPluginWindow(ePluginPaintDisable);
837 #endif
839 PRBool windowless = (window->type == nsPluginWindowType_Drawable);
841 nsPoint origin = GetWindowOriginInPixels(windowless);
843 window->x = origin.x;
844 window->y = origin.y;
846 window->width = presContext->AppUnitsToDevPixels(aSize.width);
847 window->height = presContext->AppUnitsToDevPixels(aSize.height);
849 // on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep
850 // us from drawing on screen until the widget is properly positioned, which will not
851 // happen until we have finished the reflow process.
852 window->clipRect.top = 0;
853 window->clipRect.left = 0;
854 #ifdef XP_MACOSX
855 window->clipRect.bottom = 0;
856 window->clipRect.right = 0;
857 #else
858 window->clipRect.bottom = presContext->AppUnitsToDevPixels(aSize.height);
859 window->clipRect.right = presContext->AppUnitsToDevPixels(aSize.width);
860 #endif
863 void
864 nsObjectFrame::CallSetWindow()
866 nsPluginWindow *win = nsnull;
868 nsresult rv;
869 nsCOMPtr<nsIPluginInstance> pi;
870 if (!mInstanceOwner ||
871 NS_FAILED(rv = mInstanceOwner->GetInstance(*getter_AddRefs(pi))) ||
872 !pi ||
873 NS_FAILED(rv = mInstanceOwner->GetWindow(win)) ||
874 !win)
875 return;
877 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
879 #ifdef XP_MACOSX
880 mInstanceOwner->FixUpPluginWindow(ePluginPaintDisable);
881 #endif
883 if (IsHidden())
884 return;
886 PRBool windowless = (window->type == nsPluginWindowType_Drawable);
888 nsPoint origin = GetWindowOriginInPixels(windowless);
890 window->x = origin.x;
891 window->y = origin.y;
893 // refresh the plugin port as well
894 #ifdef MOZ_X11
895 if(windowless) {
896 // There is no plugin port window but there are some extra fields to
897 // fill in.
898 nsIWidget* widget = GetWindow();
899 if (widget) {
900 NPSetWindowCallbackStruct* ws_info =
901 static_cast<NPSetWindowCallbackStruct*>(window->ws_info);
902 ws_info->display =
903 static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY));
904 #ifdef MOZ_WIDGET_GTK2
905 GdkWindow* gdkWindow =
906 static_cast<GdkWindow*>(widget->GetNativeData(NS_NATIVE_WINDOW));
907 GdkColormap* gdkColormap = gdk_drawable_get_colormap(gdkWindow);
908 ws_info->colormap = gdk_x11_colormap_get_xcolormap(gdkColormap);
909 GdkVisual* gdkVisual = gdk_colormap_get_visual(gdkColormap);
910 ws_info->visual = gdk_x11_visual_get_xvisual(gdkVisual);
911 ws_info->depth = gdkVisual->depth;
912 #endif
915 else
916 #endif
918 window->window = mInstanceOwner->GetPluginPort();
921 // this will call pi->SetWindow and take care of window subclassing
922 // if needed, see bug 132759.
923 window->CallSetWindow(pi);
925 mInstanceOwner->ReleasePluginPort((nsPluginPort *)window->window);
928 PRBool
929 nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
931 if (aTabIndex)
932 *aTabIndex = -1;
933 return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
936 PRBool
937 nsObjectFrame::IsHidden(PRBool aCheckVisibilityStyle) const
939 if (aCheckVisibilityStyle) {
940 if (!GetStyleVisibility()->IsVisibleOrCollapsed())
941 return PR_TRUE;
944 // only <embed> tags support the HIDDEN attribute
945 if (mContent->Tag() == nsGkAtoms::embed) {
946 // Yes, these are really the kooky ways that you could tell 4.x
947 // not to hide the <embed> once you'd put the 'hidden' attribute
948 // on the tag...
950 // HIDDEN w/ no attributes gets translated as we are hidden for
951 // compatibility w/ 4.x and IE so we don't create a non-painting
952 // widget in layout. See bug 188959.
953 nsAutoString hidden;
954 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, hidden) &&
955 (hidden.IsEmpty() ||
956 !hidden.LowerCaseEqualsLiteral("false") &&
957 !hidden.LowerCaseEqualsLiteral("no") &&
958 !hidden.LowerCaseEqualsLiteral("off"))) {
959 return PR_TRUE;
963 return PR_FALSE;
966 nsPoint nsObjectFrame::GetWindowOriginInPixels(PRBool aWindowless)
968 nsIView * parentWithView;
969 nsPoint origin(0,0);
971 GetOffsetFromView(origin, &parentWithView);
973 // if it's windowless, let's make sure we have our origin set right
974 // it may need to be corrected, like after scrolling
975 if (aWindowless && parentWithView) {
976 // XXX Should this be replaced by nsIView::GetNearestWidget?
977 // The implementation below doesn't handle cases where the widget's origin
978 // doesn't coincide with its view's origin.
980 nsIViewManager* parentVM = parentWithView->GetViewManager();
982 // Walk up all the views and add up their positions until we
983 // reach the first view with a window (non-null widget). This will give us our
984 // position relative to the containing window which is what we want to give the plugin
985 nsIView* theView = parentWithView;
986 while (theView && !theView->GetWidget()) {
987 if (theView->GetViewManager() != parentVM)
988 break;
990 origin += theView->GetPosition();
991 theView = theView->GetParent();
995 origin.x = PresContext()->AppUnitsToDevPixels(origin.x);
996 origin.y = PresContext()->AppUnitsToDevPixels(origin.y);
998 return origin;
1001 NS_IMETHODIMP
1002 nsObjectFrame::DidReflow(nsPresContext* aPresContext,
1003 const nsHTMLReflowState* aReflowState,
1004 nsDidReflowStatus aStatus)
1006 // Do this check before calling the superclass, as that clears
1007 // NS_FRAME_FIRST_REFLOW
1008 if (aStatus == NS_FRAME_REFLOW_FINISHED &&
1009 (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1010 nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
1011 NS_ASSERTION(objContent, "Why not an object loading content?");
1012 objContent->HasNewFrame(this);
1015 nsresult rv = nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
1017 // The view is created hidden; once we have reflowed it and it has been
1018 // positioned then we show it.
1019 if (aStatus != NS_FRAME_REFLOW_FINISHED)
1020 return rv;
1022 if (HasView()) {
1023 nsIView* view = GetView();
1024 nsIViewManager* vm = view->GetViewManager();
1025 if (vm)
1026 vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow);
1029 // WMP10 needs an additional SetWindow call here (bug 391261)
1030 CallSetWindow();
1032 return rv;
1035 static void PaintPrintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
1036 const nsRect& aDirtyRect, nsPoint aPt)
1038 nsIRenderingContext::AutoPushTranslation translate(aCtx, aPt.x, aPt.y);
1039 static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
1042 static void PaintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
1043 const nsRect& aDirtyRect, nsPoint aPt)
1045 nsIRenderingContext::AutoPushTranslation translate(aCtx, aPt.x, aPt.y);
1046 #ifdef MOZ_X11 // FIXME - Bug 385435: Don't others want this too!
1047 nsRect relativeDirtyRect = aDirtyRect - aPt;
1048 static_cast<nsObjectFrame*>(aFrame)->PaintPlugin(*aCtx, relativeDirtyRect);
1049 #else
1050 static_cast<nsObjectFrame*>(aFrame)->PaintPlugin(*aCtx, aDirtyRect);
1051 #endif
1054 NS_IMETHODIMP
1055 nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
1056 const nsRect& aDirtyRect,
1057 const nsDisplayListSet& aLists)
1059 // XXX why are we painting collapsed object frames?
1060 if (!IsVisibleOrCollapsedForPainting(aBuilder))
1061 return NS_OK;
1063 nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
1064 NS_ENSURE_SUCCESS(rv, rv);
1066 nsPresContext::nsPresContextType type = PresContext()->Type();
1068 // If we are painting in Print Preview do nothing....
1069 if (type == nsPresContext::eContext_PrintPreview)
1070 return NS_OK;
1072 DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame");
1074 // determine if we are printing
1075 if (type == nsPresContext::eContext_Print)
1076 return aLists.Content()->AppendNewToTop(new (aBuilder)
1077 nsDisplayGeneric(this, PaintPrintPlugin, "PrintPlugin"));
1079 return aLists.Content()->AppendNewToTop(new (aBuilder)
1080 nsDisplayGeneric(this, ::PaintPlugin, "Plugin"));
1083 void
1084 nsObjectFrame::PrintPlugin(nsIRenderingContext& aRenderingContext,
1085 const nsRect& aDirtyRect)
1087 // if we are printing, we need to get the correct nsIPluginInstance
1088 // for THIS content node in order to call ->Print() on the right plugin
1090 // first, we need to get the document
1091 nsIDocument* doc = mContent->GetCurrentDoc();
1092 if (!doc)
1093 return;
1095 // now we need to get the shell for the screen
1096 // XXX assuming that the shell at zero will always be the screen one
1097 nsIPresShell *shell = doc->GetPrimaryShell();
1098 if (!shell)
1099 return;
1101 // then the shell can give us the screen frame for this content node
1102 nsIFrame* frame = shell->GetPrimaryFrameFor(mContent);
1103 if (!frame)
1104 return;
1106 nsPresContext* presContext = PresContext();
1107 // make sure this is REALLY an nsIObjectFrame
1108 // we may need to go through the children to get it
1109 nsIObjectFrame* objectFrame = nsnull;
1110 CallQueryInterface(frame,&objectFrame);
1111 if (!objectFrame)
1112 objectFrame = GetNextObjectFrame(presContext,frame);
1113 if (!objectFrame)
1114 return;
1116 // finally we can get our plugin instance
1117 nsCOMPtr<nsIPluginInstance> pi;
1118 if (NS_FAILED(objectFrame->GetPluginInstance(*getter_AddRefs(pi))) || !pi)
1119 return;
1121 // now we need to setup the correct location for printing
1122 nsresult rv;
1123 nsPluginWindow window;
1124 window.window = nsnull;
1126 // prepare embedded mode printing struct
1127 nsPluginPrint npprint;
1128 npprint.mode = nsPluginMode_Embedded;
1130 // we need to find out if we are windowless or not
1131 PRBool windowless = PR_FALSE;
1132 pi->GetValue(nsPluginInstanceVariable_WindowlessBool, (void *)&windowless);
1133 window.type = windowless ? nsPluginWindowType_Drawable : nsPluginWindowType_Window;
1135 // Get the offset of the DC
1136 nsTransform2D* rcTransform;
1137 aRenderingContext.GetCurrentTransform(rcTransform);
1138 nsPoint origin;
1139 rcTransform->GetTranslationCoord(&origin.x, &origin.y);
1141 // set it all up
1142 // XXX is windowless different?
1143 window.x = presContext->AppUnitsToDevPixels(origin.x);
1144 window.y = presContext->AppUnitsToDevPixels(origin.y);
1145 window.width = presContext->AppUnitsToDevPixels(mRect.width);
1146 window.height= presContext->AppUnitsToDevPixels(mRect.height);
1147 window.clipRect.bottom = 0; window.clipRect.top = 0;
1148 window.clipRect.left = 0; window.clipRect.right = 0;
1150 // XXX platform specific printing code
1151 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1152 /* UNIX does things completely differently:
1153 * We call the plugin and it sends generated PostScript data into a
1154 * file handle we provide. If the plugin returns with success we embed
1155 * this PostScript code fragment into the PostScript job we send to the
1156 * printer.
1159 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("nsObjectFrame::Paint() start for X11 platforms\n"));
1161 FILE *plugintmpfile = tmpfile();
1162 if (!plugintmpfile) {
1163 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("error: could not open tmp. file, errno=%d\n", errno));
1164 return;
1167 /* Send off print info to plugin */
1168 NPPrintCallbackStruct npPrintInfo;
1169 npPrintInfo.type = NP_PRINT;
1170 npPrintInfo.fp = plugintmpfile;
1171 npprint.print.embedPrint.platformPrint = (void *)&npPrintInfo;
1172 /* aDirtyRect contains the right information for ps print */
1173 window.x = aDirtyRect.x;
1174 window.y = aDirtyRect.y;
1175 window.width = aDirtyRect.width;
1176 window.height = aDirtyRect.height;
1177 npprint.print.embedPrint.window = window;
1178 rv = pi->Print(&npprint);
1179 if (NS_FAILED(rv)) {
1180 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("error: plugin returned failure %lx\n", (long)rv));
1181 fclose(plugintmpfile);
1182 return;
1185 /* Send data to printer */
1186 rv = aRenderingContext.RenderEPS(aDirtyRect, plugintmpfile);
1188 fclose(plugintmpfile);
1190 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("plugin printing done, return code is %lx\n", (long)rv));
1192 #elif defined(XP_WIN)
1194 /* On Windows, we use the win32 printing surface to print. This, in
1195 * turn, uses the Cairo paginated surface, which in turn uses the
1196 * meta surface to record all operations and then play them back.
1197 * This doesn't work too well for plugins, because if plugins render
1198 * directly into the DC, the meta surface won't have any knowledge
1199 * of them, and so at the end when it actually does the replay step,
1200 * it'll fill the background with white and draw over whatever was
1201 * rendered before.
1203 * So, to avoid this, we use PushGroup, which creates a new windows
1204 * surface, the plugin renders to that, and then we use normal
1205 * cairo methods to composite that in such that it's recorded using the
1206 * meta surface.
1209 gfxContext *ctx = aRenderingContext.ThebesContext();
1211 ctx->Save();
1213 ctx->NewPath();
1214 ctx->Rectangle(gfxRect(window.x, window.y,
1215 window.width, window.height));
1216 ctx->Clip();
1217 ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
1219 gfxWindowsNativeDrawing nativeDraw(ctx,
1220 gfxRect(window.x, window.y,
1221 window.width, window.height));
1222 do {
1223 HDC dc = nativeDraw.BeginNativeDrawing();
1224 if (!dc)
1225 return;
1227 npprint.print.embedPrint.platformPrint = dc;
1228 npprint.print.embedPrint.window = window;
1229 // send off print info to plugin
1230 rv = pi->Print(&npprint);
1232 nativeDraw.EndNativeDrawing();
1233 } while (nativeDraw.ShouldRenderAgain());
1234 nativeDraw.PaintToContext();
1236 ctx->PopGroupToSource();
1237 ctx->Paint();
1239 ctx->Restore();
1241 #else
1243 // we need the native printer device context to pass to plugin
1244 // NATIVE_WINDOWS_DC is a misnomer, it's whatever the native platform
1245 // thing is.
1246 void* dc;
1247 dc = aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_WINDOWS_DC);
1248 if (!dc)
1249 return; // no dc implemented so quit
1251 npprint.print.embedPrint.platformPrint = dc;
1252 npprint.print.embedPrint.window = window;
1253 // send off print info to plugin
1254 rv = pi->Print(&npprint);
1255 #endif
1257 // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same?
1258 nsDidReflowStatus status = NS_FRAME_REFLOW_FINISHED; // should we use a special status?
1259 frame->DidReflow(presContext,
1260 nsnull, status); // DidReflow will take care of it
1263 void
1264 nsObjectFrame::PaintPlugin(nsIRenderingContext& aRenderingContext,
1265 const nsRect& aDirtyRect)
1267 // Screen painting code
1268 #if defined(XP_MACOSX)
1269 // delegate all painting to the plugin instance.
1270 if (mInstanceOwner) {
1271 if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics) {
1272 PRInt32 p2a = PresContext()->AppUnitsPerDevPixel();
1273 gfxRect nativeClipRect(aDirtyRect.x, aDirtyRect.y,
1274 aDirtyRect.width, aDirtyRect.height);
1275 nativeClipRect.ScaleInverse(gfxFloat(p2a));
1276 gfxContext* ctx = aRenderingContext.ThebesContext();
1277 gfxQuartzNativeDrawing nativeDrawing(ctx, nativeClipRect);
1279 CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
1280 if (!cgContext) {
1281 NS_WARNING("null CGContextRef during PaintPlugin");
1282 return;
1285 // If gfxQuartzNativeDrawing hands out a CGContext other than the last
1286 // one we passed to the plugin, we need to pass the new one to the
1287 // plugin via SetWindow.
1288 // XXXkinetik it's not necessary to call SetWindow for every paint so
1289 // this should eventually be optimized to only do so when necessary
1290 nsPluginPort* pluginPort = mInstanceOwner->GetPluginPort();
1291 nsCOMPtr<nsIPluginInstance> inst;
1292 GetPluginInstance(*getter_AddRefs(inst));
1293 if (!inst) {
1294 NS_WARNING("null plugin instance during PaintPlugin");
1295 return;
1297 nsPluginWindow* window;
1298 mInstanceOwner->GetWindow(window);
1299 if (!window) {
1300 NS_WARNING("null plugin window during PaintPlugin");
1301 return;
1303 pluginPort->cgPort.context = cgContext;
1304 window->window = pluginPort;
1305 inst->SetWindow(window);
1307 mInstanceOwner->Paint(aDirtyRect);
1309 nativeDrawing.EndNativeDrawing();
1310 } else {
1311 mInstanceOwner->Paint(aDirtyRect);
1314 #elif defined(MOZ_X11)
1315 if (mInstanceOwner)
1317 nsPluginWindow * window;
1318 mInstanceOwner->GetWindow(window);
1320 if (window->type == nsPluginWindowType_Drawable)
1321 mInstanceOwner->Paint(aRenderingContext, aDirtyRect);
1323 #elif defined (XP_WIN) // || defined(XP_OS2)
1324 // XXX for OS/2 we need to overhaul this for Cairo builds
1325 // for now just ignore plugin stuff
1326 nsCOMPtr<nsIPluginInstance> inst;
1327 GetPluginInstance(*getter_AddRefs(inst));
1328 if (inst) {
1329 // Look if it's windowless
1330 nsPluginWindow * window;
1331 mInstanceOwner->GetWindow(window);
1333 if (window->type == nsPluginWindowType_Drawable) {
1334 // check if we need to call SetWindow with updated parameters
1335 PRBool doupdatewindow = PR_FALSE;
1336 // the offset of the DC
1337 nsPoint origin;
1339 // check if we need to update hdc
1340 HDC hdc = (HDC)aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_WINDOWS_DC);
1342 if (reinterpret_cast<HDC>(window->window) != hdc) {
1343 window->window = reinterpret_cast<nsPluginPort*>(hdc);
1344 doupdatewindow = PR_TRUE;
1348 * Layout now has an optimized way of painting. Now we always get
1349 * a new drawing surface, sized to be just what's needed. Windowless
1350 * plugins need a transform applied to their origin so they paint
1351 * in the right place. Since |SetWindow| is no longer being used
1352 * to tell the plugin where it is, we dispatch a NPWindow through
1353 * |HandleEvent| to tell the plugin when its window moved
1355 nsRefPtr<gfxContext> ctx = aRenderingContext.ThebesContext();
1356 gfxMatrix ctxMatrix = ctx->CurrentMatrix();
1357 if (ctxMatrix.HasNonTranslation()) {
1358 // soo; in the future, we should be able to render
1359 // the object content to an offscreen DC, and then
1360 // composite it in with the right transforms.
1362 // But, we don't bother doing that, because we don't
1363 // have the event handling story figured out yet.
1364 // Instead, let's just bail.
1366 return;
1369 origin.x = NSToIntRound(float(ctxMatrix.GetTranslation().x));
1370 origin.y = NSToIntRound(float(ctxMatrix.GetTranslation().y));
1372 SaveDC(hdc);
1374 /* Need to force the clip to be set */
1375 ctx->UpdateSurfaceClip();
1377 /* Set the device offsets as appropriate, for whatever our current group offsets might be */
1378 gfxFloat xoff, yoff;
1379 nsRefPtr<gfxASurface> surf = ctx->CurrentSurface(&xoff, &yoff);
1381 POINT origViewportOrigin;
1382 GetViewportOrgEx(hdc, &origViewportOrigin);
1383 SetViewportOrgEx(hdc, origViewportOrigin.x + (int) xoff, origViewportOrigin.y + (int) yoff, NULL);
1385 if ((window->x != origin.x) || (window->y != origin.y)) {
1386 window->x = origin.x;
1387 window->y = origin.y;
1388 doupdatewindow = PR_TRUE;
1391 // if our location or visible area has changed, we need to tell the plugin
1392 if (doupdatewindow) {
1393 #ifdef XP_WIN // Windowless plugins on windows need a special event to update their location, see bug 135737
1394 // bug 271442: note, the rectangle we send is now purely the bounds of the plugin
1395 // relative to the window it is contained in, which is useful for the plugin to correctly translate mouse coordinates
1397 // this does not mesh with the comments for bug 135737 which imply that the rectangle
1398 // must be clipped in some way to prevent the plugin attempting to paint over areas it shouldn't;
1400 // since the two uses of the rectangle are mutually exclusive in some cases,
1401 // and since I don't see any incorrect painting (at least with Flash and ViewPoint - the originator of 135737),
1402 // it seems that windowless plugins are not relying on information here for clipping their drawing,
1403 // and we can safely use this message to tell the plugin exactly where it is in all cases.
1405 origin = GetWindowOriginInPixels(PR_TRUE);
1406 nsRect winlessRect = nsRect(origin, nsSize(window->width, window->height));
1407 // XXX I don't think we can be certain that the location wrt to
1408 // the window only changes when the location wrt to the drawable
1409 // changes, but the hdc probably changes on every paint so
1410 // doupdatewindow is rarely false, and there is not likely to be
1411 // a problem.
1412 if (mWindowlessRect != winlessRect) {
1413 mWindowlessRect = winlessRect;
1415 WINDOWPOS winpos;
1416 memset(&winpos, 0, sizeof(winpos));
1417 winpos.x = mWindowlessRect.x;
1418 winpos.y = mWindowlessRect.y;
1419 winpos.cx = mWindowlessRect.width;
1420 winpos.cy = mWindowlessRect.height;
1422 // finally, update the plugin by sending it a WM_WINDOWPOSCHANGED event
1423 nsPluginEvent pluginEvent;
1424 pluginEvent.event = WM_WINDOWPOSCHANGED;
1425 pluginEvent.wParam = 0;
1426 pluginEvent.lParam = (uint32)&winpos;
1427 PRBool eventHandled = PR_FALSE;
1429 inst->HandleEvent(&pluginEvent, &eventHandled);
1431 #endif
1433 inst->SetWindow(window);
1436 // FIXME - Bug 385435:
1437 // This expects a dirty rect relative to the plugin's rect
1438 // XXX I wonder if this breaks if we give the frame a border so the
1439 // frame origin and plugin origin are not the same
1440 mInstanceOwner->Paint(aDirtyRect, hdc);
1442 RestoreDC(hdc, -1);
1443 surf->MarkDirty();
1446 #endif
1449 NS_IMETHODIMP
1450 nsObjectFrame::HandleEvent(nsPresContext* aPresContext,
1451 nsGUIEvent* anEvent,
1452 nsEventStatus* anEventStatus)
1454 NS_ENSURE_ARG_POINTER(anEventStatus);
1455 nsresult rv = NS_OK;
1457 if (!mInstanceOwner)
1458 return NS_ERROR_NULL_POINTER;
1460 if (anEvent->message == NS_PLUGIN_ACTIVATE) {
1461 nsIContent* content = GetContent();
1462 if (content) {
1463 content->SetFocus(aPresContext);
1464 return rv;
1468 #ifdef XP_WIN
1469 rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
1470 return rv;
1471 #endif
1473 switch (anEvent->message) {
1474 case NS_DESTROY:
1475 mInstanceOwner->CancelTimer();
1476 break;
1477 case NS_GOTFOCUS:
1478 case NS_LOSTFOCUS:
1479 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
1480 break;
1482 default:
1483 // instead of using an event listener, we can dispatch events to plugins directly.
1484 rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
1487 return rv;
1490 nsresult nsObjectFrame::GetPluginInstance(nsIPluginInstance*& aPluginInstance)
1492 aPluginInstance = nsnull;
1494 if (!mInstanceOwner)
1495 return NS_OK;
1497 return mInstanceOwner->GetInstance(aPluginInstance);
1500 nsresult
1501 nsObjectFrame::PrepareInstanceOwner()
1503 // First, have to stop any possibly running plugins.
1504 StopPluginInternal(PR_FALSE);
1506 NS_ASSERTION(!mInstanceOwner, "Must not have an instance owner here");
1508 mInstanceOwner = new nsPluginInstanceOwner();
1510 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
1511 ("Created new instance owner %p for frame %p\n", mInstanceOwner.get(),
1512 this));
1514 if (!mInstanceOwner)
1515 return NS_ERROR_OUT_OF_MEMORY;
1517 // Note, |this| may very well be gone after this call.
1518 return mInstanceOwner->Init(PresContext(), this, GetContent());
1521 nsresult
1522 nsObjectFrame::Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener)
1524 if (mInstantiating) {
1525 return NS_OK;
1528 // Note: If PrepareInstanceOwner() returns an error, |this| may very
1529 // well be deleted already.
1530 nsresult rv = PrepareInstanceOwner();
1531 NS_ENSURE_SUCCESS(rv, rv);
1533 nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(kCPluginManagerCID, &rv));
1534 if (NS_FAILED(rv))
1535 return rv;
1536 mInstanceOwner->SetPluginHost(pluginHost);
1538 // This must be done before instantiating the plugin
1539 FixupWindow(mRect.Size());
1541 NS_ASSERTION(!mInstantiating, "Say what?");
1542 mInstantiating = PR_TRUE;
1543 rv = pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
1544 mInstantiating = PR_FALSE;
1546 return rv;
1549 nsresult
1550 nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI)
1552 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
1553 ("nsObjectFrame::Instantiate(%s) called on frame %p\n", aMimeType,
1554 this));
1556 if (mInstantiating) {
1557 return NS_OK;
1560 NS_ASSERTION(aMimeType || aURI, "Need a type or a URI!");
1562 // Note: If PrepareInstanceOwner() returns an error, |this| may very
1563 // well be deleted already.
1564 nsresult rv = PrepareInstanceOwner();
1565 NS_ENSURE_SUCCESS(rv, rv);
1567 // This must be done before instantiating the plugin
1568 FixupWindow(mRect.Size());
1570 // get the nsIPluginHost service
1571 nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(kCPluginManagerCID, &rv));
1572 if (NS_FAILED(rv))
1573 return rv;
1574 mInstanceOwner->SetPluginHost(pluginHost);
1576 rv = InstantiatePlugin(pluginHost, aMimeType, aURI);
1578 // finish up
1579 if (NS_SUCCEEDED(rv)) {
1580 TryNotifyContentObjectWrapper();
1581 CallSetWindow();
1584 return rv;
1587 void
1588 nsObjectFrame::TryNotifyContentObjectWrapper()
1590 nsCOMPtr<nsIPluginInstance> inst;
1591 mInstanceOwner->GetInstance(*getter_AddRefs(inst));
1592 if (inst) {
1593 // The plugin may have set up new interfaces; we need to mess with our JS
1594 // wrapper. Note that we DO NOT want to call this if there is no plugin
1595 // instance! That would just reenter Instantiate(), trying to create
1596 // said plugin instance.
1597 NotifyContentObjectWrapper();
1601 class nsStopPluginRunnable : public nsRunnable
1603 public:
1604 nsStopPluginRunnable(nsPluginInstanceOwner *aInstanceOwner)
1605 : mInstanceOwner(aInstanceOwner)
1609 NS_IMETHOD Run();
1611 private:
1612 nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
1615 static void
1616 DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner)
1618 nsCOMPtr<nsIPluginInstance> inst;
1619 aInstanceOwner->GetInstance(*getter_AddRefs(inst));
1620 if (inst) {
1621 nsPluginWindow *win;
1622 aInstanceOwner->GetWindow(win);
1623 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
1624 nsCOMPtr<nsIPluginInstance> nullinst;
1626 PRBool doCache = PR_TRUE;
1627 PRBool doCallSetWindowAfterDestroy = PR_FALSE;
1629 // first, determine if the plugin wants to be cached
1630 inst->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *)&doCache);
1631 if (!doCache) {
1632 // then determine if the plugin wants Destroy to be called after
1633 // Set Window. This is for bug 50547.
1634 inst->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool,
1635 (void *)&doCallSetWindowAfterDestroy);
1636 if (doCallSetWindowAfterDestroy) {
1637 // XXXjst: ns4xPluginInstance::Destroy() is a no-op, clean
1638 // this mess up when there are no other instance types.
1639 inst->Stop();
1640 inst->Destroy();
1642 if (window)
1643 window->CallSetWindow(nullinst);
1644 else
1645 inst->SetWindow(nsnull);
1647 else {
1648 if (window)
1649 window->CallSetWindow(nullinst);
1650 else
1651 inst->SetWindow(nsnull);
1653 inst->Stop();
1654 inst->Destroy();
1657 else {
1658 if (window)
1659 window->CallSetWindow(nullinst);
1660 else
1661 inst->SetWindow(nsnull);
1663 inst->Stop();
1666 nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(kCPluginManagerCID);
1667 if (pluginHost)
1668 pluginHost->StopPluginInstance(inst);
1670 // the frame is going away along with its widget so tell the
1671 // window to forget its widget too
1672 if (window)
1673 window->SetPluginWidget(nsnull);
1676 aInstanceOwner->Destroy();
1679 NS_IMETHODIMP
1680 nsStopPluginRunnable::Run()
1682 DoStopPlugin(mInstanceOwner);
1684 return NS_OK;
1687 void
1688 nsObjectFrame::StopPlugin()
1690 StopPluginInternal(PR_FALSE);
1693 void
1694 nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
1696 if (mInstanceOwner == nsnull) {
1697 return;
1700 mInstanceOwner->PrepareToStop(aDelayedStop);
1702 #ifdef XP_WIN
1703 // We only deal with delayed stopping of plugins on Win32 for now,
1704 // as that's the only platform where we need to (AFAIK) and it's
1705 // unclear how safe widget parenting is on other platforms.
1706 if (aDelayedStop) {
1707 // nsStopPluginRunnable will hold a strong reference to
1708 // mInstanceOwner, and thus keep it alive as long as it needs it.
1709 nsCOMPtr<nsIRunnable> evt = new nsStopPluginRunnable(mInstanceOwner);
1710 NS_DispatchToCurrentThread(evt);
1712 // If we're asked to do a delayed stop it means we're stopping the
1713 // plugin because we're destroying the frame. In that case, tell
1714 // the view to disown the widget (i.e. leave it up to us to
1715 // destroy it).
1716 nsIView *view = GetView();
1717 if (view) {
1718 view->DisownWidget();
1720 } else
1721 #endif
1723 DoStopPlugin(mInstanceOwner);
1726 // Break relationship between frame and plugin instance owner
1727 mInstanceOwner->SetOwner(nsnull);
1729 mInstanceOwner = nsnull;
1731 // Make sure that our windowless rect has been zeroed out, so if we
1732 // get reinstantiated we'll send the right messages to the plug-in.
1733 mWindowlessRect.Empty();
1736 void
1737 nsObjectFrame::NotifyContentObjectWrapper()
1739 nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
1740 if (!doc)
1741 return;
1743 nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
1744 if (!sgo)
1745 return;
1747 nsIScriptContext *scx = sgo->GetContext();
1748 if (!scx)
1749 return;
1751 JSContext *cx = (JSContext *)scx->GetNativeContext();
1753 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
1754 nsContentUtils::XPConnect()->
1755 GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), mContent,
1756 NS_GET_IID(nsISupports),
1757 getter_AddRefs(wrapper));
1759 if (!wrapper) {
1760 // Nothing to do here if there's no wrapper for mContent
1761 return;
1764 nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(mContent));
1765 if (!ci)
1766 return;
1768 nsCOMPtr<nsISupports> s;
1769 ci->GetHelperForLanguage(nsIProgrammingLanguage::JAVASCRIPT,
1770 getter_AddRefs(s));
1772 nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(s));
1774 if (!helper) {
1775 // There's nothing we can do if there's no helper
1776 return;
1779 JSObject *obj = nsnull;
1780 nsresult rv = wrapper->GetJSObject(&obj);
1781 if (NS_FAILED(rv))
1782 return;
1784 nsCxPusher cxPusher;
1785 if (cxPusher.Push(mContent)) {
1786 // Abuse the scriptable helper to trigger prototype setup for the
1787 // wrapper for mContent so that this plugin becomes part of the DOM
1788 // object.
1789 helper->PostCreate(wrapper, cx, obj);
1793 // static
1794 nsIObjectFrame *
1795 nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)
1797 nsIFrame* child = aRoot->GetFirstChild(nsnull);
1799 while (child) {
1800 nsIObjectFrame* outFrame = nsnull;
1801 CallQueryInterface(child, &outFrame);
1802 if (outFrame) {
1803 nsCOMPtr<nsIPluginInstance> pi;
1804 outFrame->GetPluginInstance(*getter_AddRefs(pi)); // make sure we have a REAL plugin
1805 if (pi)
1806 return outFrame;
1809 outFrame = GetNextObjectFrame(aPresContext, child);
1810 if (outFrame)
1811 return outFrame;
1812 child = child->GetNextSibling();
1815 return nsnull;
1818 nsIFrame*
1819 NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
1821 return new (aPresShell) nsObjectFrame(aContext);
1825 // nsPluginDOMContextMenuListener class implementation
1827 nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener()
1831 nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
1835 NS_IMPL_ISUPPORTS2(nsPluginDOMContextMenuListener, nsIDOMContextMenuListener, nsIEventListener)
1837 NS_IMETHODIMP
1838 nsPluginDOMContextMenuListener::ContextMenu(nsIDOMEvent* aContextMenuEvent)
1840 aContextMenuEvent->PreventDefault(); // consume event
1842 return NS_OK;
1845 nsresult nsPluginDOMContextMenuListener::Init(nsIContent* aContent)
1847 nsCOMPtr<nsIDOMEventTarget> receiver(do_QueryInterface(aContent));
1848 if (receiver) {
1849 receiver->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, PR_TRUE);
1850 return NS_OK;
1853 return NS_ERROR_NO_INTERFACE;
1856 nsresult nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent)
1858 // Unregister context menu listener
1859 nsCOMPtr<nsIDOMEventTarget> receiver(do_QueryInterface(aContent));
1860 if (receiver) {
1861 receiver->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, PR_TRUE);
1864 return NS_OK;
1867 //plugin instance owner
1869 nsPluginInstanceOwner::nsPluginInstanceOwner()
1871 // create nsPluginNativeWindow object, it is derived from nsPluginWindow
1872 // struct and allows to manipulate native window procedure
1873 nsCOMPtr<nsIPluginHost> ph = do_GetService(kCPluginManagerCID);
1874 nsCOMPtr<nsPIPluginHost> pph(do_QueryInterface(ph));
1875 if (pph)
1876 pph->NewPluginNativeWindow(&mPluginWindow);
1877 else
1878 mPluginWindow = nsnull;
1880 mOwner = nsnull;
1881 mTagText = nsnull;
1882 mContentFocused = PR_FALSE;
1883 mWidgetVisible = PR_TRUE;
1884 mNumCachedAttrs = 0;
1885 mNumCachedParams = 0;
1886 mCachedAttrParamNames = nsnull;
1887 mCachedAttrParamValues = nsnull;
1888 mDestroyWidget = PR_FALSE;
1890 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
1891 ("nsPluginInstanceOwner %p created\n", this));
1894 nsPluginInstanceOwner::~nsPluginInstanceOwner()
1896 PRInt32 cnt;
1898 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
1899 ("nsPluginInstanceOwner %p deleted\n", this));
1901 // shut off the timer.
1902 if (mPluginTimer != nsnull) {
1903 CancelTimer();
1906 mOwner = nsnull;
1908 for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) {
1909 if (mCachedAttrParamNames && mCachedAttrParamNames[cnt]) {
1910 PR_Free(mCachedAttrParamNames[cnt]);
1911 mCachedAttrParamNames[cnt] = nsnull;
1914 if (mCachedAttrParamValues && mCachedAttrParamValues[cnt]) {
1915 PR_Free(mCachedAttrParamValues[cnt]);
1916 mCachedAttrParamValues[cnt] = nsnull;
1920 if (mCachedAttrParamNames) {
1921 PR_Free(mCachedAttrParamNames);
1922 mCachedAttrParamNames = nsnull;
1925 if (mCachedAttrParamValues) {
1926 PR_Free(mCachedAttrParamValues);
1927 mCachedAttrParamValues = nsnull;
1930 if (mTagText) {
1931 NS_Free(mTagText);
1932 mTagText = nsnull;
1935 // clean up plugin native window object
1936 nsCOMPtr<nsIPluginHost> ph = do_GetService(kCPluginManagerCID);
1937 nsCOMPtr<nsPIPluginHost> pph(do_QueryInterface(ph));
1938 if (pph) {
1939 pph->DeletePluginNativeWindow(mPluginWindow);
1940 mPluginWindow = nsnull;
1945 * nsISupports Implementation
1948 NS_IMPL_ADDREF(nsPluginInstanceOwner)
1949 NS_IMPL_RELEASE(nsPluginInstanceOwner)
1951 NS_INTERFACE_MAP_BEGIN(nsPluginInstanceOwner)
1952 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
1953 NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo)
1954 NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo2)
1955 #ifdef OJI
1956 NS_INTERFACE_MAP_ENTRY(nsIJVMPluginTagInfo)
1957 #endif
1958 NS_INTERFACE_MAP_ENTRY(nsIEventListener)
1959 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
1960 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
1961 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener)
1962 NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
1963 NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
1964 NS_INTERFACE_MAP_ENTRY(nsIScrollPositionListener)
1965 NS_INTERFACE_MAP_ENTRY(nsIDOMDragListener)
1966 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
1967 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPluginInstanceOwner)
1968 NS_INTERFACE_MAP_END
1970 NS_IMETHODIMP nsPluginInstanceOwner::SetInstance(nsIPluginInstance *aInstance)
1972 mInstance = aInstance;
1974 return NS_OK;
1977 NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(nsPluginWindow *&aWindow)
1979 NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null");
1980 aWindow = mPluginWindow;
1981 return NS_OK;
1984 NS_IMETHODIMP nsPluginInstanceOwner::GetMode(nsPluginMode *aMode)
1986 nsCOMPtr<nsIDocument> doc;
1987 nsresult rv = GetDocument(getter_AddRefs(doc));
1988 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
1990 if (pDoc) {
1991 *aMode = nsPluginMode_Full;
1992 } else {
1993 *aMode = nsPluginMode_Embedded;
1996 return rv;
1999 NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(PRUint16& n,
2000 const char*const*& names,
2001 const char*const*& values)
2003 nsresult rv = EnsureCachedAttrParamArrays();
2004 NS_ENSURE_SUCCESS(rv, rv);
2006 n = mNumCachedAttrs;
2007 names = (const char **)mCachedAttrParamNames;
2008 values = (const char **)mCachedAttrParamValues;
2010 return rv;
2013 NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result)
2015 NS_ENSURE_ARG_POINTER(name);
2016 NS_ENSURE_ARG_POINTER(result);
2018 nsresult rv = EnsureCachedAttrParamArrays();
2019 NS_ENSURE_SUCCESS(rv, rv);
2021 *result = nsnull;
2023 for (int i = 0; i < mNumCachedAttrs; i++) {
2024 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
2025 *result = mCachedAttrParamValues[i];
2026 return NS_OK;
2030 return NS_ERROR_FAILURE;
2033 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
2035 return CallQueryInterface(mContent, result);
2038 NS_IMETHODIMP nsPluginInstanceOwner::GetInstance(nsIPluginInstance *&aInstance)
2040 NS_IF_ADDREF(aInstance = mInstance);
2042 return NS_OK;
2045 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, const char *aTarget, void *aPostData, PRUint32 aPostDataLen, void *aHeadersData,
2046 PRUint32 aHeadersDataLen, PRBool isFile)
2048 NS_ENSURE_TRUE(mOwner,NS_ERROR_NULL_POINTER);
2050 if (mContent->IsEditable()) {
2051 return NS_OK;
2054 // the container of the pres context will give us the link handler
2055 nsCOMPtr<nsISupports> container = mOwner->PresContext()->GetContainer();
2056 NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
2057 nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
2058 NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
2060 nsAutoString unitarget;
2061 unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
2063 nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
2065 // Create an absolute URL
2066 nsCOMPtr<nsIURI> uri;
2067 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
2069 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2071 nsCOMPtr<nsIInputStream> postDataStream;
2072 nsCOMPtr<nsIInputStream> headersDataStream;
2074 // deal with post data, either in a file or raw data, and any headers
2075 if (aPostData) {
2077 rv = NS_NewPluginPostDataStream(getter_AddRefs(postDataStream), (const char *)aPostData, aPostDataLen, isFile);
2079 NS_ASSERTION(NS_SUCCEEDED(rv),"failed in creating plugin post data stream");
2080 if (NS_FAILED(rv))
2081 return rv;
2083 if (aHeadersData) {
2084 rv = NS_NewPluginPostDataStream(getter_AddRefs(headersDataStream),
2085 (const char *) aHeadersData,
2086 aHeadersDataLen,
2087 PR_FALSE,
2088 PR_TRUE); // last arg says we are headers, no /r/n/r/n fixup!
2090 NS_ASSERTION(NS_SUCCEEDED(rv),"failed in creating plugin header data stream");
2091 if (NS_FAILED(rv))
2092 return rv;
2096 PRInt32 blockPopups =
2097 nsContentUtils::GetIntPref("privacy.popups.disable_from_plugins");
2098 nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
2100 rv = lh->OnLinkClick(mContent, uri, unitarget.get(),
2101 postDataStream, headersDataStream);
2103 return rv;
2106 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char *aStatusMsg)
2108 nsresult rv = NS_ERROR_FAILURE;
2110 rv = this->ShowStatus(NS_ConvertUTF8toUTF16(aStatusMsg).get());
2112 return rv;
2115 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const PRUnichar *aStatusMsg)
2117 nsresult rv = NS_ERROR_FAILURE;
2119 if (!mOwner) {
2120 return rv;
2122 nsCOMPtr<nsISupports> cont = mOwner->PresContext()->GetContainer();
2123 if (!cont) {
2124 return NS_OK;
2127 nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(cont, &rv));
2128 if (NS_FAILED(rv) || !docShellItem) {
2129 return rv;
2132 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
2133 rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
2134 if (NS_FAILED(rv) || !treeOwner) {
2135 return rv;
2138 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner, &rv));
2139 if (NS_FAILED(rv) || !browserChrome) {
2140 return rv;
2142 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
2143 aStatusMsg);
2145 return rv;
2148 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
2150 if (!aDocument)
2151 return NS_ERROR_NULL_POINTER;
2153 // XXX sXBL/XBL2 issue: current doc or owner doc?
2154 // But keep in mind bug 322414 comment 33
2155 NS_IF_ADDREF(*aDocument = mContent->GetOwnerDoc());
2156 return NS_OK;
2159 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(nsPluginRect *invalidRect)
2161 nsresult rv = NS_ERROR_FAILURE;
2163 if (mOwner && invalidRect && mWidgetVisible) {
2164 //no reference count on view
2165 nsIView* view = mOwner->GetView();
2167 if (view) {
2168 nsPresContext* presContext = mOwner->PresContext();
2170 nsRect rect(presContext->DevPixelsToAppUnits(invalidRect->left),
2171 presContext->DevPixelsToAppUnits(invalidRect->top),
2172 presContext->DevPixelsToAppUnits(invalidRect->right - invalidRect->left),
2173 presContext->DevPixelsToAppUnits(invalidRect->bottom - invalidRect->top));
2175 //set flags to not do a synchronous update, force update does the redraw
2176 view->GetViewManager()->UpdateView(view, rect, NS_VMREFRESH_NO_SYNC);
2180 return rv;
2183 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(nsPluginRegion invalidRegion)
2185 return NS_ERROR_NOT_IMPLEMENTED;
2188 NS_IMETHODIMP nsPluginInstanceOwner::ForceRedraw()
2190 nsIView* view = mOwner->GetView();
2191 if (view) {
2192 return view->GetViewManager()->Composite();
2195 return NS_OK;
2198 NS_IMETHODIMP nsPluginInstanceOwner::GetValue(nsPluginInstancePeerVariable variable, void *value)
2200 nsresult rv = NS_ERROR_FAILURE;
2202 switch(variable) {
2203 case nsPluginInstancePeerVariable_NetscapeWindow:
2205 if (mOwner) {
2206 #if defined(XP_WIN) || defined(XP_OS2)
2207 void** pvalue = (void**)value;
2208 nsIViewManager* vm = mOwner->PresContext()->GetViewManager();
2209 if (vm) {
2210 #if defined(XP_WIN)
2211 // This property is provided to allow a "windowless" plugin to determine the window it is drawing
2212 // in, so it can translate mouse coordinates it receives directly from the operating system
2213 // to coordinates relative to itself.
2215 // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin
2216 // 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
2218 // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
2219 // determines the window handle of the mozilla window containing the "windowless" plugin.
2221 // Given that this HWND may not be that of the document's window, there is a slight risk
2222 // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
2223 // does not suggest this HWND IS that of the document window, rather that of the window
2224 // the plugin is drawn in, this seems like a safe fix.
2226 // we only attempt to get the nearest window if this really is a "windowless" plugin so as not
2227 // to change any behaviour for the much more common windowed plugins,
2228 // though why this method would even be being called for a windowed plugin escapes me.
2229 if (mPluginWindow && mPluginWindow->type == nsPluginWindowType_Drawable) {
2230 // it turns out that flash also uses this window for determining focus, and is currently
2231 // unable to show a caret correctly if we return the enclosing window. Therefore for
2232 // now we only return the enclosing window when there is an actual offset which
2233 // would otherwise cause coordinates to be offset incorrectly. (i.e.
2234 // if the enclosing window if offset from the document window)
2236 // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
2237 // does not seem to be possible without a change to the flash plugin
2239 nsIWidget* win = mOwner->GetWindow();
2240 if (win) {
2241 nsIView *view = nsIView::GetViewFor(win);
2242 NS_ASSERTION(view, "No view for widget");
2243 nsIView *rootView = nsnull;
2244 vm->GetRootView(rootView);
2245 NS_ASSERTION(rootView, "No root view");
2246 nsPoint offset = view->GetOffsetTo(rootView);
2248 if (offset.x || offset.y) {
2249 // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
2250 // so that mouse co-ordinates are not messed up.
2251 *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW);
2252 if (*pvalue)
2253 return NS_OK;
2257 #endif
2258 // simply return the document window
2259 nsCOMPtr<nsIWidget> widget;
2260 rv = vm->GetWidget(getter_AddRefs(widget));
2261 if (widget) {
2262 *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
2263 } else NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
2264 } else NS_ASSERTION(vm, "couldn't get view manager in getting doc's window handle");
2265 #elif defined(MOZ_WIDGET_GTK2)
2266 // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
2267 nsIWidget* win = mOwner->GetWindow();
2268 if (!win)
2269 return rv;
2270 GdkWindow* gdkWindow =
2271 static_cast<GdkWindow*>(win->GetNativeData(NS_NATIVE_WINDOW));
2272 if (!gdkWindow)
2273 return rv;
2274 gdkWindow = gdk_window_get_toplevel(gdkWindow);
2275 *static_cast<Window*>(value) = GDK_WINDOW_XID(gdkWindow);
2276 return NS_OK;
2277 #endif
2278 } else NS_ASSERTION(mOwner, "plugin owner has no owner in getting doc's window handle");
2279 break;
2283 return rv;
2286 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
2288 NS_ENSURE_ARG_POINTER(result);
2290 *result = nsPluginTagType_Unknown;
2292 nsIAtom *atom = mContent->Tag();
2294 if (atom == nsGkAtoms::applet)
2295 *result = nsPluginTagType_Applet;
2296 else if (atom == nsGkAtoms::embed)
2297 *result = nsPluginTagType_Embed;
2298 else if (atom == nsGkAtoms::object)
2299 *result = nsPluginTagType_Object;
2301 return NS_OK;
2304 NS_IMETHODIMP nsPluginInstanceOwner::GetTagText(const char* *result)
2306 NS_ENSURE_ARG_POINTER(result);
2307 if (nsnull == mTagText) {
2308 nsresult rv;
2309 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent, &rv));
2310 if (NS_FAILED(rv))
2311 return rv;
2313 nsCOMPtr<nsIDocument> document;
2314 rv = GetDocument(getter_AddRefs(document));
2315 if (NS_FAILED(rv))
2316 return rv;
2318 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(document);
2319 NS_ASSERTION(domDoc, "Need a document");
2321 nsCOMPtr<nsIDocumentEncoder> docEncoder(do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/html", &rv));
2322 if (NS_FAILED(rv))
2323 return rv;
2324 rv = docEncoder->Init(domDoc, NS_LITERAL_STRING("text/html"), nsIDocumentEncoder::OutputEncodeBasicEntities);
2325 if (NS_FAILED(rv))
2326 return rv;
2328 nsCOMPtr<nsIDOMRange> range(do_CreateInstance(kRangeCID,&rv));
2329 if (NS_FAILED(rv))
2330 return rv;
2332 rv = range->SelectNode(node);
2333 if (NS_FAILED(rv))
2334 return rv;
2336 docEncoder->SetRange(range);
2337 nsString elementHTML;
2338 rv = docEncoder->EncodeToString(elementHTML);
2339 if (NS_FAILED(rv))
2340 return rv;
2342 mTagText = ToNewUTF8String(elementHTML);
2343 if (!mTagText)
2344 return NS_ERROR_OUT_OF_MEMORY;
2346 *result = mTagText;
2347 return NS_OK;
2350 NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(PRUint16& n, const char*const*& names, const char*const*& values)
2352 nsresult rv = EnsureCachedAttrParamArrays();
2353 NS_ENSURE_SUCCESS(rv, rv);
2355 n = mNumCachedParams;
2356 if (n) {
2357 names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1);
2358 values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1);
2359 } else
2360 names = values = nsnull;
2362 return rv;
2365 NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result)
2367 NS_ENSURE_ARG_POINTER(name);
2368 NS_ENSURE_ARG_POINTER(result);
2370 nsresult rv = EnsureCachedAttrParamArrays();
2371 NS_ENSURE_SUCCESS(rv, rv);
2373 *result = nsnull;
2375 for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) {
2376 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
2377 *result = mCachedAttrParamValues[i];
2378 return NS_OK;
2382 return NS_ERROR_FAILURE;
2385 NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentBase(const char* *result)
2387 NS_ENSURE_ARG_POINTER(result);
2388 nsresult rv = NS_OK;
2389 if (mDocumentBase.IsEmpty()) {
2390 if (!mOwner) {
2391 *result = nsnull;
2392 return NS_ERROR_FAILURE;
2395 nsIDocument* doc = mContent->GetOwnerDoc();
2396 NS_ASSERTION(doc, "Must have an owner doc");
2397 rv = doc->GetBaseURI()->GetSpec(mDocumentBase);
2399 if (NS_SUCCEEDED(rv))
2400 *result = ToNewCString(mDocumentBase);
2401 return rv;
2404 static nsDataHashtable<nsDepCharHashKey, const char *> * gCharsetMap;
2405 typedef struct {
2406 char mozName[16];
2407 char javaName[12];
2408 } moz2javaCharset;
2410 /* XXX If you add any strings longer than
2411 * {"x-mac-cyrillic", "MacCyrillic"},
2412 * {"x-mac-ukrainian", "MacUkraine"},
2413 * to the following array then you MUST update the
2414 * sizes of the arrays in the moz2javaCharset struct
2417 static const moz2javaCharset charsets[] =
2419 {"windows-1252", "Cp1252"},
2420 {"IBM850", "Cp850"},
2421 {"IBM852", "Cp852"},
2422 {"IBM855", "Cp855"},
2423 {"IBM857", "Cp857"},
2424 {"IBM828", "Cp862"},
2425 {"IBM864", "Cp864"},
2426 {"IBM866", "Cp866"},
2427 {"windows-1250", "Cp1250"},
2428 {"windows-1251", "Cp1251"},
2429 {"windows-1253", "Cp1253"},
2430 {"windows-1254", "Cp1254"},
2431 {"windows-1255", "Cp1255"},
2432 {"windows-1256", "Cp1256"},
2433 {"windows-1257", "Cp1257"},
2434 {"windows-1258", "Cp1258"},
2435 {"EUC-JP", "EUC_JP"},
2436 {"EUC-KR", "EUC_KR"},
2437 {"x-euc-tw", "EUC_TW"},
2438 {"gb18030", "GB18030"},
2439 {"x-gbk", "GBK"},
2440 {"ISO-2022-JP", "ISO2022JP"},
2441 {"ISO-2022-KR", "ISO2022KR"},
2442 {"ISO-8859-2", "ISO8859_2"},
2443 {"ISO-8859-3", "ISO8859_3"},
2444 {"ISO-8859-4", "ISO8859_4"},
2445 {"ISO-8859-5", "ISO8859_5"},
2446 {"ISO-8859-6", "ISO8859_6"},
2447 {"ISO-8859-7", "ISO8859_7"},
2448 {"ISO-8859-8", "ISO8859_8"},
2449 {"ISO-8859-9", "ISO8859_9"},
2450 {"ISO-8859-13", "ISO8859_13"},
2451 {"x-johab", "Johab"},
2452 {"KOI8-R", "KOI8_R"},
2453 {"TIS-620", "MS874"},
2454 {"windows-936", "MS936"},
2455 {"x-windows-949", "MS949"},
2456 {"x-mac-arabic", "MacArabic"},
2457 {"x-mac-croatian", "MacCroatia"},
2458 {"x-mac-cyrillic", "MacCyrillic"},
2459 {"x-mac-greek", "MacGreek"},
2460 {"x-mac-hebrew", "MacHebrew"},
2461 {"x-mac-icelandic", "MacIceland"},
2462 {"x-mac-roman", "MacRoman"},
2463 {"x-mac-romanian", "MacRomania"},
2464 {"x-mac-ukrainian", "MacUkraine"},
2465 {"Shift_JIS", "SJIS"},
2466 {"TIS-620", "TIS620"}
2469 NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentEncoding(const char* *result)
2471 NS_ENSURE_ARG_POINTER(result);
2472 *result = nsnull;
2474 nsresult rv;
2475 // XXX sXBL/XBL2 issue: current doc or owner doc?
2476 nsCOMPtr<nsIDocument> doc;
2477 rv = GetDocument(getter_AddRefs(doc));
2478 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get document");
2479 if (NS_FAILED(rv))
2480 return rv;
2482 const nsCString &charset = doc->GetDocumentCharacterSet();
2484 if (charset.IsEmpty())
2485 return NS_OK;
2487 // common charsets and those not requiring conversion first
2488 if (charset.EqualsLiteral("us-ascii")) {
2489 *result = PL_strdup("US_ASCII");
2490 } else if (charset.EqualsLiteral("ISO-8859-1") ||
2491 !nsCRT::strncmp(PromiseFlatCString(charset).get(), "UTF", 3)) {
2492 *result = ToNewCString(charset);
2493 } else {
2494 if (!gCharsetMap) {
2495 const int NUM_CHARSETS = sizeof(charsets) / sizeof(moz2javaCharset);
2496 gCharsetMap = new nsDataHashtable<nsDepCharHashKey, const char*>();
2497 if (!gCharsetMap || !gCharsetMap->Init(NUM_CHARSETS))
2498 return NS_ERROR_OUT_OF_MEMORY;
2500 for (PRUint16 i = 0; i < NUM_CHARSETS; i++) {
2501 gCharsetMap->Put(charsets[i].mozName, charsets[i].javaName);
2504 // if found mapping, return it; otherwise return original charset
2505 const char *mapping;
2506 *result = gCharsetMap->Get(charset.get(), &mapping) ? PL_strdup(mapping) :
2507 ToNewCString(charset);
2510 return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
2513 NS_IMETHODIMP nsPluginInstanceOwner::GetAlignment(const char* *result)
2515 return GetAttribute("ALIGN", result);
2518 NS_IMETHODIMP nsPluginInstanceOwner::GetWidth(PRUint32 *result)
2520 NS_ENSURE_ARG_POINTER(result);
2522 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
2524 *result = mPluginWindow->width;
2526 return NS_OK;
2529 NS_IMETHODIMP nsPluginInstanceOwner::GetHeight(PRUint32 *result)
2531 NS_ENSURE_ARG_POINTER(result);
2533 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
2535 *result = mPluginWindow->height;
2537 return NS_OK;
2541 NS_IMETHODIMP nsPluginInstanceOwner::GetBorderVertSpace(PRUint32 *result)
2543 nsresult rv;
2544 const char *vspace;
2546 rv = GetAttribute("VSPACE", &vspace);
2548 if (NS_OK == rv) {
2549 if (*result != 0)
2550 *result = (PRUint32)atol(vspace);
2551 else
2552 *result = 0;
2554 else
2555 *result = 0;
2557 return rv;
2560 NS_IMETHODIMP nsPluginInstanceOwner::GetBorderHorizSpace(PRUint32 *result)
2562 nsresult rv;
2563 const char *hspace;
2565 rv = GetAttribute("HSPACE", &hspace);
2567 if (NS_OK == rv) {
2568 if (*result != 0)
2569 *result = (PRUint32)atol(hspace);
2570 else
2571 *result = 0;
2573 else
2574 *result = 0;
2576 return rv;
2579 NS_IMETHODIMP nsPluginInstanceOwner::GetUniqueID(PRUint32 *result)
2581 NS_ENSURE_ARG_POINTER(result);
2582 *result = NS_PTR_TO_INT32(mOwner);
2583 return NS_OK;
2586 #ifdef OJI
2587 NS_IMETHODIMP nsPluginInstanceOwner::GetCode(const char* *result)
2589 nsresult rv;
2590 nsPluginTagType tagType;
2591 NS_ENSURE_SUCCESS(rv = GetTagType(&tagType), rv);
2593 rv = NS_ERROR_FAILURE;
2594 if (nsPluginTagType_Object != tagType)
2595 rv = GetAttribute("CODE", result);
2596 if (NS_FAILED(rv))
2597 rv = GetParameter("CODE", result);
2599 return rv;
2602 NS_IMETHODIMP nsPluginInstanceOwner::GetCodeBase(const char* *result)
2604 nsresult rv;
2605 if (NS_FAILED(rv = GetAttribute("CODEBASE", result)))
2606 rv = GetParameter("CODEBASE", result);
2607 return rv;
2610 NS_IMETHODIMP nsPluginInstanceOwner::GetArchive(const char* *result)
2612 nsresult rv;
2613 if (NS_FAILED(rv = GetAttribute("ARCHIVE", result)))
2614 rv = GetParameter("ARCHIVE", result);
2615 return rv;
2618 NS_IMETHODIMP nsPluginInstanceOwner::GetName(const char* *result)
2620 nsresult rv;
2621 nsPluginTagType tagType;
2622 NS_ENSURE_SUCCESS(rv = GetTagType(&tagType), rv);
2624 rv = NS_ERROR_FAILURE;
2625 if (nsPluginTagType_Object != tagType)
2626 rv = GetAttribute("NAME", result);
2627 if (NS_FAILED(rv))
2628 rv = GetParameter("NAME", result);
2630 return rv;
2633 NS_IMETHODIMP nsPluginInstanceOwner::GetMayScript(PRBool *result)
2635 NS_ENSURE_ARG_POINTER(result);
2636 nsPluginTagType tagType;
2637 NS_ENSURE_SUCCESS(GetTagType(&tagType), NS_ERROR_FAILURE);
2639 const char* unused;
2640 if (nsPluginTagType_Object == tagType)
2641 *result = NS_SUCCEEDED(GetParameter("MAYSCRIPT", &unused));
2642 else
2643 *result = NS_SUCCEEDED(GetAttribute("MAYSCRIPT", &unused));
2645 return NS_OK;
2647 #endif /* OJI */
2649 // Cache the attributes and/or parameters of our tag into a single set
2650 // of arrays to be compatible with 4.x. The attributes go first,
2651 // followed by a PARAM/null and then any PARAM tags. Also, hold the
2652 // cached array around for the duration of the life of the instance
2653 // because 4.x did. See bug 111008.
2655 nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
2657 if (mCachedAttrParamValues)
2658 return NS_OK;
2660 NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) &&
2661 !mCachedAttrParamNames,
2662 "re-cache of attrs/params not implemented! use the DOM "
2663 "node directy instead");
2664 NS_ENSURE_TRUE(mOwner, NS_ERROR_NULL_POINTER);
2666 // first, we need to find out how much we need to allocate for our
2667 // arrays count up attributes
2668 mNumCachedAttrs = 0;
2670 PRUint32 cattrs = mContent->GetAttrCount();
2672 if (cattrs < 0x0000FFFF) {
2673 // unsigned 32 bits to unsigned 16 bits conversion
2674 mNumCachedAttrs = static_cast<PRUint16>(cattrs);
2675 } else {
2676 mNumCachedAttrs = 0xFFFE; // minus one in case we add an extra "src" entry below
2679 // now, we need to find all the PARAM tags that are children of us
2680 // however, be carefull NOT to include any PARAMs that don't have us
2681 // as a direct parent. For nested object (or applet) tags, be sure
2682 // to only round up the param tags that coorespond with THIS
2683 // instance. And also, weed out any bogus tags that may get in the
2684 // way, see bug 39609. Then, with any param tag that meet our
2685 // qualification, temporarly cache them in an nsCOMArray until
2686 // we can figure out what size to make our fixed char* array.
2688 mNumCachedParams = 0;
2689 nsCOMArray<nsIDOMElement> ourParams;
2691 // use the DOM to get us ALL our dependent PARAM tags, even if not
2692 // ours
2693 nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(mContent);
2694 NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE);
2696 nsCOMPtr<nsIDOMNodeList> allParams;
2698 nsINodeInfo *ni = mContent->NodeInfo();
2700 // Making DOM method calls can cause our frame to go away, which
2701 // might kill us...
2702 nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
2704 if (ni->NamespaceEquals(kNameSpaceID_XHTML)) {
2705 // For XHTML elements we need to take the namespace URI into
2706 // account when looking for param elements.
2708 NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
2710 mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"),
2711 getter_AddRefs(allParams));
2712 } else {
2713 // If content is not XHTML, it must be HTML, no need to worry
2714 // about namespaces then...
2716 mydomElement->GetElementsByTagName(NS_LITERAL_STRING("param"),
2717 getter_AddRefs(allParams));
2720 if (allParams) {
2721 PRUint32 numAllParams;
2722 allParams->GetLength(&numAllParams);
2723 // loop through every so called dependent PARAM tag to check if it
2724 // "belongs" to us
2726 for (PRUint32 i = 0; i < numAllParams; i++) {
2727 nsCOMPtr<nsIDOMNode> pnode;
2728 allParams->Item(i, getter_AddRefs(pnode));
2730 nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
2731 if (domelement) {
2732 // let's NOT count up param tags that don't have a name attribute
2733 nsAutoString name;
2734 domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
2735 if (!name.IsEmpty()) {
2736 nsCOMPtr<nsIDOMNode> parent;
2737 nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
2738 nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
2739 pnode->GetParentNode(getter_AddRefs(parent));
2740 // walk up the parents of this PARAM until we find an object
2741 // (or applet) tag
2743 while (!(domobject || domapplet) && parent) {
2744 domobject = do_QueryInterface(parent);
2745 domapplet = do_QueryInterface(parent);
2746 nsCOMPtr<nsIDOMNode> temp;
2747 parent->GetParentNode(getter_AddRefs(temp));
2748 parent = temp;
2751 if (domapplet || domobject) {
2752 if (domapplet)
2753 parent = domapplet;
2754 else
2755 parent = domobject;
2757 // now check to see if this PARAM's parent is us. if so,
2758 // cache it for later
2760 nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(mydomElement);
2761 if (parent == mydomNode) {
2762 ourParams.AppendObject(domelement);
2770 // We're done with DOM method calls now; make sure we still have a frame.
2771 NS_ENSURE_TRUE(mOwner, NS_ERROR_OUT_OF_MEMORY);
2773 PRUint32 cparams = ourParams.Count(); // unsigned 32 bits to unsigned 16 bits conversion
2774 if (cparams < 0x0000FFFF)
2775 mNumCachedParams = static_cast<PRUint16>(cparams);
2776 else
2777 mNumCachedParams = 0xFFFF;
2779 // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
2780 // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
2781 // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
2782 // look for "data", lets instead copy the "data" attribute and add another entry
2783 // to the bottom of the array if there isn't already a "src" specified.
2784 PRInt16 numRealAttrs = mNumCachedAttrs;
2785 nsAutoString data;
2786 if (mContent->Tag() == nsGkAtoms::object
2787 && !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::src)
2788 && mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, data)) {
2789 mNumCachedAttrs++;
2792 // now lets make the arrays
2793 mCachedAttrParamNames = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1);
2794 NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY);
2795 mCachedAttrParamValues = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1);
2796 NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY);
2798 // let's fill in our attributes
2799 PRInt16 c = 0;
2801 // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the
2802 // attribute order. So we want to make sure we give the plugin the
2803 // attributes in the order they came in in the source, to be compatible with
2804 // other browsers. Now in HTML, the storage order is the reverse of the
2805 // source order, while in XML and XHTML it's the same as the source order
2806 // (see the AddAttributes functions in the HTML and XML content sinks).
2807 PRInt16 start, end, increment;
2808 if (mContent->IsNodeOfType(nsINode::eHTML) &&
2809 mContent->NodeInfo()->NamespaceEquals(kNameSpaceID_None)) {
2810 // HTML. Walk attributes in reverse order.
2811 start = numRealAttrs - 1;
2812 end = -1;
2813 increment = -1;
2814 } else {
2815 // XHTML or XML. Walk attributes in forward order.
2816 start = 0;
2817 end = numRealAttrs;
2818 increment = 1;
2820 for (PRInt16 index = start; index != end; index += increment) {
2821 const nsAttrName* attrName = mContent->GetAttrNameAt(index);
2822 nsIAtom* atom = attrName->LocalName();
2823 nsAutoString value;
2824 mContent->GetAttr(attrName->NamespaceID(), atom, value);
2825 nsAutoString name;
2826 atom->ToString(name);
2828 FixUpURLS(name, value);
2830 mCachedAttrParamNames [c] = ToNewUTF8String(name);
2831 mCachedAttrParamValues[c] = ToNewUTF8String(value);
2832 c++;
2835 // if the conditions above were met, copy the "data" attribute to a "src" array entry
2836 if (data.Length()) {
2837 mCachedAttrParamNames [mNumCachedAttrs-1] = ToNewUTF8String(NS_LITERAL_STRING("SRC"));
2838 mCachedAttrParamValues[mNumCachedAttrs-1] = ToNewUTF8String(data);
2841 // add our PARAM and null separator
2842 mCachedAttrParamNames [mNumCachedAttrs] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
2843 mCachedAttrParamValues[mNumCachedAttrs] = nsnull;
2845 // now fill in the PARAM name/value pairs from the cached DOM nodes
2846 c = 0;
2847 for (PRInt16 idx = 0; idx < mNumCachedParams; idx++) {
2848 nsIDOMElement* param = ourParams.ObjectAt(idx);
2849 if (param) {
2850 nsAutoString name;
2851 nsAutoString value;
2852 param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above
2853 param->GetAttribute(NS_LITERAL_STRING("value"), value);
2855 FixUpURLS(name, value);
2858 * According to the HTML 4.01 spec, at
2859 * http://www.w3.org/TR/html4/types.html#type-cdata
2860 * ''User agents may ignore leading and trailing
2861 * white space in CDATA attribute values (e.g., "
2862 * myval " may be interpreted as "myval"). Authors
2863 * should not declare attribute values with
2864 * leading or trailing white space.''
2865 * However, do not trim consecutive spaces as in bug 122119
2867 name.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE);
2868 value.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE);
2869 mCachedAttrParamNames [mNumCachedAttrs + 1 + c] = ToNewUTF8String(name);
2870 mCachedAttrParamValues[mNumCachedAttrs + 1 + c] = ToNewUTF8String(value);
2871 c++; // rules!
2875 return NS_OK;
2879 // Here's where we forward events to plugins.
2881 #ifdef XP_MACOSX
2883 static void InitializeEventRecord(EventRecord* event)
2885 memset(event, 0, sizeof(EventRecord));
2886 ::GetGlobalMouse(&event->where);
2887 event->when = ::TickCount();
2888 event->modifiers = ::GetCurrentKeyModifiers();
2891 NPDrawingModel nsPluginInstanceOwner::GetDrawingModel()
2893 #ifndef NP_NO_QUICKDRAW
2894 NPDrawingModel drawingModel = NPDrawingModelQuickDraw;
2895 #else
2896 NPDrawingModel drawingModel = NPDrawingModelCoreGraphics;
2897 #endif
2899 if (!mInstance)
2900 return drawingModel;
2902 mInstance->GetValue(nsPluginInstanceVariable_DrawingModel,
2903 (void *)&drawingModel);
2905 return drawingModel;
2908 void nsPluginInstanceOwner::GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord* origEvent, EventRecord& aMacEvent)
2910 nsPresContext* presContext = mOwner ? mOwner->PresContext() : nsnull;
2911 InitializeEventRecord(&aMacEvent);
2912 switch (anEvent.message) {
2913 case NS_FOCUS_EVENT_START: // this is the same as NS_FOCUS_CONTENT
2914 aMacEvent.what = nsPluginEventType_GetFocusEvent;
2915 if (presContext) {
2916 nsIContent* content = mContent;
2917 if (content)
2918 content->SetFocus(presContext);
2920 break;
2922 case NS_BLUR_CONTENT:
2923 aMacEvent.what = nsPluginEventType_LoseFocusEvent;
2924 if (presContext) {
2925 nsIContent* content = mContent;
2926 if (content)
2927 content->RemoveFocus(presContext);
2929 break;
2931 case NS_MOUSE_MOVE:
2932 case NS_MOUSE_ENTER:
2933 if (origEvent)
2934 aMacEvent = *origEvent;
2935 aMacEvent.what = nsPluginEventType_AdjustCursorEvent;
2936 break;
2940 #endif
2942 nsresult nsPluginInstanceOwner::ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
2944 #ifdef XP_MACOSX
2945 CancelTimer();
2947 if (mInstance) {
2948 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2949 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
2950 EventRecord scrollEvent;
2951 InitializeEventRecord(&scrollEvent);
2952 scrollEvent.what = nsPluginEventType_ScrollingBeginsEvent;
2954 WindowRef window = FixUpPluginWindow(ePluginPaintDisable);
2955 if (window) {
2956 nsPluginEvent pluginEvent = { &scrollEvent, nsPluginPlatformWindowRef(window) };
2957 PRBool eventHandled = PR_FALSE;
2958 mInstance->HandleEvent(&pluginEvent, &eventHandled);
2960 pluginWidget->EndDrawPlugin();
2963 #endif
2964 return NS_OK;
2967 nsresult nsPluginInstanceOwner::ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
2969 #ifdef XP_MACOSX
2970 if (mInstance) {
2971 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2972 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
2973 EventRecord scrollEvent;
2974 InitializeEventRecord(&scrollEvent);
2975 scrollEvent.what = nsPluginEventType_ScrollingEndsEvent;
2977 WindowRef window = FixUpPluginWindow(ePluginPaintEnable);
2978 if (window) {
2979 nsPluginEvent pluginEvent = { &scrollEvent, nsPluginPlatformWindowRef(window) };
2980 PRBool eventHandled = PR_FALSE;
2981 mInstance->HandleEvent(&pluginEvent, &eventHandled);
2983 pluginWidget->EndDrawPlugin();
2986 // FIXME - Only invalidate the newly revealed amount.
2987 // XXX necessary?
2988 if (mWidget)
2989 mWidget->Invalidate(PR_TRUE);
2991 #endif
2993 StartTimer(NORMAL_PLUGIN_DELAY);
2994 return NS_OK;
2997 /*=============== nsIFocusListener ======================*/
2998 nsresult nsPluginInstanceOwner::Focus(nsIDOMEvent * aFocusEvent)
3000 mContentFocused = PR_TRUE;
3001 return DispatchFocusToPlugin(aFocusEvent);
3004 nsresult nsPluginInstanceOwner::Blur(nsIDOMEvent * aFocusEvent)
3006 mContentFocused = PR_FALSE;
3007 return DispatchFocusToPlugin(aFocusEvent);
3010 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
3012 #ifndef XP_MACOSX
3013 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type) {
3014 // continue only for cases without child window
3015 return aFocusEvent->PreventDefault(); // consume event
3017 #endif
3019 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aFocusEvent));
3020 if (privateEvent) {
3021 nsEvent * theEvent;
3022 privateEvent->GetInternalNSEvent(&theEvent);
3023 if (theEvent) {
3024 // we only care about the message in ProcessEvent
3025 nsGUIEvent focusEvent(NS_IS_TRUSTED_EVENT(theEvent), theEvent->message,
3026 nsnull);
3027 nsEventStatus rv = ProcessEvent(focusEvent);
3028 if (nsEventStatus_eConsumeNoDefault == rv) {
3029 aFocusEvent->PreventDefault();
3030 aFocusEvent->StopPropagation();
3033 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, focusEvent null");
3035 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, privateEvent null");
3037 return NS_OK;
3040 /*=============== nsIDOMDragListener ======================*/
3041 nsresult nsPluginInstanceOwner::DragEnter(nsIDOMEvent* aMouseEvent)
3043 if (mInstance) {
3044 // Let the plugin handle drag events.
3045 aMouseEvent->PreventDefault();
3046 aMouseEvent->StopPropagation();
3049 return NS_OK;
3052 nsresult nsPluginInstanceOwner::DragOver(nsIDOMEvent* aMouseEvent)
3054 if (mInstance) {
3055 // Let the plugin handle drag events.
3056 aMouseEvent->PreventDefault();
3057 aMouseEvent->StopPropagation();
3060 return NS_OK;
3063 nsresult nsPluginInstanceOwner::DragExit(nsIDOMEvent* aMouseEvent)
3065 if (mInstance) {
3066 // Let the plugin handle drag events.
3067 aMouseEvent->PreventDefault();
3068 aMouseEvent->StopPropagation();
3071 return NS_OK;
3074 nsresult nsPluginInstanceOwner::DragDrop(nsIDOMEvent* aMouseEvent)
3076 if (mInstance) {
3077 // Let the plugin handle drag events.
3078 aMouseEvent->PreventDefault();
3079 aMouseEvent->StopPropagation();
3082 return NS_OK;
3085 nsresult nsPluginInstanceOwner::DragGesture(nsIDOMEvent* aMouseEvent)
3087 if (mInstance) {
3088 // Let the plugin handle drag events.
3089 aMouseEvent->PreventDefault();
3090 aMouseEvent->StopPropagation();
3093 return NS_OK;
3096 nsresult nsPluginInstanceOwner::Drag(nsIDOMEvent* aMouseEvent)
3098 if (mInstance) {
3099 // Let the plugin handle drag events.
3100 aMouseEvent->PreventDefault();
3101 aMouseEvent->StopPropagation();
3104 return NS_OK;
3107 nsresult nsPluginInstanceOwner::DragEnd(nsIDOMEvent* aMouseEvent)
3109 if (mInstance) {
3110 // Let the plugin handle drag events.
3111 aMouseEvent->PreventDefault();
3112 aMouseEvent->StopPropagation();
3115 return NS_OK;
3120 /*=============== nsIKeyListener ======================*/
3121 nsresult nsPluginInstanceOwner::KeyDown(nsIDOMEvent* aKeyEvent)
3123 return DispatchKeyToPlugin(aKeyEvent);
3126 nsresult nsPluginInstanceOwner::KeyUp(nsIDOMEvent* aKeyEvent)
3128 return DispatchKeyToPlugin(aKeyEvent);
3131 nsresult nsPluginInstanceOwner::KeyPress(nsIDOMEvent* aKeyEvent)
3133 #ifdef XP_MACOSX // send KeyPress events only on Mac
3135 // KeyPress events are really synthesized keyDown events.
3136 // Here we check the native message of the event so that
3137 // we won't send the plugin two keyDown events.
3138 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
3139 if (privateEvent) {
3140 nsEvent *theEvent;
3141 privateEvent->GetInternalNSEvent(&theEvent);
3142 const nsGUIEvent *guiEvent = (nsGUIEvent*)theEvent;
3143 const EventRecord *ev = (EventRecord*)(guiEvent->nativeMsg);
3144 if (guiEvent &&
3145 guiEvent->message == NS_KEY_PRESS &&
3146 ev &&
3147 ev->what == keyDown)
3148 return aKeyEvent->PreventDefault(); // consume event
3151 // Nasty hack to avoid recursive event dispatching with Java. Java can
3152 // dispatch key events to a TSM handler, which comes back and calls
3153 // [ChildView insertText:] on the cocoa widget, which sends a key
3154 // event back down.
3155 static PRBool sInKeyDispatch = PR_FALSE;
3157 if (sInKeyDispatch)
3158 return aKeyEvent->PreventDefault(); // consume event
3160 sInKeyDispatch = PR_TRUE;
3161 nsresult rv = DispatchKeyToPlugin(aKeyEvent);
3162 sInKeyDispatch = PR_FALSE;
3163 return rv;
3164 #else
3165 if (mInstance) {
3166 // If this event is going to the plugin, we want to kill it.
3167 // Not actually sending keypress to the plugin, since we didn't before.
3168 aKeyEvent->PreventDefault();
3169 aKeyEvent->StopPropagation();
3171 return NS_OK;
3172 #endif
3175 nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent)
3177 #ifndef XP_MACOSX
3178 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
3179 return aKeyEvent->PreventDefault(); // consume event
3180 // continue only for cases without child window
3181 #endif
3183 if (mInstance) {
3184 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
3185 if (privateEvent) {
3186 nsKeyEvent* keyEvent = nsnull;
3187 privateEvent->GetInternalNSEvent((nsEvent**)&keyEvent);
3188 if (keyEvent) {
3189 nsEventStatus rv = ProcessEvent(*keyEvent);
3190 if (nsEventStatus_eConsumeNoDefault == rv) {
3191 aKeyEvent->PreventDefault();
3192 aKeyEvent->StopPropagation();
3195 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, keyEvent null");
3197 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, privateEvent null");
3200 return NS_OK;
3203 /*=============== nsIMouseMotionListener ======================*/
3205 nsresult
3206 nsPluginInstanceOwner::MouseMove(nsIDOMEvent* aMouseEvent)
3208 #if !defined(XP_MACOSX)
3209 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
3210 return aMouseEvent->PreventDefault(); // consume event
3211 // continue only for cases without child window
3212 #endif
3214 // don't send mouse events if we are hiddden
3215 if (!mWidgetVisible)
3216 return NS_OK;
3218 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
3219 if (privateEvent) {
3220 nsMouseEvent* mouseEvent = nsnull;
3221 privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
3222 if (mouseEvent) {
3223 nsEventStatus rv = ProcessEvent(*mouseEvent);
3224 if (nsEventStatus_eConsumeNoDefault == rv) {
3225 return aMouseEvent->PreventDefault(); // consume event
3228 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, mouseEvent null");
3230 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, privateEvent null");
3232 return NS_OK;
3235 /*=============== nsIMouseListener ======================*/
3237 nsresult
3238 nsPluginInstanceOwner::MouseDown(nsIDOMEvent* aMouseEvent)
3240 #if !defined(XP_MACOSX)
3241 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
3242 return aMouseEvent->PreventDefault(); // consume event
3243 // continue only for cases without child window
3244 #endif
3246 // if the plugin is windowless, we need to set focus ourselves
3247 // otherwise, we might not get key events
3248 if (mOwner && mPluginWindow &&
3249 mPluginWindow->type == nsPluginWindowType_Drawable) {
3250 mContent->SetFocus(mOwner->PresContext());
3253 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
3254 if (privateEvent) {
3255 nsMouseEvent* mouseEvent = nsnull;
3256 privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
3257 if (mouseEvent) {
3258 nsEventStatus rv = ProcessEvent(*mouseEvent);
3259 if (nsEventStatus_eConsumeNoDefault == rv) {
3260 return aMouseEvent->PreventDefault(); // consume event
3263 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, mouseEvent null");
3265 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, privateEvent null");
3267 return NS_OK;
3270 nsresult
3271 nsPluginInstanceOwner::MouseUp(nsIDOMEvent* aMouseEvent)
3273 return DispatchMouseToPlugin(aMouseEvent);
3276 nsresult
3277 nsPluginInstanceOwner::MouseClick(nsIDOMEvent* aMouseEvent)
3279 return DispatchMouseToPlugin(aMouseEvent);
3282 nsresult
3283 nsPluginInstanceOwner::MouseDblClick(nsIDOMEvent* aMouseEvent)
3285 return DispatchMouseToPlugin(aMouseEvent);
3288 nsresult
3289 nsPluginInstanceOwner::MouseOver(nsIDOMEvent* aMouseEvent)
3291 return DispatchMouseToPlugin(aMouseEvent);
3294 nsresult
3295 nsPluginInstanceOwner::MouseOut(nsIDOMEvent* aMouseEvent)
3297 return DispatchMouseToPlugin(aMouseEvent);
3300 nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent)
3302 #if !defined(XP_MACOSX)
3303 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
3304 return aMouseEvent->PreventDefault(); // consume event
3305 // continue only for cases without child window
3306 #endif
3308 // don't send mouse events if we are hiddden
3309 if (!mWidgetVisible)
3310 return NS_OK;
3312 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
3313 if (privateEvent) {
3314 nsMouseEvent* mouseEvent = nsnull;
3315 privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
3316 if (mouseEvent) {
3317 nsEventStatus rv = ProcessEvent(*mouseEvent);
3318 if (nsEventStatus_eConsumeNoDefault == rv) {
3319 aMouseEvent->PreventDefault();
3320 aMouseEvent->StopPropagation();
3323 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, mouseEvent null");
3325 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, privateEvent null");
3327 return NS_OK;
3330 nsresult
3331 nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
3333 return NS_OK;
3336 #ifdef MOZ_X11
3337 static unsigned int XInputEventState(const nsInputEvent& anEvent)
3339 unsigned int state = 0;
3340 if(anEvent.isShift) state |= ShiftMask;
3341 if(anEvent.isControl) state |= ControlMask;
3342 if(anEvent.isAlt) state |= Mod1Mask;
3343 if(anEvent.isMeta) state |= Mod4Mask;
3344 return state;
3346 #endif
3348 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
3350 // printf("nsGUIEvent.message: %d\n", anEvent.message);
3351 nsEventStatus rv = nsEventStatus_eIgnore;
3352 if (!mInstance || !mOwner) // if mInstance is null, we shouldn't be here
3353 return rv;
3355 #ifdef XP_MACOSX
3356 // check for null mWidget
3357 if (mWidget) {
3358 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3359 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
3360 EventRecord macEvent;
3361 EventRecord* event = (EventRecord*)anEvent.nativeMsg;
3362 if ((event == NULL) || (event->what == nullEvent) ||
3363 (anEvent.message == NS_FOCUS_CONTENT) ||
3364 (anEvent.message == NS_BLUR_CONTENT) ||
3365 (anEvent.message == NS_MOUSE_MOVE) ||
3366 (anEvent.message == NS_MOUSE_ENTER)) {
3367 GUItoMacEvent(anEvent, event, macEvent);
3368 event = &macEvent;
3371 if (anEvent.message == NS_FOCUS_CONTENT) {
3372 // Work around an issue in the Flash plugin, which can cache a pointer
3373 // to a doomed TSM document (one that belongs to a NSTSMInputContext)
3374 // and try to activate it after it has been deleted. See bug 183313.
3375 ::DeactivateTSMDocument(::TSMGetActiveDocument());
3378 PRBool eventHandled = PR_FALSE;
3379 WindowRef window = FixUpPluginWindow(ePluginPaintIgnore);
3380 if (window) {
3381 nsPluginEvent pluginEvent = { event, nsPluginPlatformWindowRef(window) };
3382 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3385 if (eventHandled && !(anEvent.eventStructType == NS_MOUSE_EVENT &&
3386 anEvent.message == NS_MOUSE_BUTTON_DOWN &&
3387 static_cast<const nsMouseEvent&>(anEvent).button ==
3388 nsMouseEvent::eLeftButton &&
3389 !mContentFocused))
3390 rv = nsEventStatus_eConsumeNoDefault;
3392 pluginWidget->EndDrawPlugin();
3395 #endif
3397 #ifdef XP_WIN
3398 // this code supports windowless plugins
3399 nsPluginEvent * pPluginEvent = (nsPluginEvent *)anEvent.nativeMsg;
3400 // we can get synthetic events from the nsEventStateManager... these
3401 // have no nativeMsg
3402 nsPluginEvent pluginEvent;
3403 if (!pPluginEvent) {
3404 switch (anEvent.message) {
3405 case NS_FOCUS_CONTENT:
3406 pluginEvent.event = WM_SETFOCUS;
3407 pluginEvent.wParam = 0;
3408 pluginEvent.lParam = 0;
3409 pPluginEvent = &pluginEvent;
3410 break;
3411 case NS_BLUR_CONTENT:
3412 pluginEvent.event = WM_KILLFOCUS;
3413 pluginEvent.wParam = 0;
3414 pluginEvent.lParam = 0;
3415 pPluginEvent = &pluginEvent;
3416 break;
3420 if (pPluginEvent) {
3421 PRBool eventHandled = PR_FALSE;
3422 mInstance->HandleEvent(pPluginEvent, &eventHandled);
3423 if (eventHandled)
3424 rv = nsEventStatus_eConsumeNoDefault;
3426 #endif
3428 #ifdef MOZ_X11
3429 // this code supports windowless plugins
3430 nsIWidget* widget = anEvent.widget;
3431 nsPluginEvent pluginEvent;
3432 pluginEvent.event.type = 0;
3434 switch(anEvent.eventStructType)
3436 case NS_MOUSE_EVENT:
3438 switch (anEvent.message)
3440 case NS_MOUSE_CLICK:
3441 case NS_MOUSE_DOUBLECLICK:
3442 // Button up/down events sent instead.
3443 return rv;
3446 // Get reference point relative to plugin origin.
3447 const nsPresContext* presContext = mOwner->PresContext();
3448 nsPoint appPoint =
3449 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mOwner);
3450 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
3451 presContext->AppUnitsToDevPixels(appPoint.y));
3452 const nsMouseEvent& mouseEvent =
3453 static_cast<const nsMouseEvent&>(anEvent);
3454 // Get reference point relative to screen:
3455 nsRect windowRect(anEvent.refPoint, nsSize(1, 1));
3456 nsRect rootPoint(-1,-1,1,1);
3457 if (widget)
3458 widget->WidgetToScreen(windowRect, rootPoint);
3459 #ifdef MOZ_WIDGET_GTK2
3460 Window root = GDK_ROOT_WINDOW();
3461 #else
3462 Window root = None; // Could XQueryTree, but this is not important.
3463 #endif
3465 switch (anEvent.message)
3467 case NS_MOUSE_ENTER_SYNTH:
3468 case NS_MOUSE_EXIT_SYNTH:
3470 XCrossingEvent& event = pluginEvent.event.xcrossing;
3471 event.type = anEvent.message == NS_MOUSE_ENTER_SYNTH ?
3472 EnterNotify : LeaveNotify;
3473 event.root = root;
3474 event.time = anEvent.time;
3475 event.x = pluginPoint.x;
3476 event.y = pluginPoint.y;
3477 event.x_root = rootPoint.x;
3478 event.y_root = rootPoint.y;
3479 event.state = XInputEventState(mouseEvent);
3480 // information lost
3481 event.subwindow = None;
3482 event.mode = -1;
3483 event.detail = NotifyDetailNone;
3484 event.same_screen = True;
3485 event.focus = mContentFocused;
3487 break;
3488 case NS_MOUSE_MOVE:
3490 XMotionEvent& event = pluginEvent.event.xmotion;
3491 event.type = MotionNotify;
3492 event.root = root;
3493 event.time = anEvent.time;
3494 event.x = pluginPoint.x;
3495 event.y = pluginPoint.y;
3496 event.x_root = rootPoint.x;
3497 event.y_root = rootPoint.y;
3498 event.state = XInputEventState(mouseEvent);
3499 // information lost
3500 event.subwindow = None;
3501 event.is_hint = NotifyNormal;
3502 event.same_screen = True;
3504 break;
3505 case NS_MOUSE_BUTTON_DOWN:
3506 case NS_MOUSE_BUTTON_UP:
3508 XButtonEvent& event = pluginEvent.event.xbutton;
3509 event.type = anEvent.message == NS_MOUSE_BUTTON_DOWN ?
3510 ButtonPress : ButtonRelease;
3511 event.root = root;
3512 event.time = anEvent.time;
3513 event.x = pluginPoint.x;
3514 event.y = pluginPoint.y;
3515 event.x_root = rootPoint.x;
3516 event.y_root = rootPoint.y;
3517 event.state = XInputEventState(mouseEvent);
3518 switch (mouseEvent.button)
3520 case nsMouseEvent::eMiddleButton:
3521 event.button = 2;
3522 break;
3523 case nsMouseEvent::eRightButton:
3524 event.button = 3;
3525 break;
3526 default: // nsMouseEvent::eLeftButton;
3527 event.button = 1;
3528 break;
3530 // information lost:
3531 event.subwindow = None;
3532 event.same_screen = True;
3534 break;
3537 break;
3539 //XXX case NS_MOUSE_SCROLL_EVENT: not received.
3541 case NS_KEY_EVENT:
3542 if (anEvent.nativeMsg)
3544 XKeyEvent &event = pluginEvent.event.xkey;
3545 #ifdef MOZ_WIDGET_GTK2
3546 event.root = GDK_ROOT_WINDOW();
3547 event.time = anEvent.time;
3548 const GdkEventKey* gdkEvent =
3549 static_cast<const GdkEventKey*>(anEvent.nativeMsg);
3550 event.keycode = gdkEvent->hardware_keycode;
3551 event.state = gdkEvent->state;
3552 switch (anEvent.message)
3554 case NS_KEY_DOWN:
3555 event.type = XKeyPress;
3556 break;
3557 case NS_KEY_UP:
3558 event.type = KeyRelease;
3559 break;
3561 #endif
3562 // Information that could be obtained from nativeMsg but we may not
3563 // want to promise to provide:
3564 event.subwindow = None;
3565 event.x = 0;
3566 event.y = 0;
3567 event.x_root = -1;
3568 event.y_root = -1;
3569 event.same_screen = False;
3571 else
3573 // If we need to send synthesized key events, then
3574 // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
3575 // gdk_keymap_get_entries_for_keyval will be useful, but the
3576 // mappings will not be unique.
3577 NS_WARNING("Synthesized key event not sent to plugin");
3579 break;
3581 default:
3582 switch (anEvent.message)
3584 case NS_FOCUS_CONTENT:
3585 case NS_BLUR_CONTENT:
3587 XFocusChangeEvent &event = pluginEvent.event.xfocus;
3588 event.type =
3589 anEvent.message == NS_FOCUS_CONTENT ? FocusIn : FocusOut;
3590 // information lost:
3591 event.mode = -1;
3592 event.detail = NotifyDetailNone;
3594 break;
3598 if (!pluginEvent.event.type) {
3599 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
3600 ("Unhandled event message %d with struct type %d\n",
3601 anEvent.message, anEvent.eventStructType));
3602 return rv;
3605 // Fill in (useless) generic event information.
3606 XAnyEvent& event = pluginEvent.event.xany;
3607 event.display = widget ?
3608 static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nsnull;
3609 event.window = None; // not a real window
3610 // information lost:
3611 event.serial = 0;
3612 event.send_event = False;
3614 PRBool eventHandled = PR_FALSE;
3615 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3616 if (eventHandled)
3617 rv = nsEventStatus_eConsumeNoDefault;
3618 #endif
3620 return rv;
3623 nsresult
3624 nsPluginInstanceOwner::Destroy()
3626 // stop the timer explicitly to reduce reference count.
3627 CancelTimer();
3629 // unregister context menu listener
3630 if (mCXMenuListener) {
3631 mCXMenuListener->Destroy(mContent);
3632 mCXMenuListener = nsnull;
3635 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mContent));
3636 if (target) {
3638 nsCOMPtr<nsIDOMEventListener> listener;
3639 QueryInterface(NS_GET_IID(nsIDOMEventListener), getter_AddRefs(listener));
3641 // Unregister focus event listener
3642 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMFocusListener));
3644 // Unregister mouse event listener
3645 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseListener));
3647 // now for the mouse motion listener
3648 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseMotionListener));
3650 // Unregister key event listener;
3651 target->RemoveEventListener(NS_LITERAL_STRING("keypress"), listener, PR_TRUE);
3652 target->RemoveEventListener(NS_LITERAL_STRING("keydown"), listener, PR_TRUE);
3653 target->RemoveEventListener(NS_LITERAL_STRING("keyup"), listener, PR_TRUE);
3655 // Unregister drag event listener;
3656 target->RemoveEventListener(NS_LITERAL_STRING("dragdrop"), listener, PR_TRUE);
3657 target->RemoveEventListener(NS_LITERAL_STRING("dragover"), listener, PR_TRUE);
3658 target->RemoveEventListener(NS_LITERAL_STRING("dragexit"), listener, PR_TRUE);
3659 target->RemoveEventListener(NS_LITERAL_STRING("dragenter"), listener, PR_TRUE);
3660 target->RemoveEventListener(NS_LITERAL_STRING("draggesture"), listener, PR_TRUE);
3663 if (mDestroyWidget && mWidget) {
3664 mWidget->Destroy();
3667 return NS_OK;
3671 * Prepare to stop
3673 void
3674 nsPluginInstanceOwner::PrepareToStop(PRBool aDelayedStop)
3676 #ifdef XP_WIN
3677 if (aDelayedStop && mWidget) {
3678 // To delay stopping a plugin we need to reparent the plugin
3679 // so that we can safely tear down the
3680 // plugin after its frame (and view) is gone.
3682 // Also hide and disable the widget to avoid it from appearing in
3683 // odd places after reparenting it, but before it gets destroyed.
3684 mWidget->Show(PR_FALSE);
3685 mWidget->Enable(PR_FALSE);
3687 // Reparent the plugins native window. This relies on the widget
3688 // and plugin et al not holding any other references to its
3689 // parent.
3690 mWidget->SetParent(nsnull);
3692 mDestroyWidget = PR_TRUE;
3694 #endif
3696 // Unregister scroll position listener
3697 nsIFrame* parentWithView = mOwner->GetAncestorWithView();
3698 nsIView* curView = parentWithView ? parentWithView->GetView() : nsnull;
3699 while (curView) {
3700 nsIScrollableView* scrollingView = curView->ToScrollableView();
3701 if (scrollingView)
3702 scrollingView->RemoveScrollPositionListener((nsIScrollPositionListener *)this);
3704 curView = curView->GetParent();
3708 // Paints are handled differently, so we just simulate an update event.
3710 #ifdef XP_MACOSX
3711 void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect)
3713 if (!mInstance || !mOwner)
3714 return;
3716 #ifdef DO_DIRTY_INTERSECT // aDirtyRect isn't always correct, see bug 56128
3717 nsPoint rel(aDirtyRect.x, aDirtyRect.y);
3718 nsPoint abs(0,0);
3719 nsCOMPtr<nsIWidget> containerWidget;
3721 // Convert dirty rect relative coordinates to absolute and also get the containerWidget
3722 ConvertRelativeToWindowAbsolute(mOwner, rel, abs, *getter_AddRefs(containerWidget));
3724 nsRect absDirtyRect = nsRect(abs.x, abs.y, aDirtyRect.width, aDirtyRect.height);
3726 // Convert to absolute pixel values for the dirty rect
3727 nsIntRect absDirtyRectInPixels;
3728 ConvertAppUnitsToPixels(*mOwner->GetPresContext(), absDirtyRect,
3729 absDirtyRectInPixels);
3730 #endif
3732 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3733 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
3734 WindowRef window = FixUpPluginWindow(ePluginPaintEnable);
3735 if (window) {
3736 EventRecord updateEvent;
3737 InitializeEventRecord(&updateEvent);
3738 updateEvent.what = updateEvt;
3739 updateEvent.message = UInt32(window);
3741 nsPluginEvent pluginEvent = { &updateEvent, nsPluginPlatformWindowRef(window) };
3742 PRBool eventHandled = PR_FALSE;
3743 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3745 pluginWidget->EndDrawPlugin();
3748 #endif
3750 #ifdef XP_WIN
3751 void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect, HDC ndc)
3753 if (!mInstance || !mOwner)
3754 return;
3756 nsPluginWindow * window;
3757 GetWindow(window);
3758 nsRect relDirtyRect = nsRect(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
3759 nsIntRect relDirtyRectInPixels;
3760 ConvertAppUnitsToPixels(*mOwner->PresContext(), relDirtyRect,
3761 relDirtyRectInPixels);
3763 // we got dirty rectangle in relative window coordinates, but we
3764 // need it in absolute units and in the (left, top, right, bottom) form
3765 RECT drc;
3766 drc.left = relDirtyRectInPixels.x + window->x;
3767 drc.top = relDirtyRectInPixels.y + window->y;
3768 drc.right = drc.left + relDirtyRectInPixels.width;
3769 drc.bottom = drc.top + relDirtyRectInPixels.height;
3771 nsPluginEvent pluginEvent;
3772 pluginEvent.event = WM_PAINT;
3773 pluginEvent.wParam = (uint32)ndc;
3774 pluginEvent.lParam = (uint32)&drc;
3775 PRBool eventHandled = PR_FALSE;
3776 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3778 #endif
3780 #ifdef MOZ_X11
3781 void nsPluginInstanceOwner::Paint(nsIRenderingContext& aRenderingContext,
3782 const nsRect& aDirtyRect)
3784 if (!mInstance || !mOwner)
3785 return;
3787 nsPluginWindow* window;
3788 GetWindow(window);
3790 nsIntRect dirtyRectInPixels;
3791 ConvertAppUnitsToPixels(*mOwner->PresContext(), aDirtyRect,
3792 dirtyRectInPixels);
3793 // Sanitize the dirty rect so we don't tell plugins that the area outside
3794 // the plugin rectangle needs updating.
3795 nsIntRect pluginDirtyRect;
3796 if (!pluginDirtyRect.IntersectRect(nsIntRect(0, 0, window->width, window->height), dirtyRectInPixels))
3797 return;
3799 Renderer renderer(window, mInstance, pluginDirtyRect);
3800 PRUint32 rendererFlags =
3801 Renderer::DRAW_SUPPORTS_OFFSET |
3802 Renderer::DRAW_SUPPORTS_CLIP_RECT |
3803 Renderer::DRAW_SUPPORTS_NONDEFAULT_VISUAL |
3804 Renderer::DRAW_SUPPORTS_ALTERNATE_DISPLAY;
3806 PRBool transparent = PR_TRUE;
3807 mInstance->GetValue(nsPluginInstanceVariable_TransparentBool,
3808 (void *)&transparent);
3809 if (!transparent)
3810 rendererFlags |= Renderer::DRAW_IS_OPAQUE;
3812 gfxContext* ctx =
3813 static_cast<gfxContext*>
3814 (aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT));
3816 // The display used by gfxXlibNativeRenderer will be the one for the cairo
3817 // surface (provided that it is an Xlib surface) but the display argument
3818 // here needs to be non-NULL for cairo_draw_with_xlib ->
3819 // _create_temp_xlib_surface -> DefaultScreen(dpy).
3820 NPSetWindowCallbackStruct* ws_info =
3821 static_cast<NPSetWindowCallbackStruct*>(window->ws_info);
3822 renderer.Draw(ws_info->display, ctx, window->width, window->height,
3823 rendererFlags, nsnull);
3826 nsresult
3827 nsPluginInstanceOwner::Renderer::NativeDraw(Display* dpy, Drawable drawable,
3828 Visual* visual,
3829 short offsetX, short offsetY,
3830 XRectangle* clipRects,
3831 PRUint32 numClipRects)
3833 // See if the plugin must be notified of new window parameters.
3834 PRBool doupdatewindow = PR_FALSE;
3836 if (mWindow->x != offsetX || mWindow->y != offsetY) {
3837 mWindow->x = offsetX;
3838 mWindow->y = offsetY;
3839 doupdatewindow = PR_TRUE;
3842 NS_ASSERTION(numClipRects <= 1, "We don't support multiple clip rectangles!");
3843 nsPluginRect newClipRect;
3844 if (numClipRects) {
3845 newClipRect.left = clipRects[0].x;
3846 newClipRect.top = clipRects[0].y;
3847 newClipRect.right = clipRects[0].x + clipRects[0].width;
3848 newClipRect.bottom = clipRects[0].y + clipRects[0].height;
3850 else {
3851 // We should have been given a clip if an offset is -ve.
3852 NS_ASSERTION(offsetX >= 0 && offsetY >= 0,
3853 "Clip rectangle offsets are negative!");
3854 newClipRect.left = offsetX;
3855 newClipRect.top = offsetY;
3856 newClipRect.right = offsetX + mWindow->width;
3857 newClipRect.bottom = offsetY + mWindow->height;
3860 if (mWindow->clipRect.left != newClipRect.left ||
3861 mWindow->clipRect.top != newClipRect.top ||
3862 mWindow->clipRect.right != newClipRect.right ||
3863 mWindow->clipRect.bottom != newClipRect.bottom) {
3864 mWindow->clipRect = newClipRect;
3865 doupdatewindow = PR_TRUE;
3868 NPSetWindowCallbackStruct* ws_info =
3869 static_cast<NPSetWindowCallbackStruct*>(mWindow->ws_info);
3870 if ( ws_info->visual != visual) {
3871 // NPAPI needs a colormap but the surface doesn't provide a colormap. If
3872 // gfxContent::CurrentSurface is a gfxXlibSurface then the visual here
3873 // should be derived from that of the window and so the colormap of the
3874 // window should be fine. For other surfaces I don't know what to use.
3875 NS_ASSERTION(ws_info->visual == visual,
3876 "Visual changed: colormap may not match");
3877 ws_info->visual = visual;
3878 doupdatewindow = PR_TRUE;
3881 if (doupdatewindow)
3882 mInstance->SetWindow(mWindow);
3884 nsPluginEvent pluginEvent;
3885 XGraphicsExposeEvent& exposeEvent = pluginEvent.event.xgraphicsexpose;
3886 // set the drawing info
3887 exposeEvent.type = GraphicsExpose;
3888 exposeEvent.display = dpy;
3889 exposeEvent.drawable = drawable;
3890 exposeEvent.x = mDirtyRect.x + offsetX;
3891 exposeEvent.y = mDirtyRect.y + offsetY;
3892 exposeEvent.width = mDirtyRect.width;
3893 exposeEvent.height = mDirtyRect.height;
3894 exposeEvent.count = 0;
3895 // information not set:
3896 exposeEvent.serial = 0;
3897 exposeEvent.send_event = False;
3898 exposeEvent.major_code = 0;
3899 exposeEvent.minor_code = 0;
3901 PRBool eventHandled = PR_FALSE;
3902 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3904 return NS_OK;
3906 #endif
3908 // Here's how we give idle time to plugins.
3910 NS_IMETHODIMP nsPluginInstanceOwner::Notify(nsITimer* /* timer */)
3912 #ifdef XP_MACOSX
3913 // validate the plugin clipping information by syncing the plugin window info to
3914 // reflect the current widget location. This makes sure that everything is updated
3915 // correctly in the event of scrolling in the window.
3916 if (mInstance) {
3917 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3918 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
3919 WindowRef window = FixUpPluginWindow(ePluginPaintIgnore);
3920 if (window) {
3921 EventRecord idleEvent;
3922 InitializeEventRecord(&idleEvent);
3923 idleEvent.what = nullEvent;
3925 // give a bogus 'where' field of our null event when hidden, so Flash
3926 // won't respond to mouse moves in other tabs, see bug 120875
3927 if (!mWidgetVisible)
3928 idleEvent.where.h = idleEvent.where.v = 20000;
3930 nsPluginEvent pluginEvent = { &idleEvent, nsPluginPlatformWindowRef(window) };
3932 PRBool eventHandled = PR_FALSE;
3933 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3936 pluginWidget->EndDrawPlugin();
3939 #endif
3940 return NS_OK;
3943 void nsPluginInstanceOwner::StartTimer(unsigned int aDelay)
3945 #ifdef XP_MACOSX
3946 nsresult rv;
3948 // start a periodic timer to provide null events to the plugin instance.
3949 if (!mPluginTimer) {
3950 mPluginTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
3951 if (NS_SUCCEEDED(rv))
3952 mPluginTimer->InitWithCallback(this, aDelay, nsITimer::TYPE_REPEATING_SLACK);
3954 #endif
3957 void nsPluginInstanceOwner::CancelTimer()
3959 if (mPluginTimer) {
3960 mPluginTimer->Cancel();
3961 mPluginTimer = nsnull;
3965 nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext,
3966 nsObjectFrame* aFrame,
3967 nsIContent* aContent)
3969 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
3970 ("nsPluginInstanceOwner::Init() called on %p for frame %p\n", this,
3971 aFrame));
3973 mOwner = aFrame;
3974 mContent = aContent;
3976 nsWeakFrame weakFrame(aFrame);
3978 // Some plugins require a specific sequence of shutdown and startup when
3979 // a page is reloaded. Shutdown happens usually when the last instance
3980 // is destroyed. Here we make sure the plugin instance in the old
3981 // document is destroyed before we try to create the new one.
3982 aPresContext->EnsureVisible(PR_TRUE);
3984 if (!weakFrame.IsAlive()) {
3985 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
3986 ("nsPluginInstanceOwner::Init's EnsureVisible() call destroyed "
3987 "instance owner %p\n", this));
3989 return NS_ERROR_NOT_AVAILABLE;
3992 // register context menu listener
3993 mCXMenuListener = new nsPluginDOMContextMenuListener();
3994 if (mCXMenuListener) {
3995 mCXMenuListener->Init(aContent);
3998 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mContent));
3999 if (target) {
4001 nsCOMPtr<nsIDOMEventListener> listener;
4002 QueryInterface(NS_GET_IID(nsIDOMEventListener), getter_AddRefs(listener));
4004 // Register focus listener
4005 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMFocusListener));
4007 // Register mouse listener
4008 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseListener));
4010 // now do the mouse motion listener
4011 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseMotionListener));
4013 // Register key listener
4014 target->AddEventListener(NS_LITERAL_STRING("keypress"), listener, PR_TRUE);
4015 target->AddEventListener(NS_LITERAL_STRING("keydown"), listener, PR_TRUE);
4016 target->AddEventListener(NS_LITERAL_STRING("keyup"), listener, PR_TRUE);
4018 // Register drag listener
4019 target->AddEventListener(NS_LITERAL_STRING("dragdrop"), listener, PR_TRUE);
4020 target->AddEventListener(NS_LITERAL_STRING("dragover"), listener, PR_TRUE);
4021 target->AddEventListener(NS_LITERAL_STRING("dragexit"), listener, PR_TRUE);
4022 target->AddEventListener(NS_LITERAL_STRING("dragenter"), listener, PR_TRUE);
4023 target->AddEventListener(NS_LITERAL_STRING("draggesture"), listener, PR_TRUE);
4026 // Register scroll position listener
4027 // We need to register a scroll pos listener on every scrollable
4028 // view up to the top
4029 nsIFrame* parentWithView = mOwner->GetAncestorWithView();
4030 nsIView* curView = parentWithView ? parentWithView->GetView() : nsnull;
4031 while (curView) {
4032 nsIScrollableView* scrollingView = curView->ToScrollableView();
4033 if (scrollingView)
4034 scrollingView->AddScrollPositionListener((nsIScrollPositionListener *)this);
4036 curView = curView->GetParent();
4039 return NS_OK;
4042 nsPluginPort* nsPluginInstanceOwner::GetPluginPort()
4044 //!!! Port must be released for windowless plugins on Windows, because it is HDC !!!
4046 nsPluginPort* result = NULL;
4047 if (mWidget) {
4048 #ifdef XP_WIN
4049 if (mPluginWindow && mPluginWindow->type == nsPluginWindowType_Drawable)
4050 result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_GRAPHIC);
4051 else
4052 #endif
4053 #ifdef XP_MACOSX
4054 if (GetDrawingModel() == NPDrawingModelCoreGraphics)
4055 result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT_CG);
4056 else
4057 #endif
4058 result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
4060 return result;
4063 void nsPluginInstanceOwner::ReleasePluginPort(nsPluginPort * pluginPort)
4065 #ifdef XP_WIN
4066 if (mWidget && mPluginWindow &&
4067 mPluginWindow->type == nsPluginWindowType_Drawable) {
4068 mWidget->FreeNativeData((HDC)pluginPort, NS_NATIVE_GRAPHIC);
4070 #endif
4073 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
4075 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
4077 nsIView *view;
4078 nsresult rv = NS_ERROR_FAILURE;
4080 if (mOwner) {
4081 // Create view if necessary
4083 view = mOwner->GetView();
4085 if (!view || !mWidget) {
4086 PRBool windowless = PR_FALSE;
4088 mInstance->GetValue(nsPluginInstanceVariable_WindowlessBool,
4089 (void *)&windowless);
4091 // always create widgets in Twips, not pixels
4092 nsPresContext* context = mOwner->PresContext();
4093 rv = mOwner->CreateWidget(context->DevPixelsToAppUnits(mPluginWindow->width),
4094 context->DevPixelsToAppUnits(mPluginWindow->height),
4095 windowless);
4096 if (NS_OK == rv) {
4097 view = mOwner->GetView();
4099 if (view) {
4100 mWidget = view->GetWidget();
4103 if (PR_TRUE == windowless) {
4104 mPluginWindow->type = nsPluginWindowType_Drawable;
4106 // this needs to be a HDC according to the spec, but I do
4107 // not see the right way to release it so let's postpone
4108 // passing HDC till paint event when it is really
4109 // needed. Change spec?
4110 mPluginWindow->window = nsnull;
4111 } else if (mWidget) {
4112 mWidget->Resize(mPluginWindow->width, mPluginWindow->height,
4113 PR_FALSE);
4115 // mPluginWindow->type is used in |GetPluginPort| so it must
4116 // be initilized first
4117 mPluginWindow->type = nsPluginWindowType_Window;
4118 mPluginWindow->window = GetPluginPort();
4120 // start the idle timer.
4121 StartTimer(NORMAL_PLUGIN_DELAY);
4123 // tell the plugin window about the widget
4124 mPluginWindow->SetPluginWidget(mWidget);
4130 return rv;
4133 void nsPluginInstanceOwner::SetPluginHost(nsIPluginHost* aHost)
4135 mPluginHost = aHost;
4138 #if defined(XP_WIN) || (defined(DO_DIRTY_INTERSECT) && defined(XP_MACOSX)) || defined(MOZ_X11)
4139 // convert frame coordinates from twips to pixels
4140 static void ConvertAppUnitsToPixels(const nsPresContext& aPresContext, const nsRect& aTwipsRect, nsIntRect& aPixelRect)
4142 aPixelRect.x = aPresContext.AppUnitsToDevPixels(aTwipsRect.x);
4143 aPixelRect.y = aPresContext.AppUnitsToDevPixels(aTwipsRect.y);
4144 aPixelRect.width = aPresContext.AppUnitsToDevPixels(aTwipsRect.width);
4145 aPixelRect.height = aPresContext.AppUnitsToDevPixels(aTwipsRect.height);
4147 #endif
4149 // Mac specific code to fix up the port location and clipping region
4150 #ifdef XP_MACOSX
4152 #ifdef DO_DIRTY_INTERSECT
4153 // Convert from a frame relative coordinate to a coordinate relative to its
4154 // containing window
4155 static void ConvertRelativeToWindowAbsolute(nsIFrame* aFrame,
4156 nsPoint& aRel,
4157 nsPoint& aAbs,
4158 nsIWidget*& aContainerWidget)
4160 // See if this frame has a view
4161 nsIView *view = aFrame->GetView();
4162 if (!view) {
4163 aAbs.x = 0;
4164 aAbs.y = 0;
4165 // Calculate frames offset from its nearest view
4166 aFrame->GetOffsetFromView(aAbs, &view);
4167 } else {
4168 // Store frames offset from its view.
4169 aAbs = aFrame->GetPosition();
4172 NS_ASSERTION(view, "the object frame does not have a view");
4173 if (view) {
4174 // Calculate the view's offset from its nearest widget
4175 nsPoint viewOffset;
4176 aContainerWidget = view->GetNearestWidget(&viewOffset);
4177 NS_IF_ADDREF(aContainerWidget);
4178 aAbs += viewOffset;
4181 // Add relative coordinate to the absolute coordinate that has been calculated
4182 aAbs += aRel;
4184 #endif // DO_DIRTY_INTERSECT
4186 WindowRef nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState)
4188 if (!mWidget || !mPluginWindow || !mInstance)
4189 return nsnull;
4191 nsPluginPort* pluginPort = GetPluginPort();
4193 if (!pluginPort)
4194 return nsnull;
4196 NPDrawingModel drawingModel = GetDrawingModel();
4198 // first, check our view for CSS visibility style
4199 PRBool isVisible =
4200 mOwner->GetView()->GetVisibility() == nsViewVisibility_kShow;
4202 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
4204 nsPoint pluginOrigin;
4205 nsRect widgetClip;
4206 PRBool widgetVisible;
4207 pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin, /* out */ widgetVisible);
4209 // printf("GetPluginClipRect returning visible %d\n", widgetVisible);
4211 isVisible &= widgetVisible;
4212 if (!isVisible)
4213 widgetClip.Empty();
4215 #ifndef NP_NO_QUICKDRAW
4216 // set the port coordinates
4217 if (drawingModel == NPDrawingModelQuickDraw) {
4218 mPluginWindow->x = -pluginPort->qdPort.portx;
4219 mPluginWindow->y = -pluginPort->qdPort.porty;
4221 else if (drawingModel == NPDrawingModelCoreGraphics)
4222 #endif
4224 // This would be a lot easier if we could use obj-c here,
4225 // but we can't. Since we have only nsIWidget and we can't
4226 // use its native widget (an obj-c object) we have to go
4227 // from the widget's screen coordinates to its window coords
4228 // instead of straight to window coords.
4229 nsRect geckoBounds;
4230 mWidget->GetBounds(geckoBounds);
4231 // we need a rect that is the entire *internal* rect, so the
4232 // x and y coords are 0, width is the same.
4233 geckoBounds.x = 0;
4234 geckoBounds.y = 0;
4235 nsRect geckoScreenCoords;
4236 mWidget->WidgetToScreen(geckoBounds, geckoScreenCoords);
4238 Rect windowRect;
4239 WindowRef window = (WindowRef)pluginPort->cgPort.window;
4240 ::GetWindowBounds(window, kWindowStructureRgn, &windowRect);
4242 mPluginWindow->x = geckoScreenCoords.x - windowRect.left;
4243 mPluginWindow->y = geckoScreenCoords.y - windowRect.top;
4246 nsPluginRect oldClipRect = mPluginWindow->clipRect;
4248 // fix up the clipping region
4249 mPluginWindow->clipRect.top = widgetClip.y;
4250 mPluginWindow->clipRect.left = widgetClip.x;
4252 mWidgetVisible = isVisible;
4254 if (!mWidgetVisible || inPaintState == ePluginPaintDisable) {
4255 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
4256 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
4257 // pluginPort = nsnull; // don't uncomment this
4259 else if (inPaintState == ePluginPaintEnable)
4261 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height;
4262 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left + widgetClip.width;
4265 // if the clip rect changed, call SetWindow()
4266 // (RealPlayer needs this to draw correctly)
4267 if (mPluginWindow->clipRect.left != oldClipRect.left ||
4268 mPluginWindow->clipRect.top != oldClipRect.top ||
4269 mPluginWindow->clipRect.right != oldClipRect.right ||
4270 mPluginWindow->clipRect.bottom != oldClipRect.bottom)
4272 mInstance->SetWindow(mPluginWindow);
4273 // if the clipRect is of size 0, make the null timer fire less often
4274 CancelTimer();
4275 if (mPluginWindow->clipRect.left == mPluginWindow->clipRect.right ||
4276 mPluginWindow->clipRect.top == mPluginWindow->clipRect.bottom) {
4277 StartTimer(HIDDEN_PLUGIN_DELAY);
4279 else {
4280 StartTimer(NORMAL_PLUGIN_DELAY);
4284 #ifndef NP_NO_QUICKDRAW
4285 if (drawingModel == NPDrawingModelQuickDraw)
4286 return ::GetWindowFromPort(pluginPort->qdPort.port);
4287 #endif
4289 if (drawingModel == NPDrawingModelCoreGraphics)
4290 return pluginPort->cgPort.window;
4292 return nsnull;
4295 #endif // XP_MACOSX
4297 // Little helper function to resolve relative URL in
4298 // |value| for certain inputs of |name|
4299 void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
4301 if (name.LowerCaseEqualsLiteral("pluginurl") ||
4302 name.LowerCaseEqualsLiteral("pluginspage")) {
4304 nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
4305 nsAutoString newURL;
4306 NS_MakeAbsoluteURI(newURL, value, baseURI);
4307 if (!newURL.IsEmpty())
4308 value = newURL;