backing out bug 347743 due to major crasher in 386332
[mozilla-central.git] / layout / generic / nsObjectFrame.cpp
blob3990bbaab1c1d83f02713f4971dceea57c778c60
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 #ifdef MOZ_CAIRO_GFX
126 #include "gfxContext.h"
127 #endif
129 // accessibility support
130 #ifdef ACCESSIBILITY
131 #include "nsIAccessibilityService.h"
132 #endif
134 #ifdef MOZ_LOGGING
135 #define FORCE_PR_LOG 1 /* Allow logging in the release build */
136 #endif /* MOZ_LOGGING */
137 #include "prlog.h"
139 #include <errno.h>
141 #include "nsContentCID.h"
142 static NS_DEFINE_CID(kRangeCID, NS_RANGE_CID);
144 /* X headers suck */
145 #ifdef KeyPress
146 #undef KeyPress
147 #endif
149 #ifdef XP_WIN
150 #include <wtypes.h>
151 #include <winuser.h>
152 #endif
154 #ifdef CreateEvent // Thank you MS.
155 #undef CreateEvent
156 #endif
158 #ifdef PR_LOGGING
159 static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame");
160 #endif /* PR_LOGGING */
162 // 1020 / 60
163 #define NORMAL_PLUGIN_DELAY 17
165 // low enough to avoid audio skipping/delays
166 #define HIDDEN_PLUGIN_DELAY 100
168 // special class for handeling DOM context menu events because for
169 // some reason it starves other mouse events if implemented on the
170 // same class
171 class nsPluginDOMContextMenuListener : public nsIDOMContextMenuListener,
172 public nsIEventListener
174 public:
175 nsPluginDOMContextMenuListener();
176 virtual ~nsPluginDOMContextMenuListener();
178 NS_DECL_ISUPPORTS
180 NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent);
182 nsresult Init(nsIContent* aContent);
183 nsresult Destroy(nsIContent* aContent);
185 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent)
187 return NS_OK;
189 nsEventStatus ProcessEvent(const nsGUIEvent& anEvent)
191 return nsEventStatus_eConsumeNoDefault;
196 class nsPluginInstanceOwner : public nsIPluginInstanceOwner,
197 public nsIPluginTagInfo2,
198 #ifdef OJI
199 public nsIJVMPluginTagInfo,
200 #endif
201 public nsIEventListener,
202 public nsITimerCallback,
203 public nsIDOMMouseListener,
204 public nsIDOMMouseMotionListener,
205 public nsIDOMKeyListener,
206 public nsIDOMFocusListener,
207 public nsIScrollPositionListener,
208 public nsIDOMDragListener
211 public:
212 nsPluginInstanceOwner();
213 virtual ~nsPluginInstanceOwner();
215 NS_DECL_ISUPPORTS
217 //nsIPluginInstanceOwner interface
219 NS_IMETHOD SetInstance(nsIPluginInstance *aInstance);
221 NS_IMETHOD GetInstance(nsIPluginInstance *&aInstance);
223 NS_IMETHOD GetWindow(nsPluginWindow *&aWindow);
225 NS_IMETHOD GetMode(nsPluginMode *aMode);
227 NS_IMETHOD CreateWidget(void);
229 NS_IMETHOD GetURL(const char *aURL, const char *aTarget, void *aPostData,
230 PRUint32 aPostDataLen, void *aHeadersData,
231 PRUint32 aHeadersDataLen, PRBool isFile = PR_FALSE);
233 NS_IMETHOD ShowStatus(const char *aStatusMsg);
235 NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
237 NS_IMETHOD GetDocument(nsIDocument* *aDocument);
239 NS_IMETHOD InvalidateRect(nsPluginRect *invalidRect);
241 NS_IMETHOD InvalidateRegion(nsPluginRegion invalidRegion);
243 NS_IMETHOD ForceRedraw();
245 NS_IMETHOD GetValue(nsPluginInstancePeerVariable variable, void *value);
247 //nsIPluginTagInfo interface
249 NS_IMETHOD GetAttributes(PRUint16& n, const char*const*& names,
250 const char*const*& values);
252 NS_IMETHOD GetAttribute(const char* name, const char* *result);
254 //nsIPluginTagInfo2 interface
256 NS_IMETHOD GetTagType(nsPluginTagType *result);
258 NS_IMETHOD GetTagText(const char* *result);
260 NS_IMETHOD GetParameters(PRUint16& n, const char*const*& names, const char*const*& values);
262 NS_IMETHOD GetParameter(const char* name, const char* *result);
264 NS_IMETHOD GetDocumentBase(const char* *result);
266 NS_IMETHOD GetDocumentEncoding(const char* *result);
268 NS_IMETHOD GetAlignment(const char* *result);
270 NS_IMETHOD GetWidth(PRUint32 *result);
272 NS_IMETHOD GetHeight(PRUint32 *result);
274 NS_IMETHOD GetBorderVertSpace(PRUint32 *result);
276 NS_IMETHOD GetBorderHorizSpace(PRUint32 *result);
278 NS_IMETHOD GetUniqueID(PRUint32 *result);
280 NS_IMETHOD GetDOMElement(nsIDOMElement* *result);
282 #ifdef OJI
283 //nsIJVMPluginTagInfo interface
285 NS_IMETHOD GetCode(const char* *result);
287 NS_IMETHOD GetCodeBase(const char* *result);
289 NS_IMETHOD GetArchive(const char* *result);
291 NS_IMETHOD GetName(const char* *result);
293 NS_IMETHOD GetMayScript(PRBool *result);
295 #endif /* OJI */
297 /** nsIDOMMouseListener interfaces
298 * @see nsIDOMMouseListener
300 NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
301 NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
302 NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
303 NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
304 NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
305 NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
306 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
307 /* END interfaces from nsIDOMMouseListener*/
309 // nsIDOMMouseListener intefaces
310 NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent);
311 NS_IMETHOD DragMove(nsIDOMEvent* aMouseEvent) { return NS_OK; }
313 // nsIDOMKeyListener interfaces
314 NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
315 NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
316 NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
317 // end nsIDOMKeyListener interfaces
319 // nsIDOMFocuListener interfaces
320 NS_IMETHOD Focus(nsIDOMEvent * aFocusEvent);
321 NS_IMETHOD Blur(nsIDOMEvent * aFocusEvent);
323 // nsIDOMDragListener interfaces
324 NS_IMETHOD DragEnter(nsIDOMEvent* aMouseEvent);
325 NS_IMETHOD DragOver(nsIDOMEvent* aMouseEvent);
326 NS_IMETHOD DragExit(nsIDOMEvent* aMouseEvent);
327 NS_IMETHOD DragDrop(nsIDOMEvent* aMouseEvent);
328 NS_IMETHOD DragGesture(nsIDOMEvent* aMouseEvent);
329 NS_IMETHOD Drag(nsIDOMEvent* aMouseEvent);
330 NS_IMETHOD DragEnd(nsIDOMEvent* aMouseEvent);
333 nsresult Destroy();
335 //nsIEventListener interface
336 nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
338 void Paint(const nsRect& aDirtyRect, PRUint32 ndc = 0);
340 // nsITimerCallback interface
341 NS_DECL_NSITIMERCALLBACK
343 void CancelTimer();
344 void StartTimer(unsigned int aDelay);
346 // nsIScrollPositionListener interface
347 NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
348 NS_IMETHOD ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
350 //locals
352 nsresult Init(nsPresContext* aPresContext, nsObjectFrame* aFrame,
353 nsIContent* aContent);
355 nsPluginPort* GetPluginPort();
356 void ReleasePluginPort(nsPluginPort * pluginPort);
358 void SetPluginHost(nsIPluginHost* aHost);
360 #ifdef XP_MACOSX
361 NPDrawingModel GetDrawingModel();
362 WindowRef FixUpPluginWindow(PRInt32 inPaintState);
363 void GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord* origEvent, EventRecord& aMacEvent);
364 #endif
366 private:
367 void FixUpURLS(const nsString &name, nsAString &value);
369 nsPluginNativeWindow *mPluginWindow;
370 nsCOMPtr<nsIPluginInstance> mInstance;
371 nsObjectFrame *mOwner;
372 nsCOMPtr<nsIContent> mContent;
373 nsCString mDocumentBase;
374 char *mTagText;
375 nsCOMPtr<nsIWidget> mWidget;
376 nsCOMPtr<nsITimer> mPluginTimer;
377 nsCOMPtr<nsIPluginHost> mPluginHost;
378 PRPackedBool mContentFocused;
379 PRPackedBool mWidgetVisible; // used on Mac to store our widget's visible state
380 PRUint16 mNumCachedAttrs;
381 PRUint16 mNumCachedParams;
382 char **mCachedAttrParamNames;
383 char **mCachedAttrParamValues;
385 nsPluginDOMContextMenuListener * mCXMenuListener; // pointer to wrapper for nsIDOMContextMenuListener
387 nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
388 nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent);
389 nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
391 nsresult EnsureCachedAttrParamArrays();
394 #if defined(XP_WIN) || (defined(DO_DIRTY_INTERSECT) && defined(XP_MACOSX))
395 static void ConvertAppUnitsToPixels(nsPresContext& aPresContext, nsRect& aTwipsRect, nsRect& aPixelRect);
396 #endif
398 // Mac specific code to fix up port position and clip during paint
399 #ifdef XP_MACOSX
401 #ifdef DO_DIRTY_INTERSECT
402 // convert relative coordinates to absolute
403 static void ConvertRelativeToWindowAbsolute(nsIFrame* aFrame, nsPoint& aRel, nsPoint& aAbs, nsIWidget *&aContainerWidget);
404 #endif
406 enum { ePluginPaintIgnore, ePluginPaintEnable, ePluginPaintDisable };
408 #endif // XP_MACOSX
410 nsObjectFrame::~nsObjectFrame()
414 NS_IMETHODIMP
415 nsObjectFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
417 NS_ENSURE_ARG_POINTER(aInstancePtr);
418 *aInstancePtr = nsnull;
420 #ifdef DEBUG
421 if (aIID.Equals(NS_GET_IID(nsIFrameDebug))) {
422 *aInstancePtr = NS_STATIC_CAST(nsIFrameDebug*,this);
423 return NS_OK;
425 #endif
427 if (aIID.Equals(NS_GET_IID(nsIObjectFrame))) {
428 *aInstancePtr = NS_STATIC_CAST(nsIObjectFrame*,this);
429 return NS_OK;
430 } else if (aIID.Equals(NS_GET_IID(nsIFrame))) {
431 *aInstancePtr = NS_STATIC_CAST(nsIFrame*,this);
432 return NS_OK;
433 } else if (aIID.Equals(NS_GET_IID(nsISupports))) {
434 *aInstancePtr = NS_STATIC_CAST(nsIObjectFrame*,this);
435 return NS_OK;
437 return NS_NOINTERFACE;
440 NS_IMETHODIMP_(nsrefcnt) nsObjectFrame::AddRef(void)
442 NS_WARNING("not supported for frames");
443 return 1;
446 NS_IMETHODIMP_(nsrefcnt) nsObjectFrame::Release(void)
448 NS_WARNING("not supported for frames");
449 return 1;
452 #ifdef ACCESSIBILITY
453 NS_IMETHODIMP nsObjectFrame::GetAccessible(nsIAccessible** aAccessible)
455 nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
457 if (accService) {
458 return accService->CreateHTMLObjectFrameAccessible(this, aAccessible);
461 return NS_ERROR_FAILURE;
464 #ifdef XP_WIN
465 NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
467 *aPort = (HWND) mInstanceOwner->GetPluginPort();
468 return NS_OK;
470 #endif
471 #endif
474 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
475 static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
477 // #define DO_DIRTY_INTERSECT 1 // enable dirty rect intersection during paint
479 NS_IMETHODIMP
480 nsObjectFrame::Init(nsIContent* aContent,
481 nsIFrame* aParent,
482 nsIFrame* aPrevInFlow)
484 #ifdef DEBUG
485 mInstantiating = PR_FALSE;
486 #endif
488 nsresult rv = nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow);
489 nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
490 NS_ASSERTION(objContent, "Why not an object loading content?");
491 objContent->HasNewFrame(this);
492 return rv;
495 void
496 nsObjectFrame::Destroy()
498 NS_ASSERTION(!mInstantiating, "about to crash due to bug 136927");
500 // we need to finish with the plugin before native window is destroyed
501 // doing this in the destructor is too late.
502 StopPlugin();
504 nsObjectFrameSuper::Destroy();
507 nsIAtom*
508 nsObjectFrame::GetType() const
510 return nsGkAtoms::objectFrame;
513 #ifdef DEBUG
514 NS_IMETHODIMP
515 nsObjectFrame::GetFrameName(nsAString& aResult) const
517 return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
519 #endif
521 nsresult
522 nsObjectFrame::CreateWidgetForView(nsIView* aView)
524 // Bug 179822: Create widget and allow non-unicode SubClass
525 nsWidgetInitData initData;
526 initData.mUnicode = PR_FALSE;
527 return aView->CreateWidget(kWidgetCID, &initData);
530 nsresult
531 nsObjectFrame::CreateWidget(nscoord aWidth,
532 nscoord aHeight,
533 PRBool aViewOnly)
535 nsIView* view = GetView();
536 NS_ASSERTION(view, "Object frames must have views");
537 if (!view) {
538 return NS_OK; //XXX why OK? MMP
541 nsIViewManager* viewMan = view->GetViewManager();
542 // mark the view as hidden since we don't know the (x,y) until Paint
543 // XXX is the above comment correct?
544 viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
546 //this is ugly. it was ripped off from didreflow(). MMP
547 // Position and size view relative to its parent, not relative to our
548 // parent frame (our parent frame may not have a view).
550 nsIView* parentWithView;
551 nsPoint origin;
552 nsRect r(0, 0, mRect.width, mRect.height);
554 GetOffsetFromView(origin, &parentWithView);
555 viewMan->ResizeView(view, r);
556 viewMan->MoveViewTo(view, origin.x, origin.y);
558 if (!aViewOnly && !view->HasWidget()) {
559 nsresult rv = CreateWidgetForView(view);
560 if (NS_FAILED(rv)) {
561 return NS_OK; //XXX why OK? MMP
566 // Here we set the background color for this widget because some plugins will use
567 // the child window background color when painting. If it's not set, it may default to gray
568 // Sometimes, a frame doesn't have a background color or is transparent. In this
569 // case, walk up the frame tree until we do find a frame with a background color
570 for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
571 const nsStyleBackground* background = frame->GetStyleBackground();
572 if (!background->IsTransparent()) { // make sure we got an actual color
573 nsIWidget* win = view->GetWidget();
574 if (win)
575 win->SetBackgroundColor(background->mBackgroundColor);
576 break;
582 viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
584 return NS_OK;
587 #define EMBED_DEF_WIDTH 240
588 #define EMBED_DEF_HEIGHT 200
590 /* virtual */ nscoord
591 nsObjectFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
593 nscoord result = 0;
595 if (!IsHidden(PR_FALSE)) {
596 nsIAtom *atom = mContent->Tag();
597 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
598 result = nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH);
602 DISPLAY_MIN_WIDTH(this, result);
603 return result;
606 /* virtual */ nscoord
607 nsObjectFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
609 return nsObjectFrame::GetMinWidth(aRenderingContext);
612 void
613 nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext,
614 const nsHTMLReflowState& aReflowState,
615 nsHTMLReflowMetrics& aMetrics)
617 // By default, we have no area
618 aMetrics.width = 0;
619 aMetrics.height = 0;
621 if (IsHidden(PR_FALSE)) {
622 return;
625 aMetrics.width = aReflowState.ComputedWidth();
626 aMetrics.height = aReflowState.mComputedHeight;
628 // for EMBED and APPLET, default to 240x200 for compatibility
629 nsIAtom *atom = mContent->Tag();
630 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
631 if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
632 aMetrics.width = PR_MIN(PR_MAX(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH),
633 aReflowState.mComputedMinWidth),
634 aReflowState.mComputedMaxWidth);
636 if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
637 aMetrics.height = PR_MIN(PR_MAX(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT),
638 aReflowState.mComputedMinHeight),
639 aReflowState.mComputedMaxHeight);
642 #if defined (MOZ_WIDGET_GTK2)
643 // We need to make sure that the size of the object frame does not
644 // exceed the maximum size of X coordinates. See bug #225357 for
645 // more information. In theory Gtk2 can handle large coordinates,
646 // but underlying plugins can't.
647 aMetrics.height = PR_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.height);
648 aMetrics.width = PR_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.width);
649 #endif
652 // At this point, the width has an unconstrained value only if we have
653 // nothing to go on (no width set, no information from the plugin, nothing).
654 // Make up a number.
655 if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
656 aMetrics.width =
657 (aReflowState.mComputedMinWidth != NS_UNCONSTRAINEDSIZE) ?
658 aReflowState.mComputedMinWidth : 0;
661 // At this point, the height has an unconstrained value only in two cases:
662 // a) We are in standards mode with percent heights and parent is auto-height
663 // b) We have no height information at all.
664 // In either case, we have to make up a number.
665 if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
666 aMetrics.height =
667 (aReflowState.mComputedMinHeight != NS_UNCONSTRAINEDSIZE) ?
668 aReflowState.mComputedMinHeight : 0;
671 // XXXbz don't add in the border and padding, because we screw up our
672 // plugin's size and positioning if we do... Eventually we _do_ want to
673 // paint borders, though! At that point, we will need to adjust the desired
674 // size either here or in Reflow.... Further, we will need to fix Paint() to
675 // call the superclass in all cases.
678 NS_IMETHODIMP
679 nsObjectFrame::Reflow(nsPresContext* aPresContext,
680 nsHTMLReflowMetrics& aMetrics,
681 const nsHTMLReflowState& aReflowState,
682 nsReflowStatus& aStatus)
684 DO_GLOBAL_REFLOW_COUNT("nsObjectFrame");
685 DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
687 // Get our desired size
688 GetDesiredSize(aPresContext, aReflowState, aMetrics);
690 // delay plugin instantiation until all children have
691 // arrived. Otherwise there may be PARAMs or other stuff that the
692 // plugin needs to see that haven't arrived yet.
693 if (!GetContent()->IsDoneAddingChildren()) {
694 aStatus = NS_FRAME_COMPLETE;
695 return NS_OK;
698 // if we are printing or print previewing, bail for now
699 if (aPresContext->Medium() == nsGkAtoms::print) {
700 aStatus = NS_FRAME_COMPLETE;
701 return NS_OK;
705 FixupWindow(nsSize(aMetrics.width, aMetrics.height));
707 aStatus = NS_FRAME_COMPLETE;
709 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
710 return NS_OK;
713 nsresult
714 nsObjectFrame::InstantiatePlugin(nsIPluginHost* aPluginHost,
715 const char* aMimeType,
716 nsIURI* aURI)
718 // If you add early return(s), be sure to balance this call to
719 // appShell->SuspendNative() with additional call(s) to
720 // appShell->ReturnNative().
721 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
722 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
723 if (appShell) {
724 appShell->SuspendNative();
727 #ifdef DEBUG
728 mInstantiating = PR_TRUE;
729 #endif
731 NS_ASSERTION(mContent, "We should have a content node.");
733 nsIDocument* doc = mContent->GetOwnerDoc();
734 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
736 nsresult rv;
737 if (pDoc) { /* full-page mode */
738 nsCOMPtr<nsIStreamListener> stream;
739 rv = aPluginHost->InstantiateFullPagePlugin(aMimeType, aURI,
740 /* resulting stream listener */ *getter_AddRefs(stream),
741 mInstanceOwner);
742 if (NS_SUCCEEDED(rv))
743 pDoc->SetStreamListener(stream);
744 } else { /* embedded mode */
745 rv = aPluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI,
746 mInstanceOwner);
748 #ifdef DEBUG
749 mInstantiating = PR_FALSE;
750 #endif
752 if (appShell) {
753 appShell->ResumeNative();
756 // XXX having to do this sucks. it'd be better to move the code from DidReflow
757 // to FixupWindow or something.
758 PresContext()->GetPresShell()->
759 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
760 return rv;
763 void
764 nsObjectFrame::FixupWindow(const nsSize& aSize)
766 nsPresContext* presContext = PresContext();
768 if (!mInstanceOwner)
769 return;
771 nsPluginWindow *window;
772 mInstanceOwner->GetWindow(window);
774 NS_ENSURE_TRUE(window, /**/);
776 nsPoint origin;
777 nsIView *parentWithView;
778 GetOffsetFromView(origin, &parentWithView);
779 window->x = presContext->AppUnitsToDevPixels(origin.x);
780 window->y = presContext->AppUnitsToDevPixels(origin.y);
781 window->width = presContext->AppUnitsToDevPixels(aSize.width);
782 window->height = presContext->AppUnitsToDevPixels(aSize.height);
784 // on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep
785 // us from drawing on screen until the widget is properly positioned, which will not
786 // happen until we have finished the reflow process.
787 window->clipRect.top = 0;
788 window->clipRect.left = 0;
789 #ifdef XP_MACOSX
790 window->clipRect.bottom = 0;
791 window->clipRect.right = 0;
792 #else
793 window->clipRect.bottom = presContext->AppUnitsToDevPixels(aSize.height);
794 window->clipRect.right = presContext->AppUnitsToDevPixels(aSize.width);
795 #endif
798 PRBool
799 nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
801 if (aTabIndex)
802 *aTabIndex = -1;
803 return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
806 PRBool
807 nsObjectFrame::IsHidden(PRBool aCheckVisibilityStyle) const
809 if (aCheckVisibilityStyle) {
810 if (!GetStyleVisibility()->IsVisibleOrCollapsed())
811 return PR_TRUE;
814 // only <embed> tags support the HIDDEN attribute
815 if (mContent->Tag() == nsGkAtoms::embed) {
816 // Yes, these are really the kooky ways that you could tell 4.x
817 // not to hide the <embed> once you'd put the 'hidden' attribute
818 // on the tag...
820 // HIDDEN w/ no attributes gets translated as we are hidden for
821 // compatibility w/ 4.x and IE so we don't create a non-painting
822 // widget in layout. See bug 188959.
823 nsAutoString hidden;
824 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, hidden) &&
825 (hidden.IsEmpty() ||
826 !hidden.LowerCaseEqualsLiteral("false") &&
827 !hidden.LowerCaseEqualsLiteral("no") &&
828 !hidden.LowerCaseEqualsLiteral("off"))) {
829 return PR_TRUE;
833 return PR_FALSE;
836 nsPoint nsObjectFrame::GetWindowOriginInPixels(PRBool aWindowless)
838 nsIView * parentWithView;
839 nsPoint origin(0,0);
841 GetOffsetFromView(origin, &parentWithView);
843 // if it's windowless, let's make sure we have our origin set right
844 // it may need to be corrected, like after scrolling
845 if (aWindowless && parentWithView) {
846 nsIViewManager* parentVM = parentWithView->GetViewManager();
848 // Walk up all the views and add up their positions until we
849 // reach the first view with a window (non-null widget). This will give us our
850 // position relative to the containing window which is what we want to give the plugin
851 nsIView* theView = parentWithView;
852 while (theView && !theView->GetWidget()) {
853 if (theView->GetViewManager() != parentVM)
854 break;
856 origin += theView->GetPosition();
857 theView = theView->GetParent();
861 origin.x = PresContext()->AppUnitsToDevPixels(origin.x);
862 origin.y = PresContext()->AppUnitsToDevPixels(origin.y);
864 return origin;
867 NS_IMETHODIMP
868 nsObjectFrame::DidReflow(nsPresContext* aPresContext,
869 const nsHTMLReflowState* aReflowState,
870 nsDidReflowStatus aStatus)
872 nsresult rv = nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
874 // The view is created hidden; once we have reflowed it and it has been
875 // positioned then we show it.
876 if (aStatus != NS_FRAME_REFLOW_FINISHED)
877 return rv;
879 PRBool bHidden = IsHidden();
881 if (HasView()) {
882 nsIView* view = GetView();
883 nsIViewManager* vm = view->GetViewManager();
884 if (vm)
885 vm->SetViewVisibility(view, bHidden ? nsViewVisibility_kHide : nsViewVisibility_kShow);
888 nsPluginWindow *win = nsnull;
890 nsCOMPtr<nsIPluginInstance> pi;
891 if (!mInstanceOwner ||
892 NS_FAILED(rv = mInstanceOwner->GetInstance(*getter_AddRefs(pi))) ||
893 !pi ||
894 NS_FAILED(rv = mInstanceOwner->GetWindow(win)) ||
895 !win)
896 return rv;
898 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
900 #ifdef XP_MACOSX
901 mInstanceOwner->FixUpPluginWindow(ePluginPaintDisable);
902 #endif
904 if (bHidden)
905 return rv;
907 PRBool windowless = (window->type == nsPluginWindowType_Drawable);
909 nsPoint origin = GetWindowOriginInPixels(windowless);
911 window->x = origin.x;
912 window->y = origin.y;
914 // refresh the plugin port as well
915 window->window = mInstanceOwner->GetPluginPort();
917 // this will call pi->SetWindow and take care of window subclassing
918 // if needed, see bug 132759
919 window->CallSetWindow(pi);
921 mInstanceOwner->ReleasePluginPort((nsPluginPort *)window->window);
923 return rv;
926 static void PaintPrintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
927 const nsRect& aDirtyRect, nsPoint aPt)
929 nsIRenderingContext::AutoPushTranslation translate(aCtx, aPt.x, aPt.y);
930 NS_STATIC_CAST(nsObjectFrame*, aFrame)->PrintPlugin(*aCtx, aDirtyRect);
933 static void PaintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
934 const nsRect& aDirtyRect, nsPoint aPt)
936 nsIRenderingContext::AutoPushTranslation translate(aCtx, aPt.x, aPt.y);
937 NS_STATIC_CAST(nsObjectFrame*, aFrame)->PaintPlugin(*aCtx, aDirtyRect);
940 NS_IMETHODIMP
941 nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
942 const nsRect& aDirtyRect,
943 const nsDisplayListSet& aLists)
945 // XXX why are we painting collapsed object frames?
946 if (!IsVisibleOrCollapsedForPainting(aBuilder))
947 return NS_OK;
949 nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
950 NS_ENSURE_SUCCESS(rv, rv);
952 nsPresContext::nsPresContextType type = PresContext()->Type();
954 // If we are painting in Print Preview do nothing....
955 if (type == nsPresContext::eContext_PrintPreview)
956 return NS_OK;
958 DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame");
960 // determine if we are printing
961 if (type == nsPresContext::eContext_Print)
962 return aLists.Content()->AppendNewToTop(new (aBuilder)
963 nsDisplayGeneric(this, PaintPrintPlugin, "PrintPlugin"));
965 return aLists.Content()->AppendNewToTop(new (aBuilder)
966 nsDisplayGeneric(this, ::PaintPlugin, "Plugin"));
969 void
970 nsObjectFrame::PrintPlugin(nsIRenderingContext& aRenderingContext,
971 const nsRect& aDirtyRect)
973 // if we are printing, we need to get the correct nsIPluginInstance
974 // for THIS content node in order to call ->Print() on the right plugin
976 // first, we need to get the document
977 nsIDocument* doc = mContent->GetCurrentDoc();
978 if (!doc)
979 return;
981 // now we need to get the shell for the screen
982 // XXX assuming that the shell at zero will always be the screen one
983 nsIPresShell *shell = doc->GetPrimaryShell();
984 if (!shell)
985 return;
987 // then the shell can give us the screen frame for this content node
988 nsIFrame* frame = shell->GetPrimaryFrameFor(mContent);
989 if (!frame)
990 return;
992 nsPresContext* presContext = PresContext();
993 // make sure this is REALLY an nsIObjectFrame
994 // we may need to go through the children to get it
995 nsIObjectFrame* objectFrame = nsnull;
996 CallQueryInterface(frame,&objectFrame);
997 if (!objectFrame)
998 objectFrame = GetNextObjectFrame(presContext,frame);
999 if (!objectFrame)
1000 return;
1002 // finally we can get our plugin instance
1003 nsCOMPtr<nsIPluginInstance> pi;
1004 if (NS_FAILED(objectFrame->GetPluginInstance(*getter_AddRefs(pi))) || !pi)
1005 return;
1007 // now we need to setup the correct location for printing
1008 nsresult rv;
1009 nsPluginWindow window;
1010 window.window = nsnull;
1012 // prepare embedded mode printing struct
1013 nsPluginPrint npprint;
1014 npprint.mode = nsPluginMode_Embedded;
1016 // we need to find out if we are windowless or not
1017 PRBool windowless = PR_FALSE;
1018 pi->GetValue(nsPluginInstanceVariable_WindowlessBool, (void *)&windowless);
1019 window.type = windowless ? nsPluginWindowType_Drawable : nsPluginWindowType_Window;
1021 // Get the offset of the DC
1022 nsTransform2D* rcTransform;
1023 aRenderingContext.GetCurrentTransform(rcTransform);
1024 nsPoint origin;
1025 rcTransform->GetTranslationCoord(&origin.x, &origin.y);
1027 // set it all up
1028 // XXX is windowless different?
1029 window.x = origin.x;
1030 window.y = origin.y;
1031 window.width = presContext->AppUnitsToDevPixels(mRect.width);
1032 window.height= presContext->AppUnitsToDevPixels(mRect.height);
1033 window.clipRect.bottom = 0; window.clipRect.top = 0;
1034 window.clipRect.left = 0; window.clipRect.right = 0;
1036 // XXX platform specific printing code
1037 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1038 /* UNIX does things completely differently:
1039 * We call the plugin and it sends generated PostScript data into a
1040 * file handle we provide. If the plugin returns with success we embed
1041 * this PostScript code fragment into the PostScript job we send to the
1042 * printer.
1045 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("nsObjectFrame::Paint() start for X11 platforms\n"));
1047 FILE *plugintmpfile = tmpfile();
1048 if (!plugintmpfile) {
1049 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("error: could not open tmp. file, errno=%d\n", errno));
1050 return;
1053 /* Send off print info to plugin */
1054 NPPrintCallbackStruct npPrintInfo;
1055 npPrintInfo.type = NP_PRINT;
1056 npPrintInfo.fp = plugintmpfile;
1057 npprint.print.embedPrint.platformPrint = (void *)&npPrintInfo;
1058 /* aDirtyRect contains the right information for ps print */
1059 window.x = aDirtyRect.x;
1060 window.y = aDirtyRect.y;
1061 window.width = aDirtyRect.width;
1062 window.height = aDirtyRect.height;
1063 npprint.print.embedPrint.window = window;
1064 rv = pi->Print(&npprint);
1065 if (NS_FAILED(rv)) {
1066 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("error: plugin returned failure %lx\n", (long)rv));
1067 fclose(plugintmpfile);
1068 return;
1071 /* Send data to printer */
1072 rv = aRenderingContext.RenderEPS(aDirtyRect, plugintmpfile);
1074 fclose(plugintmpfile);
1076 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("plugin printing done, return code is %lx\n", (long)rv));
1078 #else
1080 // we need the native printer device context to pass to plugin
1081 // On Windows, this will be the HDC
1082 void* dc;
1083 dc = aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_WINDOWS_DC);
1085 npprint.print.embedPrint.platformPrint = dc;
1086 npprint.print.embedPrint.window = window;
1087 // send off print info to plugin
1088 rv = pi->Print(&npprint);
1089 #endif
1091 // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same?
1092 nsDidReflowStatus status = NS_FRAME_REFLOW_FINISHED; // should we use a special status?
1093 frame->DidReflow(presContext,
1094 nsnull, status); // DidReflow will take care of it
1097 void
1098 nsObjectFrame::PaintPlugin(nsIRenderingContext& aRenderingContext,
1099 const nsRect& aDirtyRect)
1101 // Screen painting code
1102 #if defined(XP_MACOSX)
1103 // delegate all painting to the plugin instance.
1104 if (mInstanceOwner)
1105 mInstanceOwner->Paint(aDirtyRect);
1106 #elif defined (XP_WIN) // || defined(XP_OS2)
1107 // XXX for OS/2 we need to overhaul this for Cairo builds
1108 // for now just ignore plugin stuff
1109 nsCOMPtr<nsIPluginInstance> inst;
1110 GetPluginInstance(*getter_AddRefs(inst));
1111 if (inst) {
1112 // Look if it's windowless
1113 nsPluginWindow * window;
1114 mInstanceOwner->GetWindow(window);
1116 if (window->type == nsPluginWindowType_Drawable) {
1117 // check if we need to call SetWindow with updated parameters
1118 PRBool doupdatewindow = PR_FALSE;
1119 // the offset of the DC
1120 nsPoint origin;
1122 // check if we need to update hdc
1123 HDC hdc = (HDC)aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_WINDOWS_DC);
1125 if (NS_REINTERPRET_CAST(HDC, window->window) != hdc) {
1126 window->window = NS_REINTERPRET_CAST(nsPluginPort*, hdc);
1127 doupdatewindow = PR_TRUE;
1131 * Layout now has an optimized way of painting. Now we always get
1132 * a new drawing surface, sized to be just what's needed. Windowless
1133 * plugins need a transform applied to their origin so they paint
1134 * in the right place. Since |SetWindow| is no longer being used
1135 * to tell the plugin where it is, we dispatch a NPWindow through
1136 * |HandleEvent| to tell the plugin when its window moved
1139 #ifdef MOZ_CAIRO_GFX
1140 nsRefPtr<gfxContext> ctx = (gfxContext*)aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
1141 gfxMatrix ctxMatrix = ctx->CurrentMatrix();
1142 if (ctxMatrix.HasNonTranslation()) {
1143 // soo; in the future, we should be able to render
1144 // the object content to an offscreen DC, and then
1145 // composite it in with the right transforms.
1147 // But, we don't bother doing that, because we don't
1148 // have the event handling story figured out yet.
1149 // Instead, let's just bail.
1151 return;
1154 origin.x = NSToIntRound(float(ctxMatrix.GetTranslation().x));
1155 origin.y = NSToIntRound(float(ctxMatrix.GetTranslation().y));
1157 SaveDC(hdc);
1159 /* Need to force the clip to be set */
1160 ctx->UpdateSurfaceClip();
1162 /* Set the device offsets as appropriate, for whatever our current group offsets might be */
1163 gfxFloat xoff, yoff;
1164 nsRefPtr<gfxASurface> surf = ctx->CurrentSurface(&xoff, &yoff);
1166 POINT origViewportOrigin;
1167 GetViewportOrgEx(hdc, &origViewportOrigin);
1168 SetViewportOrgEx(hdc, origViewportOrigin.x + (int) xoff, origViewportOrigin.y + (int) yoff, NULL);
1169 #else
1170 nsTransform2D* rcTransform;
1171 aRenderingContext.GetCurrentTransform(rcTransform);
1172 rcTransform->GetTranslationCoord(&origin.x, &origin.y);
1173 #endif
1175 if ((window->x != origin.x) || (window->y != origin.y)) {
1176 window->x = origin.x;
1177 window->y = origin.y;
1178 doupdatewindow = PR_TRUE;
1181 // if our location or visible area has changed, we need to tell the plugin
1182 if (doupdatewindow) {
1183 #ifdef XP_WIN // Windowless plugins on windows need a special event to update their location, see bug 135737
1184 // bug 271442: note, the rectangle we send is now purely the bounds of the plugin
1185 // relative to the window it is contained in, which is useful for the plugin to correctly translate mouse coordinates
1187 // this does not mesh with the comments for bug 135737 which imply that the rectangle
1188 // must be clipped in some way to prevent the plugin attempting to paint over areas it shouldn't;
1190 // since the two uses of the rectangle are mutually exclusive in some cases,
1191 // and since I don't see any incorrect painting (at least with Flash and ViewPoint - the originator of 135737),
1192 // it seems that windowless plugins are not relying on information here for clipping their drawing,
1193 // and we can safely use this message to tell the plugin exactly where it is in all cases.
1195 origin = GetWindowOriginInPixels(PR_TRUE);
1196 nsRect winlessRect = nsRect(origin, nsSize(window->width, window->height));
1197 if (mWindowlessRect != winlessRect) {
1198 mWindowlessRect = winlessRect;
1200 WINDOWPOS winpos;
1201 memset(&winpos, 0, sizeof(winpos));
1202 winpos.x = mWindowlessRect.x;
1203 winpos.y = mWindowlessRect.y;
1204 winpos.cx = mWindowlessRect.width;
1205 winpos.cy = mWindowlessRect.height;
1207 // finally, update the plugin by sending it a WM_WINDOWPOSCHANGED event
1208 nsPluginEvent pluginEvent;
1209 pluginEvent.event = WM_WINDOWPOSCHANGED;
1210 pluginEvent.wParam = 0;
1211 pluginEvent.lParam = (uint32)&winpos;
1212 PRBool eventHandled = PR_FALSE;
1214 inst->HandleEvent(&pluginEvent, &eventHandled);
1216 #endif
1218 inst->SetWindow(window);
1221 // This expects a dirty rect relative to the plugin's rect
1222 // XXX I wonder if this breaks if we give the frame a border so the
1223 // frame origin and plugin origin are not the same
1224 mInstanceOwner->Paint(aDirtyRect, (PRUint32)(HDC)hdc);
1226 #ifdef MOZ_CAIRO_GFX
1227 RestoreDC(hdc, -1);
1229 surf->MarkDirty();
1230 #endif
1233 #endif
1236 NS_IMETHODIMP
1237 nsObjectFrame::HandleEvent(nsPresContext* aPresContext,
1238 nsGUIEvent* anEvent,
1239 nsEventStatus* anEventStatus)
1241 NS_ENSURE_ARG_POINTER(anEventStatus);
1242 nsresult rv = NS_OK;
1244 if (!mInstanceOwner)
1245 return NS_ERROR_NULL_POINTER;
1247 if (anEvent->message == NS_PLUGIN_ACTIVATE) {
1248 nsIContent* content = GetContent();
1249 if (content) {
1250 content->SetFocus(aPresContext);
1251 return rv;
1255 #ifdef XP_WIN
1256 rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
1257 return rv;
1258 #endif
1260 switch (anEvent->message) {
1261 case NS_DESTROY:
1262 mInstanceOwner->CancelTimer();
1263 break;
1264 case NS_GOTFOCUS:
1265 case NS_LOSTFOCUS:
1266 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
1267 break;
1269 default:
1270 // instead of using an event listener, we can dispatch events to plugins directly.
1271 rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
1274 return rv;
1277 nsresult nsObjectFrame::GetPluginInstance(nsIPluginInstance*& aPluginInstance)
1279 aPluginInstance = nsnull;
1281 if (!mInstanceOwner)
1282 return NS_OK;
1284 return mInstanceOwner->GetInstance(aPluginInstance);
1287 nsresult
1288 nsObjectFrame::PrepareInstanceOwner()
1290 // First, have to stop any possibly running plugins.
1291 StopPlugin();
1293 NS_ASSERTION(!mInstanceOwner, "Must not have an instance owner here");
1295 mInstanceOwner = new nsPluginInstanceOwner();
1296 if (!mInstanceOwner)
1297 return NS_ERROR_OUT_OF_MEMORY;
1299 NS_ADDREF(mInstanceOwner);
1300 mInstanceOwner->Init(PresContext(), this, GetContent());
1301 return NS_OK;
1304 nsresult
1305 nsObjectFrame::Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener)
1307 nsresult rv = PrepareInstanceOwner();
1308 NS_ENSURE_SUCCESS(rv, rv);
1310 nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(kCPluginManagerCID, &rv));
1311 if (NS_FAILED(rv))
1312 return rv;
1313 mInstanceOwner->SetPluginHost(pluginHost);
1315 // This must be done before instantiating the plugin
1316 FixupWindow(mRect.Size());
1318 rv = pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
1320 // XXX having to do this sucks. it'd be better to move the code from DidReflow
1321 // to FixupWindow.
1322 PresContext()->GetPresShell()->
1323 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
1324 return rv;
1327 nsresult
1328 nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI)
1330 NS_ASSERTION(aMimeType || aURI, "Need a type or a URI!");
1331 nsresult rv = PrepareInstanceOwner();
1332 NS_ENSURE_SUCCESS(rv, rv);
1334 // This must be done before instantiating the plugin
1335 FixupWindow(mRect.Size());
1337 // get the nsIPluginHost service
1338 nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(kCPluginManagerCID, &rv));
1339 if (NS_FAILED(rv))
1340 return rv;
1341 mInstanceOwner->SetPluginHost(pluginHost);
1343 rv = InstantiatePlugin(pluginHost, aMimeType, aURI);
1345 // finish up
1346 if (NS_SUCCEEDED(rv)) {
1347 nsCOMPtr<nsIPluginInstance> inst;
1348 mInstanceOwner->GetInstance(*getter_AddRefs(inst));
1349 if (inst) {
1350 // The plugin may have set up new interfaces; we need to mess with our JS
1351 // wrapper. Note that we DO NOT want to call this if there is no plugin
1352 // instance! That would just reenter Instantiate(), trying to create
1353 // said plugin instance.
1354 NotifyContentObjectWrapper();
1358 return rv;
1361 void
1362 nsObjectFrame::StopPlugin()
1364 if (mInstanceOwner != nsnull) {
1365 nsCOMPtr<nsIPluginInstance> inst;
1366 mInstanceOwner->GetInstance(*getter_AddRefs(inst));
1367 if (inst) {
1368 nsPluginWindow *win;
1369 mInstanceOwner->GetWindow(win);
1370 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
1371 nsCOMPtr<nsIPluginInstance> nullinst;
1373 PRBool doCache = PR_TRUE;
1374 PRBool doCallSetWindowAfterDestroy = PR_FALSE;
1376 // first, determine if the plugin wants to be cached
1377 inst->GetValue(nsPluginInstanceVariable_DoCacheBool,
1378 (void *) &doCache);
1379 if (!doCache) {
1380 // then determine if the plugin wants Destroy to be called after
1381 // Set Window. This is for bug 50547.
1382 inst->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool,
1383 (void *) &doCallSetWindowAfterDestroy);
1384 if (doCallSetWindowAfterDestroy) {
1385 inst->Stop();
1386 inst->Destroy();
1388 if (window)
1389 window->CallSetWindow(nullinst);
1390 else
1391 inst->SetWindow(nsnull);
1393 else {
1394 if (window)
1395 window->CallSetWindow(nullinst);
1396 else
1397 inst->SetWindow(nsnull);
1399 inst->Stop();
1400 inst->Destroy();
1403 else {
1404 if (window)
1405 window->CallSetWindow(nullinst);
1406 else
1407 inst->SetWindow(nsnull);
1409 inst->Stop();
1412 nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(kCPluginManagerCID);
1413 if (pluginHost)
1414 pluginHost->StopPluginInstance(inst);
1416 // the frame is going away along with its widget
1417 // so tell the window to forget its widget too
1418 if (window)
1419 window->SetPluginWidget(nsnull);
1422 mInstanceOwner->Destroy();
1423 NS_RELEASE(mInstanceOwner);
1427 void
1428 nsObjectFrame::NotifyContentObjectWrapper()
1430 nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
1431 if (!doc)
1432 return;
1434 nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
1435 if (!sgo)
1436 return;
1438 nsIScriptContext *scx = sgo->GetContext();
1439 if (!scx)
1440 return;
1442 JSContext *cx = (JSContext *)scx->GetNativeContext();
1444 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
1445 nsContentUtils::XPConnect()->
1446 GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), mContent,
1447 NS_GET_IID(nsISupports),
1448 getter_AddRefs(wrapper));
1450 if (!wrapper) {
1451 // Nothing to do here if there's no wrapper for mContent
1452 return;
1455 nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(mContent));
1456 if (!ci)
1457 return;
1459 nsCOMPtr<nsISupports> s;
1460 ci->GetHelperForLanguage(nsIProgrammingLanguage::JAVASCRIPT,
1461 getter_AddRefs(s));
1463 nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(s));
1465 if (!helper) {
1466 // There's nothing we can do if there's no helper
1467 return;
1470 JSObject *obj = nsnull;
1471 nsresult rv = wrapper->GetJSObject(&obj);
1472 if (NS_FAILED(rv))
1473 return;
1475 // Abuse the scriptable helper to trigger prototype setup for the
1476 // wrapper for mContent so that this plugin becomes part of the DOM
1477 // object.
1478 helper->PostCreate(wrapper, cx, obj);
1481 // static
1482 nsIObjectFrame *
1483 nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)
1485 nsIFrame* child = aRoot->GetFirstChild(nsnull);
1487 while (child) {
1488 nsIObjectFrame* outFrame = nsnull;
1489 CallQueryInterface(child, &outFrame);
1490 if (outFrame) {
1491 nsCOMPtr<nsIPluginInstance> pi;
1492 outFrame->GetPluginInstance(*getter_AddRefs(pi)); // make sure we have a REAL plugin
1493 if (pi)
1494 return outFrame;
1497 outFrame = GetNextObjectFrame(aPresContext, child);
1498 if (outFrame)
1499 return outFrame;
1500 child = child->GetNextSibling();
1503 return nsnull;
1506 nsIFrame*
1507 NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
1509 return new (aPresShell) nsObjectFrame(aContext);
1513 // nsPluginDOMContextMenuListener class implementation
1515 nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener()
1519 nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
1523 NS_IMPL_ISUPPORTS2(nsPluginDOMContextMenuListener, nsIDOMContextMenuListener, nsIEventListener)
1525 NS_IMETHODIMP
1526 nsPluginDOMContextMenuListener::ContextMenu(nsIDOMEvent* aContextMenuEvent)
1528 aContextMenuEvent->PreventDefault(); // consume event
1530 return NS_OK;
1533 nsresult nsPluginDOMContextMenuListener::Init(nsIContent* aContent)
1535 nsCOMPtr<nsIDOMEventTarget> receiver(do_QueryInterface(aContent));
1536 if (receiver) {
1537 receiver->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, PR_TRUE);
1538 return NS_OK;
1541 return NS_ERROR_NO_INTERFACE;
1544 nsresult nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent)
1546 // Unregister context menu listener
1547 nsCOMPtr<nsIDOMEventTarget> receiver(do_QueryInterface(aContent));
1548 if (receiver) {
1549 receiver->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, PR_TRUE);
1552 return NS_OK;
1555 //plugin instance owner
1557 nsPluginInstanceOwner::nsPluginInstanceOwner()
1559 // create nsPluginNativeWindow object, it is derived from nsPluginWindow
1560 // struct and allows to manipulate native window procedure
1561 nsCOMPtr<nsIPluginHost> ph = do_GetService(kCPluginManagerCID);
1562 nsCOMPtr<nsPIPluginHost> pph(do_QueryInterface(ph));
1563 if (pph)
1564 pph->NewPluginNativeWindow(&mPluginWindow);
1565 else
1566 mPluginWindow = nsnull;
1568 mOwner = nsnull;
1569 mTagText = nsnull;
1570 mContentFocused = PR_FALSE;
1571 mWidgetVisible = PR_TRUE;
1572 mNumCachedAttrs = 0;
1573 mNumCachedParams = 0;
1574 mCachedAttrParamNames = nsnull;
1575 mCachedAttrParamValues = nsnull;
1578 nsPluginInstanceOwner::~nsPluginInstanceOwner()
1580 PRInt32 cnt;
1582 // shut off the timer.
1583 if (mPluginTimer != nsnull) {
1584 CancelTimer();
1587 mOwner = nsnull;
1589 for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) {
1590 if (mCachedAttrParamNames && mCachedAttrParamNames[cnt]) {
1591 PR_Free(mCachedAttrParamNames[cnt]);
1592 mCachedAttrParamNames[cnt] = nsnull;
1595 if (mCachedAttrParamValues && mCachedAttrParamValues[cnt]) {
1596 PR_Free(mCachedAttrParamValues[cnt]);
1597 mCachedAttrParamValues[cnt] = nsnull;
1601 if (mCachedAttrParamNames) {
1602 PR_Free(mCachedAttrParamNames);
1603 mCachedAttrParamNames = nsnull;
1606 if (mCachedAttrParamValues) {
1607 PR_Free(mCachedAttrParamValues);
1608 mCachedAttrParamValues = nsnull;
1611 if (mTagText) {
1612 NS_Free(mTagText);
1613 mTagText = nsnull;
1616 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1617 // the mem for this struct is allocated
1618 // by PR_MALLOC in ns4xPluginInstance.cpp:ns4xPluginInstance::SetWindow()
1619 if (mPluginWindow && mPluginWindow->ws_info) {
1620 PR_Free(mPluginWindow->ws_info);
1621 mPluginWindow->ws_info = nsnull;
1623 #endif
1625 // clean up plugin native window object
1626 nsCOMPtr<nsIPluginHost> ph = do_GetService(kCPluginManagerCID);
1627 nsCOMPtr<nsPIPluginHost> pph(do_QueryInterface(ph));
1628 if (pph) {
1629 pph->DeletePluginNativeWindow(mPluginWindow);
1630 mPluginWindow = nsnull;
1635 * nsISupports Implementation
1638 NS_IMPL_ADDREF(nsPluginInstanceOwner)
1639 NS_IMPL_RELEASE(nsPluginInstanceOwner)
1641 NS_INTERFACE_MAP_BEGIN(nsPluginInstanceOwner)
1642 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
1643 NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo)
1644 NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo2)
1645 #ifdef OJI
1646 NS_INTERFACE_MAP_ENTRY(nsIJVMPluginTagInfo)
1647 #endif
1648 NS_INTERFACE_MAP_ENTRY(nsIEventListener)
1649 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
1650 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
1651 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener)
1652 NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
1653 NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
1654 NS_INTERFACE_MAP_ENTRY(nsIScrollPositionListener)
1655 NS_INTERFACE_MAP_ENTRY(nsIDOMDragListener)
1656 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
1657 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPluginInstanceOwner)
1658 NS_INTERFACE_MAP_END
1660 NS_IMETHODIMP nsPluginInstanceOwner::SetInstance(nsIPluginInstance *aInstance)
1662 mInstance = aInstance;
1664 return NS_OK;
1667 NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(nsPluginWindow *&aWindow)
1669 NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null");
1670 aWindow = mPluginWindow;
1671 return NS_OK;
1674 NS_IMETHODIMP nsPluginInstanceOwner::GetMode(nsPluginMode *aMode)
1676 nsCOMPtr<nsIDocument> doc;
1677 nsresult rv = GetDocument(getter_AddRefs(doc));
1678 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
1680 if (pDoc) {
1681 *aMode = nsPluginMode_Full;
1682 } else {
1683 *aMode = nsPluginMode_Embedded;
1686 return rv;
1689 NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(PRUint16& n,
1690 const char*const*& names,
1691 const char*const*& values)
1693 nsresult rv = EnsureCachedAttrParamArrays();
1694 NS_ENSURE_SUCCESS(rv, rv);
1696 n = mNumCachedAttrs;
1697 names = (const char **)mCachedAttrParamNames;
1698 values = (const char **)mCachedAttrParamValues;
1700 return rv;
1703 NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result)
1705 NS_ENSURE_ARG_POINTER(name);
1706 NS_ENSURE_ARG_POINTER(result);
1708 nsresult rv = EnsureCachedAttrParamArrays();
1709 NS_ENSURE_SUCCESS(rv, rv);
1711 *result = nsnull;
1713 for (int i = 0; i < mNumCachedAttrs; i++) {
1714 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
1715 *result = mCachedAttrParamValues[i];
1716 return NS_OK;
1720 return NS_ERROR_FAILURE;
1723 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
1725 return CallQueryInterface(mContent, result);
1728 NS_IMETHODIMP nsPluginInstanceOwner::GetInstance(nsIPluginInstance *&aInstance)
1730 NS_IF_ADDREF(aInstance = mInstance);
1732 return NS_OK;
1735 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, const char *aTarget, void *aPostData, PRUint32 aPostDataLen, void *aHeadersData,
1736 PRUint32 aHeadersDataLen, PRBool isFile)
1738 NS_ENSURE_TRUE(mOwner,NS_ERROR_NULL_POINTER);
1740 // the container of the pres context will give us the link handler
1741 nsCOMPtr<nsISupports> container = mOwner->PresContext()->GetContainer();
1742 NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
1743 nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
1744 NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
1746 nsAutoString unitarget;
1747 unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
1749 nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
1751 // Create an absolute URL
1752 nsCOMPtr<nsIURI> uri;
1753 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
1755 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1757 nsCOMPtr<nsIInputStream> postDataStream;
1758 nsCOMPtr<nsIInputStream> headersDataStream;
1760 // deal with post data, either in a file or raw data, and any headers
1761 if (aPostData) {
1763 rv = NS_NewPluginPostDataStream(getter_AddRefs(postDataStream), (const char *)aPostData, aPostDataLen, isFile);
1765 NS_ASSERTION(NS_SUCCEEDED(rv),"failed in creating plugin post data stream");
1766 if (NS_FAILED(rv))
1767 return rv;
1769 if (aHeadersData) {
1770 rv = NS_NewPluginPostDataStream(getter_AddRefs(headersDataStream),
1771 (const char *) aHeadersData,
1772 aHeadersDataLen,
1773 PR_FALSE,
1774 PR_TRUE); // last arg says we are headers, no /r/n/r/n fixup!
1776 NS_ASSERTION(NS_SUCCEEDED(rv),"failed in creating plugin header data stream");
1777 if (NS_FAILED(rv))
1778 return rv;
1782 PRInt32 blockPopups =
1783 nsContentUtils::GetIntPref("privacy.popups.disable_from_plugins");
1784 nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
1786 rv = lh->OnLinkClick(mContent, uri, unitarget.get(),
1787 postDataStream, headersDataStream);
1789 return rv;
1792 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char *aStatusMsg)
1794 nsresult rv = NS_ERROR_FAILURE;
1796 rv = this->ShowStatus(NS_ConvertUTF8toUTF16(aStatusMsg).get());
1798 return rv;
1801 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const PRUnichar *aStatusMsg)
1803 nsresult rv = NS_ERROR_FAILURE;
1805 if (!mOwner) {
1806 return rv;
1808 nsCOMPtr<nsISupports> cont = mOwner->PresContext()->GetContainer();
1809 if (!cont) {
1810 return NS_OK;
1813 nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(cont, &rv));
1814 if (NS_FAILED(rv) || !docShellItem) {
1815 return rv;
1818 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1819 rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
1820 if (NS_FAILED(rv) || !treeOwner) {
1821 return rv;
1824 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner, &rv));
1825 if (NS_FAILED(rv) || !browserChrome) {
1826 return rv;
1828 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
1829 aStatusMsg);
1831 return rv;
1834 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
1836 if (!aDocument)
1837 return NS_ERROR_NULL_POINTER;
1839 // XXX sXBL/XBL2 issue: current doc or owner doc?
1840 // But keep in mind bug 322414 comment 33
1841 NS_IF_ADDREF(*aDocument = mContent->GetOwnerDoc());
1842 return NS_OK;
1845 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(nsPluginRect *invalidRect)
1847 nsresult rv = NS_ERROR_FAILURE;
1849 if (mOwner && invalidRect) {
1850 //no reference count on view
1851 nsIView* view = mOwner->GetView();
1853 if (view) {
1854 nsPresContext* presContext = mOwner->PresContext();
1856 nsRect rect(presContext->DevPixelsToAppUnits(invalidRect->left),
1857 presContext->DevPixelsToAppUnits(invalidRect->top),
1858 presContext->DevPixelsToAppUnits(invalidRect->right - invalidRect->left),
1859 presContext->DevPixelsToAppUnits(invalidRect->bottom - invalidRect->top));
1861 //set flags to not do a synchronous update, force update does the redraw
1862 view->GetViewManager()->UpdateView(view, rect, NS_VMREFRESH_NO_SYNC);
1866 return rv;
1869 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(nsPluginRegion invalidRegion)
1871 return NS_ERROR_NOT_IMPLEMENTED;
1874 NS_IMETHODIMP nsPluginInstanceOwner::ForceRedraw()
1876 nsIView* view = mOwner->GetView();
1877 if (view) {
1878 return view->GetViewManager()->Composite();
1881 return NS_OK;
1884 NS_IMETHODIMP nsPluginInstanceOwner::GetValue(nsPluginInstancePeerVariable variable, void *value)
1886 nsresult rv = NS_ERROR_FAILURE;
1888 switch(variable) {
1889 case nsPluginInstancePeerVariable_NetscapeWindow:
1891 if (mOwner) {
1892 void** pvalue = (void**)value;
1893 nsIViewManager* vm = mOwner->PresContext()->GetViewManager();
1894 if (vm) {
1895 #if defined(XP_WIN)
1896 // This property is provided to allow a "windowless" plugin to determine the window it is drawing
1897 // in, so it can translate mouse coordinates it receives directly from the operating system
1898 // to coordinates relative to itself.
1900 // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin
1901 // 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
1903 // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
1904 // determines the window handle of the mozilla window containing the "windowless" plugin.
1906 // Given that this HWND may not be that of the document's window, there is a slight risk
1907 // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
1908 // does not suggest this HWND IS that of the document window, rather that of the window
1909 // the plugin is drawn in, this seems like a safe fix.
1911 // we only attempt to get the nearest window if this really is a "windowless" plugin so as not
1912 // to change any behaviour for the much more common windowed plugins,
1913 // though why this method would even be being called for a windowed plugin escapes me.
1914 if (mPluginWindow && mPluginWindow->type == nsPluginWindowType_Drawable) {
1915 if (mOwner) {
1916 // it turns out that flash also uses this window for determining focus, and is currently
1917 // unable to show a caret correctly if we return the enclosing window. Therefore for
1918 // now we only return the enclosing window when there is an actual offset which
1919 // would otherwise cause coordinates to be offset incorrectly. (i.e.
1920 // if the enclosing window if offset from the document window)
1922 // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
1923 // does not seem to be possible without a change to the flash plugin
1925 nsIWidget* win = mOwner->GetWindow();
1926 if (win) {
1927 nsIView *view = nsIView::GetViewFor(win);
1928 NS_ASSERTION(view, "No view for widget");
1929 nsIView *rootView = nsnull;
1930 vm->GetRootView(rootView);
1931 NS_ASSERTION(rootView, "No root view");
1932 nsPoint offset = view->GetOffsetTo(rootView);
1934 if (offset.x || offset.y) {
1935 // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
1936 // so that mouse co-ordinates are not messed up.
1937 *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW);
1938 if (*pvalue)
1939 return NS_OK;
1944 #endif
1945 // simply return the document window
1946 nsCOMPtr<nsIWidget> widget;
1947 rv = vm->GetWidget(getter_AddRefs(widget));
1948 if (widget) {
1949 *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
1950 } else NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
1951 } else NS_ASSERTION(vm, "couldn't get view manager in getting doc's window handle");
1952 } else NS_ASSERTION(mOwner, "plugin owner has no owner in getting doc's window handle");
1953 break;
1957 return rv;
1960 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
1962 NS_ENSURE_ARG_POINTER(result);
1964 *result = nsPluginTagType_Unknown;
1966 nsIAtom *atom = mContent->Tag();
1968 if (atom == nsGkAtoms::applet)
1969 *result = nsPluginTagType_Applet;
1970 else if (atom == nsGkAtoms::embed)
1971 *result = nsPluginTagType_Embed;
1972 else if (atom == nsGkAtoms::object)
1973 *result = nsPluginTagType_Object;
1975 return NS_OK;
1978 NS_IMETHODIMP nsPluginInstanceOwner::GetTagText(const char* *result)
1980 NS_ENSURE_ARG_POINTER(result);
1981 if (nsnull == mTagText) {
1982 nsresult rv;
1983 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent, &rv));
1984 if (NS_FAILED(rv))
1985 return rv;
1987 nsCOMPtr<nsIDocument> document;
1988 rv = GetDocument(getter_AddRefs(document));
1989 if (NS_FAILED(rv))
1990 return rv;
1992 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(document);
1993 NS_ASSERTION(domDoc, "Need a document");
1995 nsCOMPtr<nsIDocumentEncoder> docEncoder(do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/html", &rv));
1996 if (NS_FAILED(rv))
1997 return rv;
1998 rv = docEncoder->Init(domDoc, NS_LITERAL_STRING("text/html"), nsIDocumentEncoder::OutputEncodeBasicEntities);
1999 if (NS_FAILED(rv))
2000 return rv;
2002 nsCOMPtr<nsIDOMRange> range(do_CreateInstance(kRangeCID,&rv));
2003 if (NS_FAILED(rv))
2004 return rv;
2006 rv = range->SelectNode(node);
2007 if (NS_FAILED(rv))
2008 return rv;
2010 docEncoder->SetRange(range);
2011 nsString elementHTML;
2012 rv = docEncoder->EncodeToString(elementHTML);
2013 if (NS_FAILED(rv))
2014 return rv;
2016 mTagText = ToNewUTF8String(elementHTML);
2017 if (!mTagText)
2018 return NS_ERROR_OUT_OF_MEMORY;
2020 *result = mTagText;
2021 return NS_OK;
2024 NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(PRUint16& n, const char*const*& names, const char*const*& values)
2026 nsresult rv = EnsureCachedAttrParamArrays();
2027 NS_ENSURE_SUCCESS(rv, rv);
2029 n = mNumCachedParams;
2030 if (n) {
2031 names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1);
2032 values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1);
2033 } else
2034 names = values = nsnull;
2036 return rv;
2039 NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result)
2041 NS_ENSURE_ARG_POINTER(name);
2042 NS_ENSURE_ARG_POINTER(result);
2044 nsresult rv = EnsureCachedAttrParamArrays();
2045 NS_ENSURE_SUCCESS(rv, rv);
2047 *result = nsnull;
2049 for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) {
2050 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
2051 *result = mCachedAttrParamValues[i];
2052 return NS_OK;
2056 return NS_ERROR_FAILURE;
2059 NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentBase(const char* *result)
2061 NS_ENSURE_ARG_POINTER(result);
2062 nsresult rv = NS_OK;
2063 if (mDocumentBase.IsEmpty()) {
2064 if (!mOwner) {
2065 *result = nsnull;
2066 return NS_ERROR_FAILURE;
2069 nsIDocument* doc = mContent->GetOwnerDoc();
2070 NS_ASSERTION(doc, "Must have an owner doc");
2071 rv = doc->GetBaseURI()->GetSpec(mDocumentBase);
2073 if (NS_SUCCEEDED(rv))
2074 *result = ToNewCString(mDocumentBase);
2075 return rv;
2078 static nsDataHashtable<nsDepCharHashKey, const char *> * gCharsetMap;
2079 typedef struct {
2080 char mozName[16];
2081 char javaName[12];
2082 } moz2javaCharset;
2084 /* XXX If you add any strings longer than
2085 * {"x-mac-cyrillic", "MacCyrillic"},
2086 * {"x-mac-ukrainian", "MacUkraine"},
2087 * to the following array then you MUST update the
2088 * sizes of the arrays in the moz2javaCharset struct
2091 static const moz2javaCharset charsets[] =
2093 {"windows-1252", "Cp1252"},
2094 {"IBM850", "Cp850"},
2095 {"IBM852", "Cp852"},
2096 {"IBM855", "Cp855"},
2097 {"IBM857", "Cp857"},
2098 {"IBM828", "Cp862"},
2099 {"IBM864", "Cp864"},
2100 {"IBM866", "Cp866"},
2101 {"windows-1250", "Cp1250"},
2102 {"windows-1251", "Cp1251"},
2103 {"windows-1253", "Cp1253"},
2104 {"windows-1254", "Cp1254"},
2105 {"windows-1255", "Cp1255"},
2106 {"windows-1256", "Cp1256"},
2107 {"windows-1257", "Cp1257"},
2108 {"windows-1258", "Cp1258"},
2109 {"EUC-JP", "EUC_JP"},
2110 {"EUC-KR", "EUC_KR"},
2111 {"x-euc-tw", "EUC_TW"},
2112 {"gb18030", "GB18030"},
2113 {"x-gbk", "GBK"},
2114 {"ISO-2022-JP", "ISO2022JP"},
2115 {"ISO-2022-KR", "ISO2022KR"},
2116 {"ISO-8859-2", "ISO8859_2"},
2117 {"ISO-8859-3", "ISO8859_3"},
2118 {"ISO-8859-4", "ISO8859_4"},
2119 {"ISO-8859-5", "ISO8859_5"},
2120 {"ISO-8859-6", "ISO8859_6"},
2121 {"ISO-8859-7", "ISO8859_7"},
2122 {"ISO-8859-8", "ISO8859_8"},
2123 {"ISO-8859-9", "ISO8859_9"},
2124 {"ISO-8859-13", "ISO8859_13"},
2125 {"x-johab", "Johab"},
2126 {"KOI8-R", "KOI8_R"},
2127 {"TIS-620", "MS874"},
2128 {"windows-936", "MS936"},
2129 {"x-windows-949", "MS949"},
2130 {"x-mac-arabic", "MacArabic"},
2131 {"x-mac-croatian", "MacCroatia"},
2132 {"x-mac-cyrillic", "MacCyrillic"},
2133 {"x-mac-greek", "MacGreek"},
2134 {"x-mac-hebrew", "MacHebrew"},
2135 {"x-mac-icelandic", "MacIceland"},
2136 {"x-mac-roman", "MacRoman"},
2137 {"x-mac-romanian", "MacRomania"},
2138 {"x-mac-ukrainian", "MacUkraine"},
2139 {"Shift_JIS", "SJIS"},
2140 {"TIS-620", "TIS620"}
2143 NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentEncoding(const char* *result)
2145 NS_ENSURE_ARG_POINTER(result);
2146 *result = nsnull;
2148 nsresult rv;
2149 // XXX sXBL/XBL2 issue: current doc or owner doc?
2150 nsCOMPtr<nsIDocument> doc;
2151 rv = GetDocument(getter_AddRefs(doc));
2152 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get document");
2153 if (NS_FAILED(rv))
2154 return rv;
2156 const nsCString &charset = doc->GetDocumentCharacterSet();
2158 if (charset.IsEmpty())
2159 return NS_OK;
2161 // common charsets and those not requiring conversion first
2162 if (charset.EqualsLiteral("us-ascii")) {
2163 *result = PL_strdup("US_ASCII");
2164 } else if (charset.EqualsLiteral("ISO-8859-1") ||
2165 !nsCRT::strncmp(PromiseFlatCString(charset).get(), "UTF", 3)) {
2166 *result = ToNewCString(charset);
2167 } else {
2168 if (!gCharsetMap) {
2169 const int NUM_CHARSETS = sizeof(charsets) / sizeof(moz2javaCharset);
2170 gCharsetMap = new nsDataHashtable<nsDepCharHashKey, const char*>();
2171 if (!gCharsetMap || !gCharsetMap->Init(NUM_CHARSETS))
2172 return NS_ERROR_OUT_OF_MEMORY;
2174 for (PRUint16 i = 0; i < NUM_CHARSETS; i++) {
2175 gCharsetMap->Put(charsets[i].mozName, charsets[i].javaName);
2178 // if found mapping, return it; otherwise return original charset
2179 const char *mapping;
2180 *result = gCharsetMap->Get(charset.get(), &mapping) ? PL_strdup(mapping) :
2181 ToNewCString(charset);
2184 return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
2187 NS_IMETHODIMP nsPluginInstanceOwner::GetAlignment(const char* *result)
2189 return GetAttribute("ALIGN", result);
2192 NS_IMETHODIMP nsPluginInstanceOwner::GetWidth(PRUint32 *result)
2194 NS_ENSURE_ARG_POINTER(result);
2196 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
2198 *result = mPluginWindow->width;
2200 return NS_OK;
2203 NS_IMETHODIMP nsPluginInstanceOwner::GetHeight(PRUint32 *result)
2205 NS_ENSURE_ARG_POINTER(result);
2207 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
2209 *result = mPluginWindow->height;
2211 return NS_OK;
2215 NS_IMETHODIMP nsPluginInstanceOwner::GetBorderVertSpace(PRUint32 *result)
2217 nsresult rv;
2218 const char *vspace;
2220 rv = GetAttribute("VSPACE", &vspace);
2222 if (NS_OK == rv) {
2223 if (*result != 0)
2224 *result = (PRUint32)atol(vspace);
2225 else
2226 *result = 0;
2228 else
2229 *result = 0;
2231 return rv;
2234 NS_IMETHODIMP nsPluginInstanceOwner::GetBorderHorizSpace(PRUint32 *result)
2236 nsresult rv;
2237 const char *hspace;
2239 rv = GetAttribute("HSPACE", &hspace);
2241 if (NS_OK == rv) {
2242 if (*result != 0)
2243 *result = (PRUint32)atol(hspace);
2244 else
2245 *result = 0;
2247 else
2248 *result = 0;
2250 return rv;
2253 NS_IMETHODIMP nsPluginInstanceOwner::GetUniqueID(PRUint32 *result)
2255 NS_ENSURE_ARG_POINTER(result);
2256 *result = NS_PTR_TO_INT32(mOwner);
2257 return NS_OK;
2260 #ifdef OJI
2261 NS_IMETHODIMP nsPluginInstanceOwner::GetCode(const char* *result)
2263 nsresult rv;
2264 nsPluginTagType tagType;
2265 NS_ENSURE_SUCCESS(rv = GetTagType(&tagType), rv);
2267 rv = NS_ERROR_FAILURE;
2268 if (nsPluginTagType_Object != tagType)
2269 rv = GetAttribute("CODE", result);
2270 if (NS_FAILED(rv))
2271 rv = GetParameter("CODE", result);
2273 return rv;
2276 NS_IMETHODIMP nsPluginInstanceOwner::GetCodeBase(const char* *result)
2278 nsresult rv;
2279 if (NS_FAILED(rv = GetAttribute("CODEBASE", result)))
2280 rv = GetParameter("CODEBASE", result);
2281 return rv;
2284 NS_IMETHODIMP nsPluginInstanceOwner::GetArchive(const char* *result)
2286 nsresult rv;
2287 if (NS_FAILED(rv = GetAttribute("ARCHIVE", result)))
2288 rv = GetParameter("ARCHIVE", result);
2289 return rv;
2292 NS_IMETHODIMP nsPluginInstanceOwner::GetName(const char* *result)
2294 nsresult rv;
2295 nsPluginTagType tagType;
2296 NS_ENSURE_SUCCESS(rv = GetTagType(&tagType), rv);
2298 rv = NS_ERROR_FAILURE;
2299 if (nsPluginTagType_Object != tagType)
2300 rv = GetAttribute("NAME", result);
2301 if (NS_FAILED(rv))
2302 rv = GetParameter("NAME", result);
2304 return rv;
2307 NS_IMETHODIMP nsPluginInstanceOwner::GetMayScript(PRBool *result)
2309 NS_ENSURE_ARG_POINTER(result);
2310 nsPluginTagType tagType;
2311 NS_ENSURE_SUCCESS(GetTagType(&tagType), NS_ERROR_FAILURE);
2313 const char* unused;
2314 if (nsPluginTagType_Object == tagType)
2315 *result = NS_SUCCEEDED(GetParameter("MAYSCRIPT", &unused));
2316 else
2317 *result = NS_SUCCEEDED(GetAttribute("MAYSCRIPT", &unused));
2319 return NS_OK;
2321 #endif /* OJI */
2323 // Cache the attributes and/or parameters of our tag into a single set
2324 // of arrays to be compatible with 4.x. The attributes go first,
2325 // followed by a PARAM/null and then any PARAM tags. Also, hold the
2326 // cached array around for the duration of the life of the instance
2327 // because 4.x did. See bug 111008.
2329 nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
2331 if (mCachedAttrParamValues)
2332 return NS_OK;
2334 NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) &&
2335 !mCachedAttrParamNames,
2336 "re-cache of attrs/params not implemented! use the DOM "
2337 "node directy instead");
2338 NS_ENSURE_TRUE(mOwner, NS_ERROR_NULL_POINTER);
2340 // first, we need to find out how much we need to allocate for our
2341 // arrays count up attributes
2342 mNumCachedAttrs = 0;
2344 PRUint32 cattrs = mContent->GetAttrCount();
2346 if (cattrs < 0x0000FFFF) {
2347 // unsigned 32 bits to unsigned 16 bits conversion
2348 mNumCachedAttrs = NS_STATIC_CAST(PRUint16, cattrs);
2349 } else {
2350 mNumCachedAttrs = 0xFFFE; // minus one in case we add an extra "src" entry below
2353 // now, we need to find all the PARAM tags that are children of us
2354 // however, be carefull NOT to include any PARAMs that don't have us
2355 // as a direct parent. For nested object (or applet) tags, be sure
2356 // to only round up the param tags that coorespond with THIS
2357 // instance. And also, weed out any bogus tags that may get in the
2358 // way, see bug 39609. Then, with any param tag that meet our
2359 // qualification, temporarly cache them in an nsCOMArray until
2360 // we can figure out what size to make our fixed char* array.
2362 mNumCachedParams = 0;
2363 nsCOMArray<nsIDOMElement> ourParams;
2365 // use the DOM to get us ALL our dependent PARAM tags, even if not
2366 // ours
2367 nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(mContent);
2368 NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE);
2370 nsCOMPtr<nsIDOMNodeList> allParams;
2372 nsINodeInfo *ni = mContent->NodeInfo();
2374 // Making DOM method calls can cause our frame to go away, which
2375 // might kill us...
2376 nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
2378 if (ni->NamespaceEquals(kNameSpaceID_XHTML)) {
2379 // For XHTML elements we need to take the namespace URI into
2380 // account when looking for param elements.
2382 NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
2384 mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"),
2385 getter_AddRefs(allParams));
2386 } else {
2387 // If content is not XHTML, it must be HTML, no need to worry
2388 // about namespaces then...
2390 mydomElement->GetElementsByTagName(NS_LITERAL_STRING("param"),
2391 getter_AddRefs(allParams));
2394 if (allParams) {
2395 PRUint32 numAllParams;
2396 allParams->GetLength(&numAllParams);
2397 // loop through every so called dependent PARAM tag to check if it
2398 // "belongs" to us
2400 for (PRUint32 i = 0; i < numAllParams; i++) {
2401 nsCOMPtr<nsIDOMNode> pnode;
2402 allParams->Item(i, getter_AddRefs(pnode));
2404 nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
2405 if (domelement) {
2406 // let's NOT count up param tags that don't have a name attribute
2407 nsAutoString name;
2408 domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
2409 if (!name.IsEmpty()) {
2410 nsCOMPtr<nsIDOMNode> parent;
2411 nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
2412 nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
2413 pnode->GetParentNode(getter_AddRefs(parent));
2414 // walk up the parents of this PARAM until we find an object
2415 // (or applet) tag
2417 while (!(domobject || domapplet) && parent) {
2418 domobject = do_QueryInterface(parent);
2419 domapplet = do_QueryInterface(parent);
2420 nsCOMPtr<nsIDOMNode> temp;
2421 parent->GetParentNode(getter_AddRefs(temp));
2422 parent = temp;
2425 if (domapplet || domobject) {
2426 if (domapplet)
2427 parent = domapplet;
2428 else
2429 parent = domobject;
2431 // now check to see if this PARAM's parent is us. if so,
2432 // cache it for later
2434 nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(mydomElement);
2435 if (parent == mydomNode) {
2436 ourParams.AppendObject(domelement);
2444 // We're done with DOM method calls now; make sure we still have a frame.
2445 NS_ENSURE_TRUE(mOwner, NS_ERROR_OUT_OF_MEMORY);
2447 PRUint32 cparams = ourParams.Count(); // unsigned 32 bits to unsigned 16 bits conversion
2448 if (cparams < 0x0000FFFF)
2449 mNumCachedParams = NS_STATIC_CAST(PRUint16, cparams);
2450 else
2451 mNumCachedParams = 0xFFFF;
2453 // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
2454 // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
2455 // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
2456 // look for "data", lets instead copy the "data" attribute and add another entry
2457 // to the bottom of the array if there isn't already a "src" specified.
2458 PRInt16 numRealAttrs = mNumCachedAttrs;
2459 nsAutoString data;
2460 if (mContent->Tag() == nsGkAtoms::object
2461 && !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::src)
2462 && mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, data)) {
2463 mNumCachedAttrs++;
2466 // now lets make the arrays
2467 mCachedAttrParamNames = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1);
2468 NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY);
2469 mCachedAttrParamValues = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1);
2470 NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY);
2472 // let's fill in our attributes
2473 PRInt16 c = 0;
2475 // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the
2476 // attribute order. So we want to make sure we give the plugin the
2477 // attributes in the order they came in in the source, to be compatible with
2478 // other browsers. Now in HTML, the storage order is the reverse of the
2479 // source order, while in XML and XHTML it's the same as the source order
2480 // (see the AddAttributes functions in the HTML and XML content sinks).
2481 PRInt16 start, end, increment;
2482 if (mContent->IsNodeOfType(nsINode::eHTML) &&
2483 mContent->NodeInfo()->NamespaceEquals(kNameSpaceID_None)) {
2484 // HTML. Walk attributes in reverse order.
2485 start = numRealAttrs - 1;
2486 end = -1;
2487 increment = -1;
2488 } else {
2489 // XHTML or XML. Walk attributes in forward order.
2490 start = 0;
2491 end = numRealAttrs;
2492 increment = 1;
2494 for (PRInt16 index = start; index != end; index += increment) {
2495 const nsAttrName* attrName = mContent->GetAttrNameAt(index);
2496 nsIAtom* atom = attrName->LocalName();
2497 nsAutoString value;
2498 mContent->GetAttr(attrName->NamespaceID(), atom, value);
2499 nsAutoString name;
2500 atom->ToString(name);
2502 FixUpURLS(name, value);
2504 mCachedAttrParamNames [c] = ToNewUTF8String(name);
2505 mCachedAttrParamValues[c] = ToNewUTF8String(value);
2506 c++;
2509 // if the conditions above were met, copy the "data" attribute to a "src" array entry
2510 if (data.Length()) {
2511 mCachedAttrParamNames [mNumCachedAttrs-1] = ToNewUTF8String(NS_LITERAL_STRING("SRC"));
2512 mCachedAttrParamValues[mNumCachedAttrs-1] = ToNewUTF8String(data);
2515 // add our PARAM and null separator
2516 mCachedAttrParamNames [mNumCachedAttrs] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
2517 mCachedAttrParamValues[mNumCachedAttrs] = nsnull;
2519 // now fill in the PARAM name/value pairs from the cached DOM nodes
2520 c = 0;
2521 for (PRInt16 idx = 0; idx < mNumCachedParams; idx++) {
2522 nsIDOMElement* param = ourParams.ObjectAt(idx);
2523 if (param) {
2524 nsAutoString name;
2525 nsAutoString value;
2526 param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above
2527 param->GetAttribute(NS_LITERAL_STRING("value"), value);
2529 FixUpURLS(name, value);
2532 * According to the HTML 4.01 spec, at
2533 * http://www.w3.org/TR/html4/types.html#type-cdata
2534 * ''User agents may ignore leading and trailing
2535 * white space in CDATA attribute values (e.g., "
2536 * myval " may be interpreted as "myval"). Authors
2537 * should not declare attribute values with
2538 * leading or trailing white space.''
2539 * However, do not trim consecutive spaces as in bug 122119
2541 name.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE);
2542 value.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE);
2543 mCachedAttrParamNames [mNumCachedAttrs + 1 + c] = ToNewUTF8String(name);
2544 mCachedAttrParamValues[mNumCachedAttrs + 1 + c] = ToNewUTF8String(value);
2545 c++; // rules!
2549 return NS_OK;
2553 // Here's where we forward events to plugins.
2555 #ifdef XP_MACOSX
2557 static void InitializeEventRecord(EventRecord* event)
2559 memset(event, 0, sizeof(EventRecord));
2560 ::GetGlobalMouse(&event->where);
2561 event->when = ::TickCount();
2562 event->modifiers = ::GetCurrentKeyModifiers();
2565 NPDrawingModel nsPluginInstanceOwner::GetDrawingModel()
2567 #ifndef NP_NO_QUICKDRAW
2568 NPDrawingModel drawingModel = NPDrawingModelQuickDraw;
2569 #else
2570 NPDrawingModel drawingModel = NPDrawingModelCoreGraphics;
2571 #endif
2573 if (!mInstance)
2574 return drawingModel;
2576 mInstance->GetValue(nsPluginInstanceVariable_DrawingModel,
2577 (void *)&drawingModel);
2579 return drawingModel;
2582 void nsPluginInstanceOwner::GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord* origEvent, EventRecord& aMacEvent)
2584 nsPresContext* presContext = mOwner ? mOwner->PresContext() : nsnull;
2585 InitializeEventRecord(&aMacEvent);
2586 switch (anEvent.message) {
2587 case NS_FOCUS_EVENT_START: // this is the same as NS_FOCUS_CONTENT
2588 aMacEvent.what = nsPluginEventType_GetFocusEvent;
2589 if (presContext) {
2590 nsIContent* content = mContent;
2591 if (content)
2592 content->SetFocus(presContext);
2594 break;
2596 case NS_BLUR_CONTENT:
2597 aMacEvent.what = nsPluginEventType_LoseFocusEvent;
2598 if (presContext) {
2599 nsIContent* content = mContent;
2600 if (content)
2601 content->RemoveFocus(presContext);
2603 break;
2605 case NS_MOUSE_MOVE:
2606 case NS_MOUSE_ENTER:
2607 if (origEvent)
2608 aMacEvent = *origEvent;
2609 aMacEvent.what = nsPluginEventType_AdjustCursorEvent;
2610 break;
2614 #endif
2616 nsresult nsPluginInstanceOwner::ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
2618 #ifdef XP_MACOSX
2619 CancelTimer();
2621 if (mInstance) {
2622 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2623 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
2624 EventRecord scrollEvent;
2625 InitializeEventRecord(&scrollEvent);
2626 scrollEvent.what = nsPluginEventType_ScrollingBeginsEvent;
2628 WindowRef window = FixUpPluginWindow(ePluginPaintDisable);
2629 if (window) {
2630 nsPluginEvent pluginEvent = { &scrollEvent, nsPluginPlatformWindowRef(window) };
2631 PRBool eventHandled = PR_FALSE;
2632 mInstance->HandleEvent(&pluginEvent, &eventHandled);
2634 pluginWidget->EndDrawPlugin();
2637 #endif
2638 return NS_OK;
2641 nsresult nsPluginInstanceOwner::ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
2643 #ifdef XP_MACOSX
2644 if (mInstance) {
2645 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2646 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
2647 EventRecord scrollEvent;
2648 InitializeEventRecord(&scrollEvent);
2649 scrollEvent.what = nsPluginEventType_ScrollingEndsEvent;
2651 WindowRef window = FixUpPluginWindow(ePluginPaintEnable);
2652 if (window) {
2653 nsPluginEvent pluginEvent = { &scrollEvent, nsPluginPlatformWindowRef(window) };
2654 PRBool eventHandled = PR_FALSE;
2655 mInstance->HandleEvent(&pluginEvent, &eventHandled);
2657 pluginWidget->EndDrawPlugin();
2660 // FIXME - Only invalidate the newly revealed amount.
2661 // XXX necessary?
2662 if (mWidget)
2663 mWidget->Invalidate(PR_TRUE);
2665 #endif
2667 StartTimer(NORMAL_PLUGIN_DELAY);
2668 return NS_OK;
2671 /*=============== nsIFocusListener ======================*/
2672 nsresult nsPluginInstanceOwner::Focus(nsIDOMEvent * aFocusEvent)
2674 mContentFocused = PR_TRUE;
2675 return DispatchFocusToPlugin(aFocusEvent);
2678 nsresult nsPluginInstanceOwner::Blur(nsIDOMEvent * aFocusEvent)
2680 mContentFocused = PR_FALSE;
2681 return DispatchFocusToPlugin(aFocusEvent);
2684 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
2686 #ifndef XP_MACOSX
2687 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type) {
2688 // continue only for cases without child window
2689 return aFocusEvent->PreventDefault(); // consume event
2691 #endif
2693 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aFocusEvent));
2694 if (privateEvent) {
2695 nsEvent * theEvent;
2696 privateEvent->GetInternalNSEvent(&theEvent);
2697 if (theEvent) {
2698 // we only care about the message in ProcessEvent
2699 nsGUIEvent focusEvent(NS_IS_TRUSTED_EVENT(theEvent), theEvent->message,
2700 nsnull);
2701 nsEventStatus rv = ProcessEvent(focusEvent);
2702 if (nsEventStatus_eConsumeNoDefault == rv) {
2703 aFocusEvent->PreventDefault();
2704 aFocusEvent->StopPropagation();
2707 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, focusEvent null");
2709 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, privateEvent null");
2711 return NS_OK;
2714 /*=============== nsIDOMDragListener ======================*/
2715 nsresult nsPluginInstanceOwner::DragEnter(nsIDOMEvent* aMouseEvent)
2717 if (mInstance) {
2718 // Let the plugin handle drag events.
2719 aMouseEvent->PreventDefault();
2720 aMouseEvent->StopPropagation();
2723 return NS_OK;
2726 nsresult nsPluginInstanceOwner::DragOver(nsIDOMEvent* aMouseEvent)
2728 if (mInstance) {
2729 // Let the plugin handle drag events.
2730 aMouseEvent->PreventDefault();
2731 aMouseEvent->StopPropagation();
2734 return NS_OK;
2737 nsresult nsPluginInstanceOwner::DragExit(nsIDOMEvent* aMouseEvent)
2739 if (mInstance) {
2740 // Let the plugin handle drag events.
2741 aMouseEvent->PreventDefault();
2742 aMouseEvent->StopPropagation();
2745 return NS_OK;
2748 nsresult nsPluginInstanceOwner::DragDrop(nsIDOMEvent* aMouseEvent)
2750 if (mInstance) {
2751 // Let the plugin handle drag events.
2752 aMouseEvent->PreventDefault();
2753 aMouseEvent->StopPropagation();
2756 return NS_OK;
2759 nsresult nsPluginInstanceOwner::DragGesture(nsIDOMEvent* aMouseEvent)
2761 if (mInstance) {
2762 // Let the plugin handle drag events.
2763 aMouseEvent->PreventDefault();
2764 aMouseEvent->StopPropagation();
2767 return NS_OK;
2770 nsresult nsPluginInstanceOwner::Drag(nsIDOMEvent* aMouseEvent)
2772 if (mInstance) {
2773 // Let the plugin handle drag events.
2774 aMouseEvent->PreventDefault();
2775 aMouseEvent->StopPropagation();
2778 return NS_OK;
2781 nsresult nsPluginInstanceOwner::DragEnd(nsIDOMEvent* aMouseEvent)
2783 if (mInstance) {
2784 // Let the plugin handle drag events.
2785 aMouseEvent->PreventDefault();
2786 aMouseEvent->StopPropagation();
2789 return NS_OK;
2794 /*=============== nsIKeyListener ======================*/
2795 nsresult nsPluginInstanceOwner::KeyDown(nsIDOMEvent* aKeyEvent)
2797 return DispatchKeyToPlugin(aKeyEvent);
2800 nsresult nsPluginInstanceOwner::KeyUp(nsIDOMEvent* aKeyEvent)
2802 return DispatchKeyToPlugin(aKeyEvent);
2805 nsresult nsPluginInstanceOwner::KeyPress(nsIDOMEvent* aKeyEvent)
2807 #ifdef XP_MACOSX // send KeyPress events only on Mac
2809 // KeyPress events are really synthesized keyDown events.
2810 // Here we check the native message of the event so that
2811 // we won't send the plugin two keyDown events.
2812 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
2813 if (privateEvent) {
2814 nsEvent *theEvent;
2815 privateEvent->GetInternalNSEvent(&theEvent);
2816 const nsGUIEvent *guiEvent = (nsGUIEvent*)theEvent;
2817 const EventRecord *ev = (EventRecord*)(guiEvent->nativeMsg);
2818 if (guiEvent &&
2819 guiEvent->message == NS_KEY_PRESS &&
2820 ev &&
2821 ev->what == keyDown)
2822 return aKeyEvent->PreventDefault(); // consume event
2825 // Nasty hack to avoid recursive event dispatching with Java. Java can
2826 // dispatch key events to a TSM handler, which comes back and calls
2827 // [ChildView insertText:] on the cocoa widget, which sends a key
2828 // event back down.
2829 static PRBool sInKeyDispatch = PR_FALSE;
2831 if (sInKeyDispatch)
2832 return aKeyEvent->PreventDefault(); // consume event
2834 sInKeyDispatch = PR_TRUE;
2835 nsresult rv = DispatchKeyToPlugin(aKeyEvent);
2836 sInKeyDispatch = PR_FALSE;
2837 return rv;
2838 #else
2839 if (mInstance) {
2840 // If this event is going to the plugin, we want to kill it.
2841 // Not actually sending keypress to the plugin, since we didn't before.
2842 aKeyEvent->PreventDefault();
2843 aKeyEvent->StopPropagation();
2845 return NS_OK;
2846 #endif
2849 nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent)
2851 #ifndef XP_MACOSX
2852 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
2853 return aKeyEvent->PreventDefault(); // consume event
2854 // continue only for cases without child window
2855 #endif
2857 if (mInstance) {
2858 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
2859 if (privateEvent) {
2860 nsKeyEvent* keyEvent = nsnull;
2861 privateEvent->GetInternalNSEvent((nsEvent**)&keyEvent);
2862 if (keyEvent) {
2863 nsEventStatus rv = ProcessEvent(*keyEvent);
2864 if (nsEventStatus_eConsumeNoDefault == rv) {
2865 aKeyEvent->PreventDefault();
2866 aKeyEvent->StopPropagation();
2869 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, keyEvent null");
2871 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, privateEvent null");
2874 return NS_OK;
2877 /*=============== nsIMouseMotionListener ======================*/
2879 nsresult
2880 nsPluginInstanceOwner::MouseMove(nsIDOMEvent* aMouseEvent)
2882 #if !defined(XP_MACOSX)
2883 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
2884 return aMouseEvent->PreventDefault(); // consume event
2885 // continue only for cases without child window
2886 #endif
2888 // don't send mouse events if we are hiddden
2889 if (!mWidgetVisible)
2890 return NS_OK;
2892 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
2893 if (privateEvent) {
2894 nsMouseEvent* mouseEvent = nsnull;
2895 privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
2896 if (mouseEvent) {
2897 nsEventStatus rv = ProcessEvent(*mouseEvent);
2898 if (nsEventStatus_eConsumeNoDefault == rv) {
2899 return aMouseEvent->PreventDefault(); // consume event
2902 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, mouseEvent null");
2904 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, privateEvent null");
2906 return NS_OK;
2909 /*=============== nsIMouseListener ======================*/
2911 nsresult
2912 nsPluginInstanceOwner::MouseDown(nsIDOMEvent* aMouseEvent)
2914 #if !defined(XP_MACOSX)
2915 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
2916 return aMouseEvent->PreventDefault(); // consume event
2917 // continue only for cases without child window
2918 #endif
2920 // if the plugin is windowless, we need to set focus ourselves
2921 // otherwise, we might not get key events
2922 if (mOwner && mPluginWindow &&
2923 mPluginWindow->type == nsPluginWindowType_Drawable) {
2924 mContent->SetFocus(mOwner->PresContext());
2927 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
2928 if (privateEvent) {
2929 nsMouseEvent* mouseEvent = nsnull;
2930 privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
2931 if (mouseEvent) {
2932 nsEventStatus rv = ProcessEvent(*mouseEvent);
2933 if (nsEventStatus_eConsumeNoDefault == rv) {
2934 return aMouseEvent->PreventDefault(); // consume event
2937 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, mouseEvent null");
2939 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, privateEvent null");
2941 return NS_OK;
2944 nsresult
2945 nsPluginInstanceOwner::MouseUp(nsIDOMEvent* aMouseEvent)
2947 return DispatchMouseToPlugin(aMouseEvent);
2950 nsresult
2951 nsPluginInstanceOwner::MouseClick(nsIDOMEvent* aMouseEvent)
2953 return DispatchMouseToPlugin(aMouseEvent);
2956 nsresult
2957 nsPluginInstanceOwner::MouseDblClick(nsIDOMEvent* aMouseEvent)
2959 return DispatchMouseToPlugin(aMouseEvent);
2962 nsresult
2963 nsPluginInstanceOwner::MouseOver(nsIDOMEvent* aMouseEvent)
2965 return DispatchMouseToPlugin(aMouseEvent);
2968 nsresult
2969 nsPluginInstanceOwner::MouseOut(nsIDOMEvent* aMouseEvent)
2971 return DispatchMouseToPlugin(aMouseEvent);
2974 nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent)
2976 #if !defined(XP_MACOSX)
2977 if (!mPluginWindow || nsPluginWindowType_Window == mPluginWindow->type)
2978 return aMouseEvent->PreventDefault(); // consume event
2979 // continue only for cases without child window
2980 #endif
2982 // don't send mouse events if we are hiddden
2983 if (!mWidgetVisible)
2984 return NS_OK;
2986 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
2987 if (privateEvent) {
2988 nsMouseEvent* mouseEvent = nsnull;
2989 privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
2990 if (mouseEvent) {
2991 nsEventStatus rv = ProcessEvent(*mouseEvent);
2992 if (nsEventStatus_eConsumeNoDefault == rv) {
2993 aMouseEvent->PreventDefault();
2994 aMouseEvent->StopPropagation();
2997 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, mouseEvent null");
2999 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, privateEvent null");
3001 return NS_OK;
3004 nsresult
3005 nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
3007 return NS_OK;
3011 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
3013 // printf("nsGUIEvent.message: %d\n", anEvent.message);
3014 nsEventStatus rv = nsEventStatus_eIgnore;
3015 if (!mInstance) // if mInstance is null, we shouldn't be here
3016 return rv;
3018 #ifdef XP_MACOSX
3019 // check for null mWidget
3020 if (mWidget) {
3021 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3022 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
3023 EventRecord macEvent;
3024 EventRecord* event = (EventRecord*)anEvent.nativeMsg;
3025 if ((event == NULL) || (event->what == nullEvent) ||
3026 (anEvent.message == NS_FOCUS_CONTENT) ||
3027 (anEvent.message == NS_BLUR_CONTENT) ||
3028 (anEvent.message == NS_MOUSE_MOVE) ||
3029 (anEvent.message == NS_MOUSE_ENTER)) {
3030 GUItoMacEvent(anEvent, event, macEvent);
3031 event = &macEvent;
3034 if (anEvent.message == NS_FOCUS_CONTENT) {
3035 // Work around an issue in the Flash plugin, which can cache a pointer
3036 // to a doomed TSM document (one that belongs to a NSTSMInputContext)
3037 // and try to activate it after it has been deleted. See bug 183313.
3038 ::DeactivateTSMDocument(::TSMGetActiveDocument());
3041 PRBool eventHandled = PR_FALSE;
3042 WindowRef window = FixUpPluginWindow(ePluginPaintIgnore);
3043 if (window) {
3044 nsPluginEvent pluginEvent = { event, nsPluginPlatformWindowRef(window) };
3045 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3048 if (eventHandled && !(anEvent.eventStructType == NS_MOUSE_EVENT &&
3049 anEvent.message == NS_MOUSE_BUTTON_DOWN &&
3050 NS_STATIC_CAST(const nsMouseEvent&, anEvent).button ==
3051 nsMouseEvent::eLeftButton &&
3052 !mContentFocused))
3053 rv = nsEventStatus_eConsumeNoDefault;
3055 pluginWidget->EndDrawPlugin();
3058 #endif
3060 #ifdef XP_WIN
3061 // this code supports windowless plugins
3062 nsPluginEvent * pPluginEvent = (nsPluginEvent *)anEvent.nativeMsg;
3063 // we can get synthetic events from the nsEventStateManager... these
3064 // have no nativeMsg
3065 nsPluginEvent pluginEvent;
3066 if (!pPluginEvent) {
3067 switch (anEvent.message) {
3068 case NS_FOCUS_CONTENT:
3069 pluginEvent.event = WM_SETFOCUS;
3070 pluginEvent.wParam = 0;
3071 pluginEvent.lParam = 0;
3072 pPluginEvent = &pluginEvent;
3073 break;
3074 case NS_BLUR_CONTENT:
3075 pluginEvent.event = WM_KILLFOCUS;
3076 pluginEvent.wParam = 0;
3077 pluginEvent.lParam = 0;
3078 pPluginEvent = &pluginEvent;
3079 break;
3083 if (pPluginEvent) {
3084 PRBool eventHandled = PR_FALSE;
3085 mInstance->HandleEvent(pPluginEvent, &eventHandled);
3086 if (eventHandled)
3087 rv = nsEventStatus_eConsumeNoDefault;
3089 #endif
3091 return rv;
3094 nsresult
3095 nsPluginInstanceOwner::Destroy()
3097 // stop the timer explicitly to reduce reference count.
3098 CancelTimer();
3100 // unregister context menu listener
3101 if (mCXMenuListener) {
3102 mCXMenuListener->Destroy(mContent);
3103 NS_RELEASE(mCXMenuListener);
3106 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mContent));
3107 if (target) {
3109 nsCOMPtr<nsIDOMEventListener> listener;
3110 QueryInterface(NS_GET_IID(nsIDOMEventListener), getter_AddRefs(listener));
3112 // Unregister focus event listener
3113 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMFocusListener));
3115 // Unregister mouse event listener
3116 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseListener));
3118 // now for the mouse motion listener
3119 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseMotionListener));
3121 // Unregister key event listener;
3122 target->RemoveEventListener(NS_LITERAL_STRING("keypress"), listener, PR_TRUE);
3123 target->RemoveEventListener(NS_LITERAL_STRING("keydown"), listener, PR_TRUE);
3124 target->RemoveEventListener(NS_LITERAL_STRING("keyup"), listener, PR_TRUE);
3126 // Unregister drag event listener;
3127 target->RemoveEventListener(NS_LITERAL_STRING("dragdrop"), listener, PR_TRUE);
3128 target->RemoveEventListener(NS_LITERAL_STRING("dragover"), listener, PR_TRUE);
3129 target->RemoveEventListener(NS_LITERAL_STRING("dragexit"), listener, PR_TRUE);
3130 target->RemoveEventListener(NS_LITERAL_STRING("dragenter"), listener, PR_TRUE);
3131 target->RemoveEventListener(NS_LITERAL_STRING("draggesture"), listener, PR_TRUE);
3134 // Unregister scroll position listener
3135 nsIFrame* parentWithView = mOwner->GetAncestorWithView();
3136 nsIView* curView = parentWithView ? parentWithView->GetView() : nsnull;
3137 while (curView) {
3138 nsIScrollableView* scrollingView = curView->ToScrollableView();
3139 if (scrollingView)
3140 scrollingView->RemoveScrollPositionListener((nsIScrollPositionListener *)this);
3142 curView = curView->GetParent();
3145 mOwner = nsnull; // break relationship between frame and plugin instance owner
3147 return NS_OK;
3150 // Paints are handled differently, so we just simulate an update event.
3152 void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect, PRUint32 ndc)
3154 if (!mInstance || !mOwner)
3155 return;
3157 #ifdef XP_MACOSX
3158 #ifdef DO_DIRTY_INTERSECT // aDirtyRect isn't always correct, see bug 56128
3159 nsPoint rel(aDirtyRect.x, aDirtyRect.y);
3160 nsPoint abs(0,0);
3161 nsCOMPtr<nsIWidget> containerWidget;
3163 // Convert dirty rect relative coordinates to absolute and also get the containerWidget
3164 ConvertRelativeToWindowAbsolute(mOwner, rel, abs, *getter_AddRefs(containerWidget));
3166 nsRect absDirtyRect = nsRect(abs.x, abs.y, aDirtyRect.width, aDirtyRect.height);
3168 // Convert to absolute pixel values for the dirty rect
3169 nsRect absDirtyRectInPixels;
3170 ConvertAppUnitsToPixels(*mOwner->GetPresContext(), absDirtyRect,
3171 absDirtyRectInPixels);
3172 #endif
3174 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3175 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
3176 WindowRef window = FixUpPluginWindow(ePluginPaintEnable);
3177 if (window) {
3178 EventRecord updateEvent;
3179 InitializeEventRecord(&updateEvent);
3180 updateEvent.what = updateEvt;
3181 updateEvent.message = UInt32(window);
3183 nsPluginEvent pluginEvent = { &updateEvent, nsPluginPlatformWindowRef(window) };
3184 PRBool eventHandled = PR_FALSE;
3185 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3187 pluginWidget->EndDrawPlugin();
3189 #endif
3191 #ifdef XP_WIN
3192 nsPluginWindow * window;
3193 GetWindow(window);
3194 nsRect relDirtyRect = nsRect(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
3195 nsRect relDirtyRectInPixels;
3196 ConvertAppUnitsToPixels(*mOwner->PresContext(), relDirtyRect,
3197 relDirtyRectInPixels);
3199 // we got dirty rectangle in relative window coordinates, but we
3200 // need it in absolute units and in the (left, top, right, bottom) form
3201 RECT drc;
3202 drc.left = relDirtyRectInPixels.x + window->x;
3203 drc.top = relDirtyRectInPixels.y + window->y;
3204 drc.right = drc.left + relDirtyRectInPixels.width;
3205 drc.bottom = drc.top + relDirtyRectInPixels.height;
3207 nsPluginEvent pluginEvent;
3208 pluginEvent.event = WM_PAINT;
3209 pluginEvent.wParam = (uint32)ndc;
3210 pluginEvent.lParam = (uint32)&drc;
3211 PRBool eventHandled = PR_FALSE;
3212 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3213 #endif
3216 // Here's how we give idle time to plugins.
3218 NS_IMETHODIMP nsPluginInstanceOwner::Notify(nsITimer* /* timer */)
3220 #ifdef XP_MACOSX
3221 // validate the plugin clipping information by syncing the plugin window info to
3222 // reflect the current widget location. This makes sure that everything is updated
3223 // correctly in the event of scrolling in the window.
3224 if (mInstance) {
3225 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3226 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
3227 WindowRef window = FixUpPluginWindow(ePluginPaintIgnore);
3228 if (window) {
3229 EventRecord idleEvent;
3230 InitializeEventRecord(&idleEvent);
3231 idleEvent.what = nullEvent;
3233 // give a bogus 'where' field of our null event when hidden, so Flash
3234 // won't respond to mouse moves in other tabs, see bug 120875
3235 if (!mWidgetVisible)
3236 idleEvent.where.h = idleEvent.where.v = 20000;
3238 nsPluginEvent pluginEvent = { &idleEvent, nsPluginPlatformWindowRef(window) };
3240 PRBool eventHandled = PR_FALSE;
3241 mInstance->HandleEvent(&pluginEvent, &eventHandled);
3244 pluginWidget->EndDrawPlugin();
3247 #endif
3248 return NS_OK;
3251 void nsPluginInstanceOwner::StartTimer(unsigned int aDelay)
3253 #ifdef XP_MACOSX
3254 nsresult rv;
3256 // start a periodic timer to provide null events to the plugin instance.
3257 if (!mPluginTimer) {
3258 mPluginTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
3259 if (NS_SUCCEEDED(rv))
3260 mPluginTimer->InitWithCallback(this, aDelay, nsITimer::TYPE_REPEATING_SLACK);
3262 #endif
3265 void nsPluginInstanceOwner::CancelTimer()
3267 if (mPluginTimer) {
3268 mPluginTimer->Cancel();
3269 mPluginTimer = nsnull;
3273 nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext,
3274 nsObjectFrame* aFrame,
3275 nsIContent* aContent)
3277 mOwner = aFrame;
3278 mContent = aContent;
3280 // Some plugins require a specific sequence of shutdown and startup when
3281 // a page is reloaded. Shutdown happens usually when the last instance
3282 // is destroyed. Here we make sure the plugin instance in the old
3283 // document is destroyed before we try to create the new one.
3284 aPresContext->EnsureVisible(PR_TRUE);
3286 // register context menu listener
3287 mCXMenuListener = new nsPluginDOMContextMenuListener();
3288 if (mCXMenuListener) {
3289 NS_ADDREF(mCXMenuListener);
3290 mCXMenuListener->Init(aContent);
3293 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mContent));
3294 if (target) {
3296 nsCOMPtr<nsIDOMEventListener> listener;
3297 QueryInterface(NS_GET_IID(nsIDOMEventListener), getter_AddRefs(listener));
3299 // Register focus listener
3300 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMFocusListener));
3302 // Register mouse listener
3303 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseListener));
3305 // now do the mouse motion listener
3306 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseMotionListener));
3308 // Register key listener
3309 target->AddEventListener(NS_LITERAL_STRING("keypress"), listener, PR_TRUE);
3310 target->AddEventListener(NS_LITERAL_STRING("keydown"), listener, PR_TRUE);
3311 target->AddEventListener(NS_LITERAL_STRING("keyup"), listener, PR_TRUE);
3313 // Register drag listener
3314 target->AddEventListener(NS_LITERAL_STRING("dragdrop"), listener, PR_TRUE);
3315 target->AddEventListener(NS_LITERAL_STRING("dragover"), listener, PR_TRUE);
3316 target->AddEventListener(NS_LITERAL_STRING("dragexit"), listener, PR_TRUE);
3317 target->AddEventListener(NS_LITERAL_STRING("dragenter"), listener, PR_TRUE);
3318 target->AddEventListener(NS_LITERAL_STRING("draggesture"), listener, PR_TRUE);
3321 // Register scroll position listener
3322 // We need to register a scroll pos listener on every scrollable
3323 // view up to the top
3324 nsIFrame* parentWithView = mOwner->GetAncestorWithView();
3325 nsIView* curView = parentWithView ? parentWithView->GetView() : nsnull;
3326 while (curView) {
3327 nsIScrollableView* scrollingView = curView->ToScrollableView();
3328 if (scrollingView)
3329 scrollingView->AddScrollPositionListener((nsIScrollPositionListener *)this);
3331 curView = curView->GetParent();
3334 return NS_OK;
3337 nsPluginPort* nsPluginInstanceOwner::GetPluginPort()
3339 //!!! Port must be released for windowless plugins on Windows, because it is HDC !!!
3341 nsPluginPort* result = NULL;
3342 if (mWidget) {
3343 #ifdef XP_WIN
3344 if (mPluginWindow && mPluginWindow->type == nsPluginWindowType_Drawable)
3345 result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_GRAPHIC);
3346 else
3347 #endif
3348 #ifdef XP_MACOSX
3349 if (GetDrawingModel() == NPDrawingModelCoreGraphics)
3350 result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT_CG);
3351 else
3352 #endif
3353 result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
3355 return result;
3358 void nsPluginInstanceOwner::ReleasePluginPort(nsPluginPort * pluginPort)
3360 #ifdef XP_WIN
3361 if (mWidget && mPluginWindow &&
3362 mPluginWindow->type == nsPluginWindowType_Drawable) {
3363 mWidget->FreeNativeData((HDC)pluginPort, NS_NATIVE_GRAPHIC);
3365 #endif
3368 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
3370 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
3372 nsIView *view;
3373 nsresult rv = NS_ERROR_FAILURE;
3375 if (mOwner) {
3376 // Create view if necessary
3378 view = mOwner->GetView();
3380 if (!view || !mWidget) {
3381 PRBool windowless = PR_FALSE;
3383 mInstance->GetValue(nsPluginInstanceVariable_WindowlessBool,
3384 (void *)&windowless);
3386 // always create widgets in Twips, not pixels
3387 nsPresContext* context = mOwner->PresContext();
3388 rv = mOwner->CreateWidget(context->DevPixelsToAppUnits(mPluginWindow->width),
3389 context->DevPixelsToAppUnits(mPluginWindow->height),
3390 windowless);
3391 if (NS_OK == rv) {
3392 view = mOwner->GetView();
3394 if (view) {
3395 mWidget = view->GetWidget();
3398 if (PR_TRUE == windowless) {
3399 mPluginWindow->type = nsPluginWindowType_Drawable;
3401 // this needs to be a HDC according to the spec, but I do
3402 // not see the right way to release it so let's postpone
3403 // passing HDC till paint event when it is really
3404 // needed. Change spec?
3405 mPluginWindow->window = nsnull;
3406 } else if (mWidget) {
3407 mWidget->Resize(mPluginWindow->width, mPluginWindow->height,
3408 PR_FALSE);
3410 // mPluginWindow->type is used in |GetPluginPort| so it must
3411 // be initilized first
3412 mPluginWindow->type = nsPluginWindowType_Window;
3413 mPluginWindow->window = GetPluginPort();
3415 // start the idle timer.
3416 StartTimer(NORMAL_PLUGIN_DELAY);
3418 // tell the plugin window about the widget
3419 mPluginWindow->SetPluginWidget(mWidget);
3425 return rv;
3428 void nsPluginInstanceOwner::SetPluginHost(nsIPluginHost* aHost)
3430 mPluginHost = aHost;
3433 #if defined(XP_WIN) || (defined(DO_DIRTY_INTERSECT) && defined(XP_MACOSX))
3434 // convert frame coordinates from twips to pixels
3435 static void ConvertAppUnitsToPixels(nsPresContext& aPresContext, nsRect& aTwipsRect, nsRect& aPixelRect)
3437 aPixelRect.x = aPresContext.AppUnitsToDevPixels(aTwipsRect.x);
3438 aPixelRect.y = aPresContext.AppUnitsToDevPixels(aTwipsRect.y);
3439 aPixelRect.width = aPresContext.AppUnitsToDevPixels(aTwipsRect.width);
3440 aPixelRect.height = aPresContext.AppUnitsToDevPixels(aTwipsRect.height);
3442 #endif
3444 // Mac specific code to fix up the port location and clipping region
3445 #ifdef XP_MACOSX
3447 #ifdef DO_DIRTY_INTERSECT
3448 // Convert from a frame relative coordinate to a coordinate relative to its
3449 // containing window
3450 static void ConvertRelativeToWindowAbsolute(nsIFrame* aFrame,
3451 nsPoint& aRel,
3452 nsPoint& aAbs,
3453 nsIWidget*& aContainerWidget)
3455 // See if this frame has a view
3456 nsIView *view = aFrame->GetView();
3457 if (!view) {
3458 aAbs.x = 0;
3459 aAbs.y = 0;
3460 // Calculate frames offset from its nearest view
3461 aFrame->GetOffsetFromView(aAbs, &view);
3462 } else {
3463 // Store frames offset from its view.
3464 aAbs = aFrame->GetPosition();
3467 NS_ASSERTION(view, "the object frame does not have a view");
3468 if (view) {
3469 // Calculate the view's offset from its nearest widget
3470 nsPoint viewOffset;
3471 aContainerWidget = view->GetNearestWidget(&viewOffset);
3472 NS_IF_ADDREF(aContainerWidget);
3473 aAbs += viewOffset;
3476 // Add relative coordinate to the absolute coordinate that has been calculated
3477 aAbs += aRel;
3479 #endif // DO_DIRTY_INTERSECT
3481 WindowRef nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState)
3483 if (!mWidget || !mPluginWindow || !mInstance)
3484 return nsnull;
3486 nsPluginPort* pluginPort = GetPluginPort();
3488 if (!pluginPort)
3489 return nsnull;
3491 NPDrawingModel drawingModel = GetDrawingModel();
3493 // first, check our view for CSS visibility style
3494 PRBool isVisible =
3495 mOwner->GetView()->GetVisibility() == nsViewVisibility_kShow;
3497 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3499 nsPoint pluginOrigin;
3500 nsRect widgetClip;
3501 PRBool widgetVisible;
3502 pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin, /* out */ widgetVisible);
3504 // printf("GetPluginClipRect returning visible %d\n", widgetVisible);
3506 isVisible &= widgetVisible;
3507 if (!isVisible)
3508 widgetClip.Empty();
3510 #ifndef NP_NO_QUICKDRAW
3511 // set the port coordinates
3512 if (drawingModel == NPDrawingModelQuickDraw) {
3513 mPluginWindow->x = -pluginPort->qdPort.portx;
3514 mPluginWindow->y = -pluginPort->qdPort.porty;
3516 else if (drawingModel == NPDrawingModelCoreGraphics)
3517 #endif
3519 // This would be a lot easier if we could use obj-c here,
3520 // but we can't. Since we have only nsIWidget and we can't
3521 // use its native widget (an obj-c object) we have to go
3522 // from the widget's screen coordinates to its window coords
3523 // instead of straight to window coords.
3524 nsRect geckoBounds;
3525 mWidget->GetBounds(geckoBounds);
3526 // we need a rect that is the entire *internal* rect, so the
3527 // x and y coords are 0, width is the same.
3528 geckoBounds.x = 0;
3529 geckoBounds.y = 0;
3530 nsRect geckoScreenCoords;
3531 mWidget->WidgetToScreen(geckoBounds, geckoScreenCoords);
3533 Rect windowRect;
3534 WindowRef window = (WindowRef)pluginPort->cgPort.window;
3535 ::GetWindowBounds(window, kWindowStructureRgn, &windowRect);
3537 mPluginWindow->x = geckoScreenCoords.x - windowRect.left;
3538 mPluginWindow->y = geckoScreenCoords.y - windowRect.top;
3541 nsPluginRect oldClipRect = mPluginWindow->clipRect;
3543 // fix up the clipping region
3544 mPluginWindow->clipRect.top = widgetClip.y;
3545 mPluginWindow->clipRect.left = widgetClip.x;
3547 mWidgetVisible = isVisible;
3549 if (!mWidgetVisible || inPaintState == ePluginPaintDisable) {
3550 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
3551 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
3552 // pluginPort = nsnull; // don't uncomment this
3554 else if (inPaintState == ePluginPaintEnable)
3556 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height;
3557 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left + widgetClip.width;
3560 // if the clip rect changed, call SetWindow()
3561 // (RealPlayer needs this to draw correctly)
3562 if (mPluginWindow->clipRect.left != oldClipRect.left ||
3563 mPluginWindow->clipRect.top != oldClipRect.top ||
3564 mPluginWindow->clipRect.right != oldClipRect.right ||
3565 mPluginWindow->clipRect.bottom != oldClipRect.bottom)
3567 mInstance->SetWindow(mPluginWindow);
3568 // if the clipRect is of size 0, make the null timer fire less often
3569 CancelTimer();
3570 if (mPluginWindow->clipRect.left == mPluginWindow->clipRect.right ||
3571 mPluginWindow->clipRect.top == mPluginWindow->clipRect.bottom) {
3572 StartTimer(HIDDEN_PLUGIN_DELAY);
3574 else {
3575 StartTimer(NORMAL_PLUGIN_DELAY);
3579 #ifndef NP_NO_QUICKDRAW
3580 if (drawingModel == NPDrawingModelQuickDraw)
3581 return ::GetWindowFromPort(pluginPort->qdPort.port);
3582 #endif
3584 if (drawingModel == NPDrawingModelCoreGraphics)
3585 return pluginPort->cgPort.window;
3587 return nsnull;
3590 #endif // XP_MACOSX
3592 // Little helper function to resolve relative URL in
3593 // |value| for certain inputs of |name|
3594 void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
3596 if (name.LowerCaseEqualsLiteral("pluginurl") ||
3597 name.LowerCaseEqualsLiteral("pluginspage")) {
3599 nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
3600 nsAutoString newURL;
3601 NS_MakeAbsoluteURI(newURL, value, baseURI);
3602 if (!newURL.IsEmpty())
3603 value = newURL;