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
5 : *
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/
10 : *
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.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
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.
22 : *
23 : * Contributor(s):
24 : * Pierre Phaneuf <pp@ludusdesign.com>
25 : * Jacek Piskozub <piskozub@iopan.gda.pl>
26 : * Leon Sha <leon.sha@sun.com>
27 : * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
28 : * Robert O'Callahan <roc+moz@cs.cmu.edu>
29 : * Christian Biesinger <cbiesinger@web.de>
30 : * Josh Aas <josh@mozilla.com>
31 : * Mats Palmgren <matspal@gmail.com>
32 : *
33 : * Alternatively, the contents of this file may be used under the terms of
34 : * either of the GNU General Public License Version 2 or later (the "GPL"),
35 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 : * in which case the provisions of the GPL or the LGPL are applicable instead
37 : * of those above. If you wish to allow use of your version of this file only
38 : * under the terms of either the GPL or the LGPL, and not to allow others to
39 : * use your version of this file under the terms of the MPL, indicate your
40 : * decision by deleting the provisions above and replace them with the notice
41 : * and other provisions required by the GPL or the LGPL. If you do not delete
42 : * the provisions above, a recipient may use your version of this file under
43 : * the terms of any one of the MPL, the GPL or the LGPL.
44 : *
45 : * ***** END LICENSE BLOCK ***** */
46 :
47 : /* rendering objects for replaced elements implemented by a plugin */
48 :
49 : #include "mozilla/plugins/PluginMessageUtils.h"
50 :
51 : #include "nscore.h"
52 : #include "nsCOMPtr.h"
53 : #include "nsPresContext.h"
54 : #include "nsIPresShell.h"
55 : #include "nsWidgetsCID.h"
56 : #include "nsIView.h"
57 : #include "nsIViewManager.h"
58 : #include "nsIDOMEventListener.h"
59 : #include "nsIDOMDragEvent.h"
60 : #include "nsPluginHost.h"
61 : #include "nsString.h"
62 : #include "nsReadableUtils.h"
63 : #include "prmem.h"
64 : #include "nsGkAtoms.h"
65 : #include "nsIAppShell.h"
66 : #include "nsIDocument.h"
67 : #include "nsINodeInfo.h"
68 : #include "nsIURL.h"
69 : #include "nsNetUtil.h"
70 : #include "nsIPluginInstanceOwner.h"
71 : #include "nsNPAPIPluginInstance.h"
72 : #include "nsIPluginTagInfo.h"
73 : #include "plstr.h"
74 : #include "nsILinkHandler.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 "nsIDOMEventTarget.h"
88 : #include "nsIDOMNSEvent.h"
89 : #include "nsIPrivateDOMEvent.h"
90 : #include "nsIDocumentEncoder.h"
91 : #include "nsXPIDLString.h"
92 : #include "nsIDOMRange.h"
93 : #include "nsIPluginWidget.h"
94 : #include "nsGUIEvent.h"
95 : #include "nsRenderingContext.h"
96 : #include "npapi.h"
97 : #include "nsTransform2D.h"
98 : #include "nsIImageLoadingContent.h"
99 : #include "nsIObjectLoadingContent.h"
100 : #include "nsPIDOMWindow.h"
101 : #include "nsContentUtils.h"
102 : #include "nsDisplayList.h"
103 : #include "nsAttrName.h"
104 : #include "nsDataHashtable.h"
105 : #include "nsDOMClassInfo.h"
106 : #include "nsFocusManager.h"
107 : #include "nsLayoutUtils.h"
108 : #include "nsFrameManager.h"
109 : #include "nsComponentManagerUtils.h"
110 : #include "nsIObserverService.h"
111 : #include "nsIScrollableFrame.h"
112 : #include "mozilla/Preferences.h"
113 : #include "sampler.h"
114 :
115 : // headers for plugin scriptability
116 : #include "nsIScriptGlobalObject.h"
117 : #include "nsIScriptContext.h"
118 : #include "nsIXPConnect.h"
119 : #include "nsIXPCScriptable.h"
120 : #include "nsIClassInfo.h"
121 : #include "nsIDOMClientRect.h"
122 :
123 : #include "nsObjectFrame.h"
124 : #include "nsIObjectFrame.h"
125 : #include "nsPluginNativeWindow.h"
126 : #include "nsIPluginDocument.h"
127 : #include "FrameLayerBuilder.h"
128 :
129 : #include "nsThreadUtils.h"
130 :
131 : #include "gfxContext.h"
132 : #include "gfxPlatform.h"
133 :
134 : #ifdef XP_WIN
135 : #include "gfxWindowsNativeDrawing.h"
136 : #include "gfxWindowsSurface.h"
137 : #endif
138 :
139 : #include "gfxImageSurface.h"
140 : #include "gfxUtils.h"
141 : #include "Layers.h"
142 : #include "ReadbackLayer.h"
143 :
144 : // accessibility support
145 : #ifdef ACCESSIBILITY
146 : #include "nsAccessibilityService.h"
147 : #endif
148 :
149 : #ifdef MOZ_LOGGING
150 : #define FORCE_PR_LOG 1 /* Allow logging in the release build */
151 : #endif /* MOZ_LOGGING */
152 : #include "prlog.h"
153 :
154 : #include <errno.h>
155 :
156 : #include "nsContentCID.h"
157 : static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
158 :
159 : #ifdef XP_MACOSX
160 : #include "gfxQuartzNativeDrawing.h"
161 : #include "nsPluginUtilsOSX.h"
162 : #include "nsCoreAnimationSupport.h"
163 : #endif
164 :
165 : #ifdef MOZ_WIDGET_GTK2
166 : #include <gdk/gdk.h>
167 : #include <gdk/gdkx.h>
168 : #include <gtk/gtk.h>
169 : #include "gfxXlibNativeRenderer.h"
170 : #endif
171 :
172 : #ifdef MOZ_X11
173 : #include "mozilla/X11Util.h"
174 : using mozilla::DefaultXDisplay;
175 : #endif
176 :
177 : #ifdef XP_WIN
178 : #include <wtypes.h>
179 : #include <winuser.h>
180 : #endif
181 :
182 : #ifdef XP_OS2
183 : #define INCL_PM
184 : #define INCL_GPI
185 : #include <os2.h>
186 : #include "gfxOS2Surface.h"
187 : #endif
188 :
189 : #ifdef CreateEvent // Thank you MS.
190 : #undef CreateEvent
191 : #endif
192 :
193 : #ifdef PR_LOGGING
194 1464 : static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame");
195 : #endif /* PR_LOGGING */
196 :
197 : #if defined(XP_MACOSX) && !defined(NP_NO_CARBON)
198 :
199 : #define MAC_CARBON_PLUGINS
200 :
201 : // The header files QuickdrawAPI.h and QDOffscreen.h are missing on OS X 10.7
202 : // and up (though the QuickDraw APIs defined in them are still present) -- so
203 : // we need to supply the relevant parts of their contents here. It's likely
204 : // that Apple will eventually remove the APIs themselves (probably in OS X
205 : // 10.8), so we need to make them weak imports, and test for their presence
206 : // before using them.
207 : extern "C" {
208 : #if !defined(__QUICKDRAWAPI__)
209 : extern void SetRect(
210 : Rect * r,
211 : short left,
212 : short top,
213 : short right,
214 : short bottom)
215 : __attribute__((weak_import));
216 : #endif /* __QUICKDRAWAPI__ */
217 :
218 : #if !defined(__QDOFFSCREEN__)
219 : extern QDErr NewGWorldFromPtr(
220 : GWorldPtr * offscreenGWorld,
221 : UInt32 PixelFormat,
222 : const Rect * boundsRect,
223 : CTabHandle cTable, /* can be NULL */
224 : GDHandle aGDevice, /* can be NULL */
225 : GWorldFlags flags,
226 : Ptr newBuffer,
227 : SInt32 rowBytes)
228 : __attribute__((weak_import));
229 : extern void DisposeGWorld(GWorldPtr offscreenGWorld)
230 : __attribute__((weak_import));
231 : #endif /* __QDOFFSCREEN__ */
232 : }
233 :
234 : #endif /* #if defined(XP_MACOSX) && !defined(NP_NO_CARBON) */
235 :
236 : using namespace mozilla;
237 : using namespace mozilla::plugins;
238 : using namespace mozilla::layers;
239 :
240 : class PluginBackgroundSink : public ReadbackSink {
241 : public:
242 0 : PluginBackgroundSink(nsObjectFrame* aFrame, PRUint64 aStartSequenceNumber)
243 0 : : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
244 0 : ~PluginBackgroundSink()
245 0 : {
246 0 : if (mFrame) {
247 0 : mFrame->mBackgroundSink = nsnull;
248 : }
249 0 : }
250 :
251 0 : virtual void SetUnknown(PRUint64 aSequenceNumber)
252 : {
253 0 : if (!AcceptUpdate(aSequenceNumber))
254 0 : return;
255 0 : mFrame->mInstanceOwner->SetBackgroundUnknown();
256 : }
257 :
258 : virtual already_AddRefed<gfxContext>
259 0 : BeginUpdate(const nsIntRect& aRect, PRUint64 aSequenceNumber)
260 : {
261 0 : if (!AcceptUpdate(aSequenceNumber))
262 0 : return nsnull;
263 0 : return mFrame->mInstanceOwner->BeginUpdateBackground(aRect);
264 : }
265 :
266 0 : virtual void EndUpdate(gfxContext* aContext, const nsIntRect& aRect)
267 : {
268 0 : return mFrame->mInstanceOwner->EndUpdateBackground(aContext, aRect);
269 : }
270 :
271 0 : void Destroy() { mFrame = nsnull; }
272 :
273 : protected:
274 0 : bool AcceptUpdate(PRUint64 aSequenceNumber) {
275 0 : if (aSequenceNumber > mLastSequenceNumber && mFrame &&
276 : mFrame->mInstanceOwner) {
277 0 : mLastSequenceNumber = aSequenceNumber;
278 0 : return true;
279 : }
280 0 : return false;
281 : }
282 :
283 : PRUint64 mLastSequenceNumber;
284 : nsObjectFrame* mFrame;
285 : };
286 :
287 0 : nsObjectFrame::nsObjectFrame(nsStyleContext* aContext)
288 : : nsObjectFrameSuper(aContext)
289 0 : , mReflowCallbackPosted(false)
290 : {
291 0 : PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
292 : ("Created new nsObjectFrame %p\n", this));
293 0 : }
294 :
295 0 : nsObjectFrame::~nsObjectFrame()
296 : {
297 0 : PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
298 : ("nsObjectFrame %p deleted\n", this));
299 0 : }
300 :
301 0 : NS_QUERYFRAME_HEAD(nsObjectFrame)
302 0 : NS_QUERYFRAME_ENTRY(nsIObjectFrame)
303 0 : NS_QUERYFRAME_TAIL_INHERITING(nsObjectFrameSuper)
304 :
305 : #ifdef ACCESSIBILITY
306 : already_AddRefed<nsAccessible>
307 0 : nsObjectFrame::CreateAccessible()
308 : {
309 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
310 : return accService ?
311 : accService->CreateHTMLObjectFrameAccessible(this, mContent,
312 0 : PresContext()->PresShell()) :
313 0 : nsnull;
314 : }
315 :
316 : #ifdef XP_WIN
317 : NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
318 : {
319 : *aPort = (HWND) mInstanceOwner->GetPluginPortFromWidget();
320 : return NS_OK;
321 : }
322 : #endif
323 : #endif
324 :
325 : NS_IMETHODIMP
326 0 : nsObjectFrame::Init(nsIContent* aContent,
327 : nsIFrame* aParent,
328 : nsIFrame* aPrevInFlow)
329 : {
330 0 : PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
331 : ("Initializing nsObjectFrame %p for content %p\n", this, aContent));
332 :
333 0 : nsresult rv = nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow);
334 :
335 0 : return rv;
336 : }
337 :
338 : void
339 0 : nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
340 : {
341 0 : if (mReflowCallbackPosted) {
342 0 : PresContext()->PresShell()->CancelReflowCallback(this);
343 : }
344 :
345 : // Tell content owner of the instance to disconnect its frame.
346 0 : nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
347 0 : NS_ASSERTION(objContent, "Why not an object loading content?");
348 0 : objContent->DisconnectFrame();
349 :
350 0 : if (mBackgroundSink) {
351 0 : mBackgroundSink->Destroy();
352 : }
353 :
354 0 : if (mInstanceOwner) {
355 0 : mInstanceOwner->SetFrame(nsnull);
356 : }
357 0 : SetInstanceOwner(nsnull);
358 :
359 0 : nsObjectFrameSuper::DestroyFrom(aDestructRoot);
360 0 : }
361 :
362 : /* virtual */ void
363 0 : nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
364 : {
365 0 : if (HasView()) {
366 0 : nsIView* view = GetView();
367 0 : nsIViewManager* vm = view->GetViewManager();
368 0 : if (vm) {
369 : nsViewVisibility visibility =
370 0 : IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
371 0 : vm->SetViewVisibility(view, visibility);
372 : }
373 : }
374 :
375 0 : nsObjectFrameSuper::DidSetStyleContext(aOldStyleContext);
376 0 : }
377 :
378 : nsIAtom*
379 0 : nsObjectFrame::GetType() const
380 : {
381 0 : return nsGkAtoms::objectFrame;
382 : }
383 :
384 : #ifdef DEBUG
385 : NS_IMETHODIMP
386 0 : nsObjectFrame::GetFrameName(nsAString& aResult) const
387 : {
388 0 : return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
389 : }
390 : #endif
391 :
392 : nsresult
393 0 : nsObjectFrame::PrepForDrawing(nsIWidget *aWidget)
394 : {
395 0 : mWidget = aWidget;
396 :
397 0 : nsIView* view = GetView();
398 0 : NS_ASSERTION(view, "Object frames must have views");
399 0 : if (!view) {
400 0 : return NS_ERROR_FAILURE;
401 : }
402 :
403 0 : nsIViewManager* viewMan = view->GetViewManager();
404 : // mark the view as hidden since we don't know the (x,y) until Paint
405 : // XXX is the above comment correct?
406 0 : viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
407 :
408 : //this is ugly. it was ripped off from didreflow(). MMP
409 : // Position and size view relative to its parent, not relative to our
410 : // parent frame (our parent frame may not have a view).
411 :
412 : nsIView* parentWithView;
413 0 : nsPoint origin;
414 0 : nsRect r(0, 0, mRect.width, mRect.height);
415 :
416 0 : GetOffsetFromView(origin, &parentWithView);
417 0 : viewMan->ResizeView(view, r);
418 0 : viewMan->MoveViewTo(view, origin.x, origin.y);
419 :
420 0 : nsRootPresContext* rpc = PresContext()->GetRootPresContext();
421 0 : if (!rpc) {
422 0 : return NS_ERROR_FAILURE;
423 : }
424 :
425 0 : if (mWidget) {
426 : // XXX this breaks plugins in popups ... do we care?
427 0 : nsIWidget* parentWidget = rpc->PresShell()->FrameManager()->GetRootFrame()->GetNearestWidget();
428 0 : if (!parentWidget) {
429 0 : return NS_ERROR_FAILURE;
430 : }
431 :
432 0 : mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view);
433 0 : if (!mInnerView) {
434 0 : NS_ERROR("Could not create inner view");
435 0 : return NS_ERROR_OUT_OF_MEMORY;
436 : }
437 0 : viewMan->InsertChild(view, mInnerView, nsnull, true);
438 :
439 0 : mWidget->SetParent(parentWidget);
440 0 : mWidget->Show(true);
441 0 : mWidget->Enable(true);
442 :
443 : // Set the plugin window to have an empty cliprect. The cliprect
444 : // will be reset when nsRootPresContext::UpdatePluginGeometry
445 : // runs later. The plugin window does need to have the correct
446 : // size here. GetEmptyClipConfiguration will probably give it the
447 : // size, but just in case we haven't been reflowed or something, set
448 : // the size explicitly.
449 0 : nsAutoTArray<nsIWidget::Configuration,1> configuration;
450 0 : GetEmptyClipConfiguration(&configuration);
451 0 : NS_ASSERTION(configuration.Length() > 0, "Empty widget configuration array!");
452 0 : configuration[0].mBounds.width = mRect.width;
453 0 : configuration[0].mBounds.height = mRect.height;
454 0 : parentWidget->ConfigureChildren(configuration);
455 :
456 0 : nsRefPtr<nsDeviceContext> dx;
457 0 : viewMan->GetDeviceContext(*getter_AddRefs(dx));
458 0 : EVENT_CALLBACK eventHandler = mInnerView->AttachWidgetEventHandler(mWidget);
459 0 : mWidget->SetEventCallback(eventHandler, dx);
460 :
461 : #ifdef XP_MACOSX
462 : // On Mac, we need to invalidate ourselves since even windowed
463 : // plugins are painted through Thebes and we need to ensure
464 : // the Thebes layer containing the plugin is updated.
465 : if (parentWidget == GetNearestWidget()) {
466 : Invalidate(GetContentRectRelativeToSelf());
467 : }
468 : #endif
469 :
470 0 : rpc->RegisterPluginForGeometryUpdates(this);
471 0 : rpc->RequestUpdatePluginGeometry(this);
472 :
473 : // Here we set the background color for this widget because some plugins will use
474 : // the child window background color when painting. If it's not set, it may default to gray
475 : // Sometimes, a frame doesn't have a background color or is transparent. In this
476 : // case, walk up the frame tree until we do find a frame with a background color
477 0 : for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
478 : nscolor bgcolor =
479 0 : frame->GetVisitedDependentColor(eCSSProperty_background_color);
480 0 : if (NS_GET_A(bgcolor) > 0) { // make sure we got an actual color
481 0 : mWidget->SetBackgroundColor(bgcolor);
482 0 : break;
483 : }
484 : }
485 : } else {
486 : // Changing to windowless mode changes the NPWindow geometry.
487 0 : FixupWindow(GetContentRectRelativeToSelf().Size());
488 :
489 : #ifndef XP_MACOSX
490 0 : rpc->RegisterPluginForGeometryUpdates(this);
491 0 : rpc->RequestUpdatePluginGeometry(this);
492 : #endif
493 : }
494 :
495 0 : if (!IsHidden()) {
496 0 : viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
497 : }
498 :
499 : #ifdef ACCESSIBILITY
500 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
501 0 : if (accService) {
502 0 : accService->RecreateAccessible(PresContext()->PresShell(), mContent);
503 : }
504 : #endif
505 :
506 0 : return NS_OK;
507 : }
508 :
509 : #define EMBED_DEF_WIDTH 240
510 : #define EMBED_DEF_HEIGHT 200
511 :
512 : /* virtual */ nscoord
513 0 : nsObjectFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
514 : {
515 0 : nscoord result = 0;
516 :
517 0 : if (!IsHidden(false)) {
518 0 : nsIAtom *atom = mContent->Tag();
519 0 : if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
520 0 : result = nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH);
521 : }
522 : }
523 :
524 0 : DISPLAY_MIN_WIDTH(this, result);
525 0 : return result;
526 : }
527 :
528 : /* virtual */ nscoord
529 0 : nsObjectFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
530 : {
531 0 : return nsObjectFrame::GetMinWidth(aRenderingContext);
532 : }
533 :
534 : void
535 0 : nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext,
536 : const nsHTMLReflowState& aReflowState,
537 : nsHTMLReflowMetrics& aMetrics)
538 : {
539 : // By default, we have no area
540 0 : aMetrics.width = 0;
541 0 : aMetrics.height = 0;
542 :
543 0 : if (IsHidden(false)) {
544 0 : return;
545 : }
546 :
547 0 : aMetrics.width = aReflowState.ComputedWidth();
548 0 : aMetrics.height = aReflowState.ComputedHeight();
549 :
550 : // for EMBED and APPLET, default to 240x200 for compatibility
551 0 : nsIAtom *atom = mContent->Tag();
552 0 : if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
553 0 : if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
554 0 : aMetrics.width = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH),
555 : aReflowState.mComputedMinWidth,
556 0 : aReflowState.mComputedMaxWidth);
557 : }
558 0 : if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
559 0 : aMetrics.height = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT),
560 : aReflowState.mComputedMinHeight,
561 0 : aReflowState.mComputedMaxHeight);
562 : }
563 :
564 : #if defined (MOZ_WIDGET_GTK2)
565 : // We need to make sure that the size of the object frame does not
566 : // exceed the maximum size of X coordinates. See bug #225357 for
567 : // more information. In theory Gtk2 can handle large coordinates,
568 : // but underlying plugins can't.
569 0 : aMetrics.height = NS_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.height);
570 0 : aMetrics.width = NS_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.width);
571 : #endif
572 : }
573 :
574 : // At this point, the width has an unconstrained value only if we have
575 : // nothing to go on (no width set, no information from the plugin, nothing).
576 : // Make up a number.
577 0 : if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
578 : aMetrics.width =
579 : (aReflowState.mComputedMinWidth != NS_UNCONSTRAINEDSIZE) ?
580 0 : aReflowState.mComputedMinWidth : 0;
581 : }
582 :
583 : // At this point, the height has an unconstrained value only in two cases:
584 : // a) We are in standards mode with percent heights and parent is auto-height
585 : // b) We have no height information at all.
586 : // In either case, we have to make up a number.
587 0 : if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
588 : aMetrics.height =
589 : (aReflowState.mComputedMinHeight != NS_UNCONSTRAINEDSIZE) ?
590 0 : aReflowState.mComputedMinHeight : 0;
591 : }
592 :
593 : // XXXbz don't add in the border and padding, because we screw up our
594 : // plugin's size and positioning if we do... Eventually we _do_ want to
595 : // paint borders, though! At that point, we will need to adjust the desired
596 : // size either here or in Reflow.... Further, we will need to fix Paint() to
597 : // call the superclass in all cases.
598 : }
599 :
600 : NS_IMETHODIMP
601 0 : nsObjectFrame::Reflow(nsPresContext* aPresContext,
602 : nsHTMLReflowMetrics& aMetrics,
603 : const nsHTMLReflowState& aReflowState,
604 : nsReflowStatus& aStatus)
605 : {
606 0 : DO_GLOBAL_REFLOW_COUNT("nsObjectFrame");
607 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
608 :
609 : // Get our desired size
610 0 : GetDesiredSize(aPresContext, aReflowState, aMetrics);
611 0 : aMetrics.SetOverflowAreasToDesiredBounds();
612 0 : FinishAndStoreOverflow(&aMetrics);
613 :
614 : // delay plugin instantiation until all children have
615 : // arrived. Otherwise there may be PARAMs or other stuff that the
616 : // plugin needs to see that haven't arrived yet.
617 0 : if (!GetContent()->IsDoneAddingChildren()) {
618 0 : aStatus = NS_FRAME_COMPLETE;
619 0 : return NS_OK;
620 : }
621 :
622 : // if we are printing or print previewing, bail for now
623 0 : if (aPresContext->Medium() == nsGkAtoms::print) {
624 0 : aStatus = NS_FRAME_COMPLETE;
625 0 : return NS_OK;
626 : }
627 :
628 0 : nsRect r(0, 0, aMetrics.width, aMetrics.height);
629 0 : r.Deflate(aReflowState.mComputedBorderPadding);
630 :
631 0 : if (mInnerView) {
632 0 : nsIViewManager* vm = mInnerView->GetViewManager();
633 0 : vm->MoveViewTo(mInnerView, r.x, r.y);
634 0 : vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), r.Size()), true);
635 : }
636 :
637 0 : FixupWindow(r.Size());
638 0 : if (!mReflowCallbackPosted) {
639 0 : mReflowCallbackPosted = true;
640 0 : aPresContext->PresShell()->PostReflowCallback(this);
641 : }
642 :
643 0 : aStatus = NS_FRAME_COMPLETE;
644 :
645 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
646 0 : return NS_OK;
647 : }
648 :
649 : ///////////// nsIReflowCallback ///////////////
650 :
651 : bool
652 0 : nsObjectFrame::ReflowFinished()
653 : {
654 0 : mReflowCallbackPosted = false;
655 0 : CallSetWindow();
656 0 : return true;
657 : }
658 :
659 : void
660 0 : nsObjectFrame::ReflowCallbackCanceled()
661 : {
662 0 : mReflowCallbackPosted = false;
663 0 : }
664 :
665 : void
666 0 : nsObjectFrame::FixupWindow(const nsSize& aSize)
667 : {
668 0 : nsPresContext* presContext = PresContext();
669 :
670 0 : if (!mInstanceOwner)
671 0 : return;
672 :
673 : NPWindow *window;
674 0 : mInstanceOwner->GetWindow(window);
675 :
676 0 : NS_ENSURE_TRUE(window, /**/);
677 :
678 : #ifdef XP_MACOSX
679 : nsWeakFrame weakFrame(this);
680 : mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintDisable);
681 : if (!weakFrame.IsAlive()) {
682 : return;
683 : }
684 : #endif
685 :
686 0 : bool windowless = (window->type == NPWindowTypeDrawable);
687 :
688 0 : nsIntPoint origin = GetWindowOriginInPixels(windowless);
689 :
690 0 : window->x = origin.x;
691 0 : window->y = origin.y;
692 :
693 0 : window->width = presContext->AppUnitsToDevPixels(aSize.width);
694 0 : window->height = presContext->AppUnitsToDevPixels(aSize.height);
695 :
696 : // on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep
697 : // us from drawing on screen until the widget is properly positioned, which will not
698 : // happen until we have finished the reflow process.
699 : #ifdef XP_MACOSX
700 : window->clipRect.top = 0;
701 : window->clipRect.left = 0;
702 : window->clipRect.bottom = 0;
703 : window->clipRect.right = 0;
704 : #else
705 0 : mInstanceOwner->UpdateWindowPositionAndClipRect(false);
706 : #endif
707 :
708 0 : NotifyPluginReflowObservers();
709 : }
710 :
711 : nsresult
712 0 : nsObjectFrame::CallSetWindow(bool aCheckIsHidden)
713 : {
714 0 : NPWindow *win = nsnull;
715 :
716 0 : nsresult rv = NS_ERROR_FAILURE;
717 0 : nsRefPtr<nsNPAPIPluginInstance> pi;
718 0 : if (!mInstanceOwner ||
719 0 : NS_FAILED(rv = mInstanceOwner->GetInstance(getter_AddRefs(pi))) ||
720 0 : !pi ||
721 0 : NS_FAILED(rv = mInstanceOwner->GetWindow(win)) ||
722 0 : !win)
723 0 : return rv;
724 :
725 0 : nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
726 : #ifdef XP_MACOSX
727 : nsWeakFrame weakFrame(this);
728 : mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintDisable);
729 : if (!weakFrame.IsAlive()) {
730 : return NS_ERROR_NOT_AVAILABLE;
731 : }
732 : #endif
733 :
734 0 : if (aCheckIsHidden && IsHidden())
735 0 : return NS_ERROR_FAILURE;
736 :
737 : // refresh the plugin port as well
738 0 : window->window = mInstanceOwner->GetPluginPortFromWidget();
739 :
740 : // Adjust plugin dimensions according to pixel snap results
741 : // and reduce amount of SetWindow calls
742 0 : nsPresContext* presContext = PresContext();
743 0 : nsRootPresContext* rootPC = presContext->GetRootPresContext();
744 0 : if (!rootPC)
745 0 : return NS_ERROR_FAILURE;
746 0 : PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
747 0 : nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
748 0 : nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame);
749 0 : nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
750 0 : window->x = intBounds.x;
751 0 : window->y = intBounds.y;
752 0 : window->width = intBounds.width;
753 0 : window->height = intBounds.height;
754 :
755 : // Calling SetWindow might destroy this frame. We need to use the instance
756 : // owner to clean up so hold a ref.
757 0 : nsRefPtr<nsPluginInstanceOwner> instanceOwnerRef(mInstanceOwner);
758 :
759 : // This will call pi->SetWindow and take care of window subclassing
760 : // if needed, see bug 132759. Calling SetWindow can destroy this frame
761 : // so check for that before doing anything else with this frame's memory.
762 0 : if (mInstanceOwner->UseAsyncRendering()) {
763 0 : rv = pi->AsyncSetWindow(window);
764 : }
765 : else {
766 0 : rv = window->CallSetWindow(pi);
767 : }
768 :
769 0 : instanceOwnerRef->ReleasePluginPort(window->window);
770 :
771 0 : return rv;
772 : }
773 :
774 : void
775 0 : nsObjectFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
776 : {
777 0 : mInstanceOwner = aOwner;
778 0 : if (!mInstanceOwner) {
779 0 : nsRootPresContext* rpc = PresContext()->GetRootPresContext();
780 0 : if (rpc) {
781 0 : if (mWidget) {
782 0 : if (mInnerView) {
783 0 : mInnerView->DetachWidgetEventHandler(mWidget);
784 : }
785 :
786 0 : rpc->UnregisterPluginForGeometryUpdates(this);
787 : // Make sure the plugin is hidden in case an update of plugin geometry
788 : // hasn't happened since this plugin became hidden.
789 0 : nsIWidget* parent = mWidget->GetParent();
790 0 : if (parent) {
791 0 : nsTArray<nsIWidget::Configuration> configurations;
792 0 : this->GetEmptyClipConfiguration(&configurations);
793 0 : parent->ConfigureChildren(configurations);
794 :
795 0 : mWidget->Show(false);
796 0 : mWidget->Enable(false);
797 0 : mWidget->SetParent(nsnull);
798 : }
799 : } else {
800 : #ifndef XP_MACOSX
801 0 : rpc->UnregisterPluginForGeometryUpdates(this);
802 : #endif
803 : }
804 : }
805 : }
806 0 : }
807 :
808 : bool
809 0 : nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
810 : {
811 0 : if (aTabIndex)
812 0 : *aTabIndex = -1;
813 0 : return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
814 : }
815 :
816 : bool
817 0 : nsObjectFrame::IsHidden(bool aCheckVisibilityStyle) const
818 : {
819 0 : if (aCheckVisibilityStyle) {
820 0 : if (!GetStyleVisibility()->IsVisibleOrCollapsed())
821 0 : return true;
822 : }
823 :
824 : // only <embed> tags support the HIDDEN attribute
825 0 : if (mContent->Tag() == nsGkAtoms::embed) {
826 : // Yes, these are really the kooky ways that you could tell 4.x
827 : // not to hide the <embed> once you'd put the 'hidden' attribute
828 : // on the tag...
829 :
830 : // HIDDEN w/ no attributes gets translated as we are hidden for
831 : // compatibility w/ 4.x and IE so we don't create a non-painting
832 : // widget in layout. See bug 188959.
833 0 : nsAutoString hidden;
834 0 : if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, hidden) &&
835 0 : (hidden.IsEmpty() ||
836 0 : (!hidden.LowerCaseEqualsLiteral("false") &&
837 0 : !hidden.LowerCaseEqualsLiteral("no") &&
838 0 : !hidden.LowerCaseEqualsLiteral("off")))) {
839 0 : return true;
840 : }
841 : }
842 :
843 0 : return false;
844 : }
845 :
846 0 : nsIntPoint nsObjectFrame::GetWindowOriginInPixels(bool aWindowless)
847 : {
848 : nsIView * parentWithView;
849 0 : nsPoint origin(0,0);
850 :
851 0 : GetOffsetFromView(origin, &parentWithView);
852 :
853 : // if it's windowless, let's make sure we have our origin set right
854 : // it may need to be corrected, like after scrolling
855 0 : if (aWindowless && parentWithView) {
856 0 : nsPoint offsetToWidget;
857 0 : parentWithView->GetNearestWidget(&offsetToWidget);
858 0 : origin += offsetToWidget;
859 : }
860 0 : origin += GetContentRectRelativeToSelf().TopLeft();
861 :
862 : return nsIntPoint(PresContext()->AppUnitsToDevPixels(origin.x),
863 0 : PresContext()->AppUnitsToDevPixels(origin.y));
864 : }
865 :
866 : NS_IMETHODIMP
867 0 : nsObjectFrame::DidReflow(nsPresContext* aPresContext,
868 : const nsHTMLReflowState* aReflowState,
869 : nsDidReflowStatus aStatus)
870 : {
871 : // Do this check before calling the superclass, as that clears
872 : // NS_FRAME_FIRST_REFLOW
873 0 : if (aStatus == NS_FRAME_REFLOW_FINISHED &&
874 0 : (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
875 0 : nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
876 0 : NS_ASSERTION(objContent, "Why not an object loading content?");
877 0 : objContent->HasNewFrame(this);
878 : }
879 :
880 0 : nsresult rv = nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
881 :
882 : // The view is created hidden; once we have reflowed it and it has been
883 : // positioned then we show it.
884 0 : if (aStatus != NS_FRAME_REFLOW_FINISHED)
885 0 : return rv;
886 :
887 0 : if (HasView()) {
888 0 : nsIView* view = GetView();
889 0 : nsIViewManager* vm = view->GetViewManager();
890 0 : if (vm)
891 0 : vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow);
892 : }
893 :
894 0 : return rv;
895 : }
896 :
897 : /* static */ void
898 0 : nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsRenderingContext* aCtx,
899 : const nsRect& aDirtyRect, nsPoint aPt)
900 : {
901 0 : nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft();
902 0 : nsRenderingContext::AutoPushTranslation translate(aCtx, pt);
903 : // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
904 0 : static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
905 0 : }
906 :
907 : class nsDisplayPluginReadback : public nsDisplayItem {
908 : public:
909 0 : nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
910 0 : : nsDisplayItem(aBuilder, aFrame)
911 : {
912 0 : MOZ_COUNT_CTOR(nsDisplayPluginReadback);
913 0 : }
914 : #ifdef NS_BUILD_REFCNT_LOGGING
915 0 : virtual ~nsDisplayPluginReadback() {
916 0 : MOZ_COUNT_DTOR(nsDisplayPluginReadback);
917 0 : }
918 : #endif
919 :
920 : virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
921 : virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
922 : nsRegion* aVisibleRegion,
923 : const nsRect& aAllowVisibleRegionExpansion);
924 :
925 0 : NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
926 :
927 0 : virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
928 : LayerManager* aManager,
929 : const ContainerParameters& aContainerParameters)
930 : {
931 0 : return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
932 : }
933 :
934 0 : virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
935 : LayerManager* aManager)
936 : {
937 0 : return LAYER_ACTIVE;
938 : }
939 : };
940 :
941 : static nsRect
942 0 : GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
943 : {
944 : // XXX For slightly more accurate region computations we should pixel-snap this
945 0 : return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
946 : }
947 :
948 : nsRect
949 0 : nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder)
950 : {
951 0 : return GetDisplayItemBounds(aBuilder, this, mFrame);
952 : }
953 :
954 : bool
955 0 : nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder,
956 : nsRegion* aVisibleRegion,
957 : const nsRect& aAllowVisibleRegionExpansion)
958 : {
959 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
960 0 : aAllowVisibleRegionExpansion))
961 0 : return false;
962 :
963 0 : nsRect expand;
964 0 : expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder));
965 : // *Add* our bounds to the visible region so that stuff underneath us is
966 : // likely to be made visible, so we can use it for a background! This is
967 : // a bit crazy since we normally only subtract from the visible region.
968 0 : aVisibleRegion->Or(*aVisibleRegion, expand);
969 0 : return true;
970 : }
971 :
972 : nsRect
973 0 : nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
974 : {
975 0 : return GetDisplayItemBounds(aBuilder, this, mFrame);
976 : }
977 :
978 : void
979 0 : nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
980 : nsRenderingContext* aCtx)
981 : {
982 0 : nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
983 0 : f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder));
984 0 : }
985 :
986 : bool
987 0 : nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
988 : nsRegion* aVisibleRegion,
989 : const nsRect& aAllowVisibleRegionExpansion)
990 : {
991 0 : mVisibleRegion.And(*aVisibleRegion, GetBounds(aBuilder));
992 : return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
993 0 : aAllowVisibleRegionExpansion);
994 : }
995 :
996 : nsRegion
997 0 : nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
998 : bool* aForceTransparentSurface)
999 : {
1000 0 : if (aForceTransparentSurface) {
1001 0 : *aForceTransparentSurface = false;
1002 : }
1003 0 : nsRegion result;
1004 0 : nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
1005 0 : if (!aBuilder->IsForPluginGeometry()) {
1006 0 : nsIWidget* widget = f->GetWidget();
1007 0 : if (widget) {
1008 0 : nsTArray<nsIntRect> clip;
1009 0 : widget->GetWindowClipRegion(&clip);
1010 0 : nsTArray<nsIWidget::Configuration> configuration;
1011 0 : GetWidgetConfiguration(aBuilder, &configuration);
1012 0 : NS_ASSERTION(configuration.Length() == 1, "No configuration found");
1013 0 : if (clip != configuration[0].mClipRegion) {
1014 : // Something has clipped us unexpectedly. Perhaps there is a translucent
1015 : // chrome element overlaying us that forced us to be clipped away. Treat
1016 : // us as non-opaque since we may have holes.
1017 : return result;
1018 : }
1019 : }
1020 : }
1021 0 : if (f->IsOpaque() &&
1022 0 : (aBuilder->IsForPluginGeometry() ||
1023 0 : (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(GetBounds(aBuilder)))) {
1024 : // We can treat this as opaque
1025 0 : result = GetBounds(aBuilder);
1026 : }
1027 0 : return result;
1028 : }
1029 :
1030 : void
1031 0 : nsDisplayPlugin::GetWidgetConfiguration(nsDisplayListBuilder* aBuilder,
1032 : nsTArray<nsIWidget::Configuration>* aConfigurations)
1033 : {
1034 0 : nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
1035 0 : nsPoint pluginOrigin = mFrame->GetContentRectRelativeToSelf().TopLeft() +
1036 0 : ToReferenceFrame();
1037 0 : f->ComputeWidgetGeometry(mVisibleRegion, pluginOrigin, aConfigurations);
1038 0 : }
1039 :
1040 : void
1041 0 : nsObjectFrame::ComputeWidgetGeometry(const nsRegion& aRegion,
1042 : const nsPoint& aPluginOrigin,
1043 : nsTArray<nsIWidget::Configuration>* aConfigurations)
1044 : {
1045 0 : if (!mWidget) {
1046 : #ifndef XP_MACOSX
1047 0 : if (mInstanceOwner) {
1048 : // UpdateWindowVisibility will notify the plugin of position changes
1049 : // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow.
1050 0 : mInstanceOwner->UpdateWindowVisibility(!aRegion.IsEmpty());
1051 : }
1052 : #endif
1053 0 : return;
1054 : }
1055 :
1056 0 : nsPresContext* presContext = PresContext();
1057 0 : nsRootPresContext* rootPC = presContext->GetRootPresContext();
1058 0 : if (!rootPC)
1059 0 : return;
1060 :
1061 0 : nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
1062 0 : if (!configuration)
1063 0 : return;
1064 0 : configuration->mChild = mWidget;
1065 :
1066 0 : PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
1067 0 : nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
1068 0 : nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame);
1069 0 : configuration->mBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
1070 :
1071 : // This should produce basically the same rectangle (but not relative
1072 : // to the root frame). We only call this here for the side-effect of
1073 : // setting mViewToWidgetOffset on the view.
1074 0 : mInnerView->CalcWidgetBounds(eWindowType_plugin);
1075 :
1076 0 : nsRegionRectIterator iter(aRegion);
1077 0 : nsIntPoint pluginOrigin = aPluginOrigin.ToNearestPixels(appUnitsPerDevPixel);
1078 0 : for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
1079 : // Snap *r to pixels while it's relative to the painted widget, to
1080 : // improve consistency with rectangle and image drawing
1081 : nsIntRect pixRect =
1082 0 : r->ToNearestPixels(appUnitsPerDevPixel) - pluginOrigin;
1083 0 : if (!pixRect.IsEmpty()) {
1084 0 : configuration->mClipRegion.AppendElement(pixRect);
1085 : }
1086 : }
1087 : }
1088 :
1089 : nsresult
1090 0 : nsObjectFrame::PluginEventNotifier::Run() {
1091 : nsCOMPtr<nsIObserverService> obsSvc =
1092 0 : mozilla::services::GetObserverService();
1093 0 : obsSvc->NotifyObservers(nsnull, "plugin-changed-event", mEventType.get());
1094 0 : return NS_OK;
1095 : }
1096 :
1097 : void
1098 0 : nsObjectFrame::NotifyPluginReflowObservers()
1099 : {
1100 0 : nsContentUtils::AddScriptRunner(new PluginEventNotifier(NS_LITERAL_STRING("reflow")));
1101 0 : }
1102 :
1103 : void
1104 0 : nsObjectFrame::DidSetWidgetGeometry()
1105 : {
1106 : #if defined(XP_MACOSX)
1107 : if (mInstanceOwner) {
1108 : mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable);
1109 : }
1110 : #endif
1111 0 : }
1112 :
1113 : bool
1114 0 : nsObjectFrame::IsOpaque() const
1115 : {
1116 : #if defined(XP_MACOSX)
1117 : // ???
1118 : return false;
1119 : #else
1120 0 : return !IsTransparentMode();
1121 : #endif
1122 : }
1123 :
1124 : bool
1125 0 : nsObjectFrame::IsTransparentMode() const
1126 : {
1127 : #if defined(XP_MACOSX)
1128 : // ???
1129 : return false;
1130 : #else
1131 0 : if (!mInstanceOwner)
1132 0 : return false;
1133 :
1134 0 : NPWindow *window = nsnull;
1135 0 : mInstanceOwner->GetWindow(window);
1136 0 : if (!window) {
1137 0 : return false;
1138 : }
1139 :
1140 0 : if (window->type != NPWindowTypeDrawable)
1141 0 : return false;
1142 :
1143 : nsresult rv;
1144 0 : nsRefPtr<nsNPAPIPluginInstance> pi;
1145 0 : rv = mInstanceOwner->GetInstance(getter_AddRefs(pi));
1146 0 : if (NS_FAILED(rv) || !pi)
1147 0 : return false;
1148 :
1149 0 : bool transparent = false;
1150 0 : pi->IsTransparent(&transparent);
1151 0 : return transparent;
1152 : #endif
1153 : }
1154 :
1155 : NS_IMETHODIMP
1156 0 : nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
1157 : const nsRect& aDirtyRect,
1158 : const nsDisplayListSet& aLists)
1159 : {
1160 : // XXX why are we painting collapsed object frames?
1161 0 : if (!IsVisibleOrCollapsedForPainting(aBuilder))
1162 0 : return NS_OK;
1163 :
1164 0 : nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
1165 0 : NS_ENSURE_SUCCESS(rv, rv);
1166 :
1167 0 : nsPresContext::nsPresContextType type = PresContext()->Type();
1168 :
1169 : // If we are painting in Print Preview do nothing....
1170 0 : if (type == nsPresContext::eContext_PrintPreview)
1171 0 : return NS_OK;
1172 :
1173 0 : DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame");
1174 :
1175 : #ifndef XP_MACOSX
1176 0 : if (mWidget && aBuilder->IsInTransform()) {
1177 : // Windowed plugins should not be rendered inside a transform.
1178 0 : return NS_OK;
1179 : }
1180 : #endif
1181 :
1182 0 : nsDisplayList replacedContent;
1183 :
1184 0 : if (aBuilder->IsForPainting() && mInstanceOwner && mInstanceOwner->UseAsyncRendering()) {
1185 0 : NPWindow* window = nsnull;
1186 0 : mInstanceOwner->GetWindow(window);
1187 0 : bool isVisible = window && window->width > 0 && window->height > 0;
1188 0 : if (isVisible && aBuilder->ShouldSyncDecodeImages()) {
1189 : #ifndef XP_MACOSX
1190 0 : mInstanceOwner->UpdateWindowVisibility(true);
1191 : #endif
1192 : }
1193 :
1194 0 : nsRefPtr<ImageContainer> container = GetImageContainer();
1195 0 : if (container && container->HasCurrentImage() || !isVisible ||
1196 0 : container->GetCurrentSize() != gfxIntSize(window->width, window->height)) {
1197 0 : mInstanceOwner->NotifyPaintWaiter(aBuilder);
1198 : }
1199 : }
1200 :
1201 : // determine if we are printing
1202 0 : if (type == nsPresContext::eContext_Print) {
1203 : rv = replacedContent.AppendNewToTop(new (aBuilder)
1204 : nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
1205 0 : nsDisplayItem::TYPE_PRINT_PLUGIN));
1206 : } else {
1207 0 : if (aBuilder->IsPaintingToWindow() &&
1208 0 : GetLayerState(aBuilder, nsnull) == LAYER_ACTIVE &&
1209 0 : IsTransparentMode()) {
1210 : rv = replacedContent.AppendNewToTop(new (aBuilder)
1211 0 : nsDisplayPluginReadback(aBuilder, this));
1212 0 : NS_ENSURE_SUCCESS(rv, rv);
1213 : }
1214 :
1215 : rv = replacedContent.AppendNewToTop(new (aBuilder)
1216 0 : nsDisplayPlugin(aBuilder, this));
1217 : }
1218 0 : NS_ENSURE_SUCCESS(rv, rv);
1219 :
1220 0 : WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
1221 :
1222 0 : return NS_OK;
1223 : }
1224 :
1225 : #ifdef XP_OS2
1226 : static void *
1227 : GetPSFromRC(nsRenderingContext& aRenderingContext)
1228 : {
1229 : nsRefPtr<gfxASurface>
1230 : surf = aRenderingContext.ThebesContext()->CurrentSurface();
1231 : if (!surf || surf->CairoStatus())
1232 : return nsnull;
1233 : return (void *)(static_cast<gfxOS2Surface*>
1234 : (static_cast<gfxASurface*>(surf.get()))->GetPS());
1235 : }
1236 : #endif
1237 :
1238 : void
1239 0 : nsObjectFrame::PrintPlugin(nsRenderingContext& aRenderingContext,
1240 : const nsRect& aDirtyRect)
1241 : {
1242 0 : nsCOMPtr<nsIObjectLoadingContent> obj(do_QueryInterface(mContent));
1243 0 : if (!obj)
1244 : return;
1245 :
1246 0 : nsIFrame* frame = nsnull;
1247 0 : obj->GetPrintFrame(&frame);
1248 0 : if (!frame)
1249 : return;
1250 :
1251 0 : nsPresContext* presContext = PresContext();
1252 : // make sure this is REALLY an nsIObjectFrame
1253 : // we may need to go through the children to get it
1254 0 : nsIObjectFrame* objectFrame = do_QueryFrame(frame);
1255 0 : if (!objectFrame)
1256 0 : objectFrame = GetNextObjectFrame(presContext,frame);
1257 0 : if (!objectFrame)
1258 : return;
1259 :
1260 : // finally we can get our plugin instance
1261 0 : nsRefPtr<nsNPAPIPluginInstance> pi;
1262 0 : if (NS_FAILED(objectFrame->GetPluginInstance(getter_AddRefs(pi))) || !pi)
1263 : return;
1264 :
1265 : // now we need to setup the correct location for printing
1266 : NPWindow window;
1267 0 : window.window = nsnull;
1268 :
1269 : // prepare embedded mode printing struct
1270 : NPPrint npprint;
1271 0 : npprint.mode = NP_EMBED;
1272 :
1273 : // we need to find out if we are windowless or not
1274 0 : bool windowless = false;
1275 0 : pi->IsWindowless(&windowless);
1276 0 : window.type = windowless ? NPWindowTypeDrawable : NPWindowTypeWindow;
1277 :
1278 0 : window.clipRect.bottom = 0; window.clipRect.top = 0;
1279 0 : window.clipRect.left = 0; window.clipRect.right = 0;
1280 :
1281 : // platform specific printing code
1282 : #ifdef MAC_CARBON_PLUGINS
1283 : // Don't use this code if any of the QuickDraw APIs it currently requires
1284 : // are missing (as they probably will be on OS X 10.8 and up).
1285 : if (!::SetRect || !::NewGWorldFromPtr || !::DisposeGWorld) {
1286 : NS_WARNING("Cannot print plugin -- required QuickDraw APIs are missing!");
1287 : return;
1288 : }
1289 :
1290 : nsSize contentSize = GetContentRectRelativeToSelf().Size();
1291 : window.x = 0;
1292 : window.y = 0;
1293 : window.width = presContext->AppUnitsToDevPixels(contentSize.width);
1294 : window.height = presContext->AppUnitsToDevPixels(contentSize.height);
1295 :
1296 : gfxContext *ctx = aRenderingContext.ThebesContext();
1297 : if (!ctx)
1298 : return;
1299 : gfxContextAutoSaveRestore save(ctx);
1300 :
1301 : ctx->NewPath();
1302 :
1303 : gfxRect rect(window.x, window.y, window.width, window.height);
1304 :
1305 : ctx->Rectangle(rect);
1306 : ctx->Clip();
1307 :
1308 : gfxQuartzNativeDrawing nativeDraw(ctx, rect);
1309 : CGContextRef cgContext = nativeDraw.BeginNativeDrawing();
1310 : if (!cgContext) {
1311 : nativeDraw.EndNativeDrawing();
1312 : return;
1313 : }
1314 :
1315 : window.clipRect.right = window.width;
1316 : window.clipRect.bottom = window.height;
1317 : window.type = NPWindowTypeDrawable;
1318 :
1319 : ::Rect gwBounds;
1320 : ::SetRect(&gwBounds, 0, 0, window.width, window.height);
1321 :
1322 : nsTArray<char> buffer(window.width * window.height * 4);
1323 : CGColorSpaceRef cspace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
1324 : if (!cspace) {
1325 : nativeDraw.EndNativeDrawing();
1326 : return;
1327 : }
1328 : CGContextRef cgBuffer =
1329 : ::CGBitmapContextCreate(buffer.Elements(),
1330 : window.width, window.height, 8, window.width * 4,
1331 : cspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedFirst);
1332 : ::CGColorSpaceRelease(cspace);
1333 : if (!cgBuffer) {
1334 : nativeDraw.EndNativeDrawing();
1335 : return;
1336 : }
1337 : GWorldPtr gWorld;
1338 : if (::NewGWorldFromPtr(&gWorld, k32ARGBPixelFormat, &gwBounds, NULL, NULL, 0,
1339 : buffer.Elements(), window.width * 4) != noErr) {
1340 : ::CGContextRelease(cgBuffer);
1341 : nativeDraw.EndNativeDrawing();
1342 : return;
1343 : }
1344 :
1345 : window.clipRect.right = window.width;
1346 : window.clipRect.bottom = window.height;
1347 : window.type = NPWindowTypeDrawable;
1348 : // Setting nsPluginPrint/NPPrint.print.embedPrint.window.window to
1349 : // &GWorldPtr and nsPluginPrint/NPPrint.print.embedPrint.platformPrint to
1350 : // GWorldPtr isn't any kind of standard (it's not documented anywhere).
1351 : // But that's what WebKit does. And it's what the Flash plugin (apparently
1352 : // the only NPAPI plugin on OS X to support printing) seems to expect. So
1353 : // we do the same. The Flash plugin uses the CoreGraphics drawing mode.
1354 : // But a GWorldPtr should be usable in either CoreGraphics or QuickDraw
1355 : // drawing mode. See bug 191046.
1356 : window.window = &gWorld;
1357 : npprint.print.embedPrint.platformPrint = gWorld;
1358 : npprint.print.embedPrint.window = window;
1359 : pi->Print(&npprint);
1360 :
1361 : ::CGContextTranslateCTM(cgContext, 0.0f, float(window.height));
1362 : ::CGContextScaleCTM(cgContext, 1.0f, -1.0f);
1363 : CGImageRef image = ::CGBitmapContextCreateImage(cgBuffer);
1364 : if (!image) {
1365 : ::CGContextRestoreGState(cgContext);
1366 : ::CGContextRelease(cgBuffer);
1367 : ::DisposeGWorld(gWorld);
1368 : nativeDraw.EndNativeDrawing();
1369 : return;
1370 : }
1371 : ::CGContextDrawImage(cgContext,
1372 : ::CGRectMake(0, 0, window.width, window.height),
1373 : image);
1374 : ::CGImageRelease(image);
1375 : ::CGContextRelease(cgBuffer);
1376 :
1377 : ::DisposeGWorld(gWorld);
1378 :
1379 : nativeDraw.EndNativeDrawing();
1380 : #elif defined(XP_UNIX)
1381 :
1382 : /* XXX this just flat-out doesn't work in a thebes world --
1383 : * RenderEPS is a no-op. So don't bother to do any work here.
1384 : */
1385 : (void)window;
1386 : (void)npprint;
1387 :
1388 : #elif defined(XP_OS2)
1389 : void *hps = GetPSFromRC(aRenderingContext);
1390 : if (!hps)
1391 : return;
1392 :
1393 : npprint.print.embedPrint.platformPrint = hps;
1394 : npprint.print.embedPrint.window = window;
1395 : // send off print info to plugin
1396 : pi->Print(&npprint);
1397 : #elif defined(XP_WIN)
1398 :
1399 : /* On Windows, we use the win32 printing surface to print. This, in
1400 : * turn, uses the Cairo paginated surface, which in turn uses the
1401 : * meta surface to record all operations and then play them back.
1402 : * This doesn't work too well for plugins, because if plugins render
1403 : * directly into the DC, the meta surface won't have any knowledge
1404 : * of them, and so at the end when it actually does the replay step,
1405 : * it'll fill the background with white and draw over whatever was
1406 : * rendered before.
1407 : *
1408 : * So, to avoid this, we use PushGroup, which creates a new windows
1409 : * surface, the plugin renders to that, and then we use normal
1410 : * cairo methods to composite that in such that it's recorded using the
1411 : * meta surface.
1412 : */
1413 :
1414 : /* we'll already be translated into the right spot by gfxWindowsNativeDrawing */
1415 : nsSize contentSize = GetContentRectRelativeToSelf().Size();
1416 : window.x = 0;
1417 : window.y = 0;
1418 : window.width = presContext->AppUnitsToDevPixels(contentSize.width);
1419 : window.height = presContext->AppUnitsToDevPixels(contentSize.height);
1420 :
1421 : gfxContext *ctx = aRenderingContext.ThebesContext();
1422 :
1423 : ctx->Save();
1424 :
1425 : /* Make sure plugins don't do any damage outside of where they're supposed to */
1426 : ctx->NewPath();
1427 : gfxRect r(window.x, window.y, window.width, window.height);
1428 : ctx->Rectangle(r);
1429 : ctx->Clip();
1430 :
1431 : gfxWindowsNativeDrawing nativeDraw(ctx, r);
1432 : do {
1433 : HDC dc = nativeDraw.BeginNativeDrawing();
1434 : if (!dc)
1435 : return;
1436 :
1437 : // XXX don't we need to call nativeDraw.TransformToNativeRect here?
1438 : npprint.print.embedPrint.platformPrint = dc;
1439 : npprint.print.embedPrint.window = window;
1440 : // send off print info to plugin
1441 : pi->Print(&npprint);
1442 :
1443 : nativeDraw.EndNativeDrawing();
1444 : } while (nativeDraw.ShouldRenderAgain());
1445 : nativeDraw.PaintToContext();
1446 :
1447 : ctx->Restore();
1448 : #endif
1449 :
1450 : // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same?
1451 : // XXX Calling DidReflow here makes no sense!!!
1452 0 : nsDidReflowStatus status = NS_FRAME_REFLOW_FINISHED; // should we use a special status?
1453 : frame->DidReflow(presContext,
1454 0 : nsnull, status); // DidReflow will take care of it
1455 : }
1456 :
1457 : already_AddRefed<ImageContainer>
1458 0 : nsObjectFrame::GetImageContainer()
1459 : {
1460 0 : nsRefPtr<ImageContainer> container = mImageContainer;
1461 :
1462 0 : if (container) {
1463 0 : return container.forget();
1464 : }
1465 :
1466 0 : container = mImageContainer = LayerManager::CreateImageContainer();
1467 :
1468 0 : return container.forget();
1469 : }
1470 :
1471 : nsRect
1472 0 : nsObjectFrame::GetPaintedRect(nsDisplayPlugin* aItem)
1473 : {
1474 0 : if (!mInstanceOwner)
1475 0 : return nsRect();
1476 0 : nsRect r = GetContentRectRelativeToSelf();
1477 0 : if (!mInstanceOwner->UseAsyncRendering())
1478 0 : return r;
1479 :
1480 0 : nsIntSize size = mInstanceOwner->GetCurrentImageSize();
1481 0 : nsPresContext* pc = PresContext();
1482 : r.IntersectRect(r, nsRect(0, 0, pc->DevPixelsToAppUnits(size.width),
1483 0 : pc->DevPixelsToAppUnits(size.height)));
1484 0 : return r;
1485 : }
1486 :
1487 : void
1488 0 : nsObjectFrame::UpdateImageLayer(const gfxRect& aRect)
1489 : {
1490 0 : if (!mInstanceOwner) {
1491 0 : return;
1492 : }
1493 :
1494 : #ifdef XP_MACOSX
1495 : if (!mInstanceOwner->UseAsyncRendering()) {
1496 : mInstanceOwner->DoCocoaEventDrawRect(aRect, nsnull);
1497 : // This makes sure the image on the container is up to date.
1498 : // XXX - Eventually we probably just want to make sure DoCocoaEventDrawRect
1499 : // updates the image container, to make this truly use 'push' semantics
1500 : // too.
1501 : mInstanceOwner->GetImageContainer();
1502 : }
1503 : #endif
1504 : }
1505 :
1506 : LayerState
1507 0 : nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
1508 : LayerManager* aManager)
1509 : {
1510 0 : if (!mInstanceOwner)
1511 0 : return LAYER_NONE;
1512 :
1513 : #ifdef XP_MACOSX
1514 : if (!mInstanceOwner->UseAsyncRendering() &&
1515 : mInstanceOwner->IsRemoteDrawingCoreAnimation() &&
1516 : mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
1517 : return LAYER_ACTIVE;
1518 : }
1519 : #endif
1520 :
1521 0 : if (!mInstanceOwner->UseAsyncRendering()) {
1522 0 : return LAYER_NONE;
1523 : }
1524 :
1525 0 : return LAYER_ACTIVE;
1526 : }
1527 :
1528 : already_AddRefed<Layer>
1529 0 : nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
1530 : LayerManager* aManager,
1531 : nsDisplayItem* aItem)
1532 : {
1533 0 : if (!mInstanceOwner)
1534 0 : return nsnull;
1535 :
1536 0 : NPWindow* window = nsnull;
1537 0 : mInstanceOwner->GetWindow(window);
1538 0 : if (!window)
1539 0 : return nsnull;
1540 :
1541 0 : if (window->width <= 0 || window->height <= 0)
1542 0 : return nsnull;
1543 :
1544 : // Create image
1545 0 : nsRefPtr<ImageContainer> container = mInstanceOwner->GetImageContainer();
1546 :
1547 0 : if (!container) {
1548 : // This can occur if our instance is gone.
1549 0 : return nsnull;
1550 : }
1551 :
1552 0 : gfxIntSize size;
1553 :
1554 0 : if (mInstanceOwner->UseAsyncRendering()) {
1555 0 : size = container->GetCurrentSize();
1556 : } else {
1557 0 : size = gfxIntSize(window->width, window->height);
1558 : }
1559 :
1560 0 : nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
1561 0 : gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
1562 : // to provide crisper and faster drawing.
1563 0 : r.Round();
1564 : nsRefPtr<Layer> layer =
1565 0 : (aBuilder->LayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
1566 :
1567 0 : if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) {
1568 0 : if (!layer) {
1569 0 : mInstanceOwner->NotifyPaintWaiter(aBuilder);
1570 : // Initialize ImageLayer
1571 0 : layer = aManager->CreateImageLayer();
1572 0 : if (!layer)
1573 0 : return nsnull;
1574 : }
1575 :
1576 0 : NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type");
1577 :
1578 0 : ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
1579 0 : UpdateImageLayer(r);
1580 :
1581 0 : if (!mInstanceOwner->UseAsyncRendering()) {
1582 0 : imglayer->SetScaleToSize(size, ImageLayer::SCALE_STRETCH);
1583 : }
1584 0 : imglayer->SetContainer(container);
1585 : gfxPattern::GraphicsFilter filter =
1586 0 : nsLayoutUtils::GetGraphicsFilterForFrame(this);
1587 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
1588 : if (!aManager->IsCompositingCheap()) {
1589 : // Pixman just horrible with bilinear filter scaling
1590 : filter = gfxPattern::FILTER_NEAREST;
1591 : }
1592 : #endif
1593 0 : imglayer->SetFilter(filter);
1594 :
1595 0 : layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
1596 : } else {
1597 0 : NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK,
1598 : "Unknown item type");
1599 0 : NS_ABORT_IF_FALSE(!IsOpaque(), "Opaque plugins don't use backgrounds");
1600 :
1601 0 : if (!layer) {
1602 0 : layer = aManager->CreateReadbackLayer();
1603 0 : if (!layer)
1604 0 : return nsnull;
1605 : }
1606 0 : NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type");
1607 :
1608 0 : ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get());
1609 0 : if (readback->GetSize() != nsIntSize(size.width, size.height)) {
1610 : // This will destroy any old background sink and notify us that the
1611 : // background is now unknown
1612 0 : readback->SetSink(nsnull);
1613 0 : readback->SetSize(nsIntSize(size.width, size.height));
1614 :
1615 0 : if (mBackgroundSink) {
1616 : // Maybe we still have a background sink associated with another
1617 : // readback layer that wasn't recycled for some reason? Unhook it
1618 : // now so that if this frame goes away, it doesn't have a dangling
1619 : // reference to us.
1620 0 : mBackgroundSink->Destroy();
1621 : }
1622 : mBackgroundSink =
1623 : new PluginBackgroundSink(this,
1624 0 : readback->AllocateSequenceNumber());
1625 0 : readback->SetSink(mBackgroundSink);
1626 : // The layer has taken ownership of our sink. When either the sink dies
1627 : // or the frame dies, the connection from the surviving object is nulled out.
1628 : }
1629 : }
1630 :
1631 : // Set a transform on the layer to draw the plugin in the right place
1632 0 : gfxMatrix transform;
1633 0 : transform.Translate(r.TopLeft());
1634 :
1635 0 : layer->SetTransform(gfx3DMatrix::From2D(transform));
1636 0 : layer->SetVisibleRegion(nsIntRect(0, 0, size.width, size.height));
1637 0 : return layer.forget();
1638 : }
1639 :
1640 : void
1641 0 : nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
1642 : nsRenderingContext& aRenderingContext,
1643 : const nsRect& aDirtyRect, const nsRect& aPluginRect)
1644 : {
1645 : #if defined(MOZ_WIDGET_ANDROID)
1646 : if (mInstanceOwner) {
1647 : NPWindow *window;
1648 : mInstanceOwner->GetWindow(window);
1649 :
1650 : gfxRect frameGfxRect =
1651 : PresContext()->AppUnitsToGfxUnits(aPluginRect);
1652 : gfxRect dirtyGfxRect =
1653 : PresContext()->AppUnitsToGfxUnits(aDirtyRect);
1654 : gfxContext* ctx = aRenderingContext.ThebesContext();
1655 :
1656 : gfx3DMatrix matrix3d = nsLayoutUtils::GetTransformToAncestor(this, nsnull);
1657 :
1658 : gfxMatrix matrix2d;
1659 : if (!matrix3d.Is2D(&matrix2d))
1660 : return;
1661 :
1662 : // The matrix includes the frame's position, so we need to transform
1663 : // from 0,0 to get the correct coordinates.
1664 : frameGfxRect.MoveTo(0, 0);
1665 :
1666 : mInstanceOwner->Paint(ctx, matrix2d.Transform(frameGfxRect), dirtyGfxRect);
1667 : return;
1668 : }
1669 : #endif
1670 :
1671 : // Screen painting code
1672 : #if defined(XP_MACOSX)
1673 : // delegate all painting to the plugin instance.
1674 : if (mInstanceOwner) {
1675 : if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics ||
1676 : mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation ||
1677 : mInstanceOwner->GetDrawingModel() ==
1678 : NPDrawingModelInvalidatingCoreAnimation) {
1679 : PRInt32 appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
1680 : // Clip to the content area where the plugin should be drawn. If
1681 : // we don't do this, the plugin can draw outside its bounds.
1682 : nsIntRect contentPixels = aPluginRect.ToNearestPixels(appUnitsPerDevPixel);
1683 : nsIntRect dirtyPixels = aDirtyRect.ToOutsidePixels(appUnitsPerDevPixel);
1684 : nsIntRect clipPixels;
1685 : clipPixels.IntersectRect(contentPixels, dirtyPixels);
1686 :
1687 : // Don't invoke the drawing code if the clip is empty.
1688 : if (clipPixels.IsEmpty())
1689 : return;
1690 :
1691 : gfxRect nativeClipRect(clipPixels.x, clipPixels.y,
1692 : clipPixels.width, clipPixels.height);
1693 : gfxContext* ctx = aRenderingContext.ThebesContext();
1694 :
1695 : gfxContextAutoSaveRestore save(ctx);
1696 : ctx->NewPath();
1697 : ctx->Rectangle(nativeClipRect);
1698 : ctx->Clip();
1699 : gfxPoint offset(contentPixels.x, contentPixels.y);
1700 : ctx->Translate(offset);
1701 :
1702 : gfxQuartzNativeDrawing nativeDrawing(ctx, nativeClipRect - offset);
1703 :
1704 : CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
1705 : if (!cgContext) {
1706 : NS_WARNING("null CGContextRef during PaintPlugin");
1707 : return;
1708 : }
1709 :
1710 : nsRefPtr<nsNPAPIPluginInstance> inst;
1711 : GetPluginInstance(getter_AddRefs(inst));
1712 : if (!inst) {
1713 : NS_WARNING("null plugin instance during PaintPlugin");
1714 : nativeDrawing.EndNativeDrawing();
1715 : return;
1716 : }
1717 : NPWindow* window;
1718 : mInstanceOwner->GetWindow(window);
1719 : if (!window) {
1720 : NS_WARNING("null plugin window during PaintPlugin");
1721 : nativeDrawing.EndNativeDrawing();
1722 : return;
1723 : }
1724 : NP_CGContext* cgPluginPortCopy =
1725 : static_cast<NP_CGContext*>(mInstanceOwner->GetPluginPortCopy());
1726 : if (!cgPluginPortCopy) {
1727 : NS_WARNING("null plugin port copy during PaintPlugin");
1728 : nativeDrawing.EndNativeDrawing();
1729 : return;
1730 : }
1731 : #ifndef NP_NO_CARBON
1732 : if (mInstanceOwner->GetEventModel() == NPEventModelCarbon &&
1733 : !mInstanceOwner->SetPluginPortAndDetectChange()) {
1734 : NS_WARNING("null plugin port during PaintPlugin");
1735 : nativeDrawing.EndNativeDrawing();
1736 : return;
1737 : }
1738 :
1739 : // In the Carbon event model...
1740 : // If gfxQuartzNativeDrawing hands out a CGContext different from the
1741 : // one set by SetPluginPortAndDetectChange(), we need to pass it to the
1742 : // plugin via SetWindow(). This will happen in nsPluginInstanceOwner::
1743 : // FixUpPluginWindow(), called from nsPluginInstanceOwner::Paint().
1744 : // (If SetPluginPortAndDetectChange() made any changes itself, this has
1745 : // already been detected in that method, and will likewise result in a
1746 : // call to SetWindow() from FixUpPluginWindow().)
1747 : NP_CGContext* windowContext = static_cast<NP_CGContext*>(window->window);
1748 : if (mInstanceOwner->GetEventModel() == NPEventModelCarbon &&
1749 : windowContext->context != cgContext) {
1750 : windowContext->context = cgContext;
1751 : cgPluginPortCopy->context = cgContext;
1752 : mInstanceOwner->SetPluginPortChanged(true);
1753 : }
1754 : #endif
1755 :
1756 : mInstanceOwner->BeginCGPaint();
1757 : if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation ||
1758 : mInstanceOwner->GetDrawingModel() ==
1759 : NPDrawingModelInvalidatingCoreAnimation) {
1760 : // CoreAnimation is updated, render the layer and perform a readback.
1761 : mInstanceOwner->RenderCoreAnimation(cgContext, window->width, window->height);
1762 : } else {
1763 : mInstanceOwner->Paint(nativeClipRect - offset, cgContext);
1764 : }
1765 : mInstanceOwner->EndCGPaint();
1766 :
1767 : nativeDrawing.EndNativeDrawing();
1768 : } else {
1769 : // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
1770 : nsRenderingContext::AutoPushTranslation
1771 : translate(&aRenderingContext, aPluginRect.TopLeft());
1772 :
1773 : // this rect is used only in the CoreGraphics drawing model
1774 : gfxRect tmpRect(0, 0, 0, 0);
1775 : mInstanceOwner->Paint(tmpRect, NULL);
1776 : }
1777 : }
1778 : #elif defined(MOZ_X11)
1779 0 : if (mInstanceOwner) {
1780 : NPWindow *window;
1781 0 : mInstanceOwner->GetWindow(window);
1782 0 : if (window->type == NPWindowTypeDrawable) {
1783 : gfxRect frameGfxRect =
1784 0 : PresContext()->AppUnitsToGfxUnits(aPluginRect);
1785 : gfxRect dirtyGfxRect =
1786 0 : PresContext()->AppUnitsToGfxUnits(aDirtyRect);
1787 0 : gfxContext* ctx = aRenderingContext.ThebesContext();
1788 :
1789 0 : mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect);
1790 : }
1791 : }
1792 : #elif defined(XP_WIN)
1793 : nsRefPtr<nsNPAPIPluginInstance> inst;
1794 : GetPluginInstance(getter_AddRefs(inst));
1795 : if (inst) {
1796 : gfxRect frameGfxRect =
1797 : PresContext()->AppUnitsToGfxUnits(aPluginRect);
1798 : gfxRect dirtyGfxRect =
1799 : PresContext()->AppUnitsToGfxUnits(aDirtyRect);
1800 : gfxContext *ctx = aRenderingContext.ThebesContext();
1801 : gfxMatrix currentMatrix = ctx->CurrentMatrix();
1802 :
1803 : if (ctx->UserToDevicePixelSnapped(frameGfxRect, false)) {
1804 : dirtyGfxRect = ctx->UserToDevice(dirtyGfxRect);
1805 : ctx->IdentityMatrix();
1806 : }
1807 : dirtyGfxRect.RoundOut();
1808 :
1809 : // Look if it's windowless
1810 : NPWindow *window;
1811 : mInstanceOwner->GetWindow(window);
1812 :
1813 : if (window->type == NPWindowTypeDrawable) {
1814 : // the offset of the DC
1815 : nsPoint origin;
1816 :
1817 : gfxWindowsNativeDrawing nativeDraw(ctx, frameGfxRect);
1818 : if (nativeDraw.IsDoublePass()) {
1819 : // OOP plugin specific: let the shim know before we paint if we are doing a
1820 : // double pass render. If this plugin isn't oop, the register window message
1821 : // will be ignored.
1822 : NPEvent pluginEvent;
1823 : pluginEvent.event = DoublePassRenderingEvent();
1824 : pluginEvent.wParam = 0;
1825 : pluginEvent.lParam = 0;
1826 : if (pluginEvent.event)
1827 : inst->HandleEvent(&pluginEvent, nsnull);
1828 : }
1829 : do {
1830 : HDC hdc = nativeDraw.BeginNativeDrawing();
1831 : if (!hdc)
1832 : return;
1833 :
1834 : RECT dest;
1835 : nativeDraw.TransformToNativeRect(frameGfxRect, dest);
1836 : RECT dirty;
1837 : nativeDraw.TransformToNativeRect(dirtyGfxRect, dirty);
1838 :
1839 : window->window = hdc;
1840 : window->x = dest.left;
1841 : window->y = dest.top;
1842 : window->clipRect.left = 0;
1843 : window->clipRect.top = 0;
1844 : // if we're painting, we're visible.
1845 : window->clipRect.right = window->width;
1846 : window->clipRect.bottom = window->height;
1847 :
1848 : // Windowless plugins on windows need a special event to update their location,
1849 : // see bug 135737.
1850 : //
1851 : // bug 271442: note, the rectangle we send is now purely the bounds of the plugin
1852 : // relative to the window it is contained in, which is useful for the plugin to
1853 : // correctly translate mouse coordinates.
1854 : //
1855 : // this does not mesh with the comments for bug 135737 which imply that the rectangle
1856 : // must be clipped in some way to prevent the plugin attempting to paint over areas
1857 : // it shouldn't.
1858 : //
1859 : // since the two uses of the rectangle are mutually exclusive in some cases, and
1860 : // since I don't see any incorrect painting (at least with Flash and ViewPoint -
1861 : // the originator of bug 135737), it seems that windowless plugins are not relying
1862 : // on information here for clipping their drawing, and we can safely use this message
1863 : // to tell the plugin exactly where it is in all cases.
1864 :
1865 : nsIntPoint origin = GetWindowOriginInPixels(true);
1866 : nsIntRect winlessRect = nsIntRect(origin, nsIntSize(window->width, window->height));
1867 :
1868 : if (!mWindowlessRect.IsEqualEdges(winlessRect)) {
1869 : mWindowlessRect = winlessRect;
1870 :
1871 : WINDOWPOS winpos;
1872 : memset(&winpos, 0, sizeof(winpos));
1873 : winpos.x = mWindowlessRect.x;
1874 : winpos.y = mWindowlessRect.y;
1875 : winpos.cx = mWindowlessRect.width;
1876 : winpos.cy = mWindowlessRect.height;
1877 :
1878 : // finally, update the plugin by sending it a WM_WINDOWPOSCHANGED event
1879 : NPEvent pluginEvent;
1880 : pluginEvent.event = WM_WINDOWPOSCHANGED;
1881 : pluginEvent.wParam = 0;
1882 : pluginEvent.lParam = (LPARAM)&winpos;
1883 : inst->HandleEvent(&pluginEvent, nsnull);
1884 : }
1885 :
1886 : inst->SetWindow(window);
1887 :
1888 : mInstanceOwner->Paint(dirty, hdc);
1889 : nativeDraw.EndNativeDrawing();
1890 : } while (nativeDraw.ShouldRenderAgain());
1891 : nativeDraw.PaintToContext();
1892 : }
1893 :
1894 : ctx->SetMatrix(currentMatrix);
1895 : }
1896 : #elif defined(XP_OS2)
1897 : nsRefPtr<nsNPAPIPluginInstance> inst;
1898 : GetPluginInstance(getter_AddRefs(inst));
1899 : if (inst) {
1900 : // Look if it's windowless
1901 : NPWindow *window;
1902 : mInstanceOwner->GetWindow(window);
1903 :
1904 : if (window->type == NPWindowTypeDrawable) {
1905 : // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
1906 : nsRenderingContext::AutoPushTranslation
1907 : translate(&aRenderingContext, aPluginRect.TopLeft());
1908 :
1909 : // check if we need to call SetWindow with updated parameters
1910 : bool doupdatewindow = false;
1911 : // the offset of the DC
1912 : nsIntPoint origin;
1913 :
1914 : /*
1915 : * Layout now has an optimized way of painting. Now we always get
1916 : * a new drawing surface, sized to be just what's needed. Windowless
1917 : * plugins need a transform applied to their origin so they paint
1918 : * in the right place. Since |SetWindow| is no longer being used
1919 : * to tell the plugin where it is, we dispatch a NPWindow through
1920 : * |HandleEvent| to tell the plugin when its window moved
1921 : */
1922 : gfxContext *ctx = aRenderingContext.ThebesContext();
1923 :
1924 : gfxMatrix ctxMatrix = ctx->CurrentMatrix();
1925 : if (ctxMatrix.HasNonTranslation()) {
1926 : // soo; in the future, we should be able to render
1927 : // the object content to an offscreen DC, and then
1928 : // composite it in with the right transforms.
1929 :
1930 : // But, we don't bother doing that, because we don't
1931 : // have the event handling story figured out yet.
1932 : // Instead, let's just bail.
1933 :
1934 : return;
1935 : }
1936 :
1937 : origin.x = NSToIntRound(float(ctxMatrix.GetTranslation().x));
1938 : origin.y = NSToIntRound(float(ctxMatrix.GetTranslation().y));
1939 :
1940 : /* Need to force the clip to be set */
1941 : ctx->UpdateSurfaceClip();
1942 :
1943 : /* Set the device offsets as appropriate, for whatever our current group offsets might be */
1944 : gfxFloat xoff, yoff;
1945 : nsRefPtr<gfxASurface> surf = ctx->CurrentSurface(&xoff, &yoff);
1946 :
1947 : if (surf->CairoStatus() != 0) {
1948 : NS_WARNING("Plugin is being asked to render to a surface that's in error!");
1949 : return;
1950 : }
1951 :
1952 : // check if we need to update the PS
1953 : HPS hps = (HPS)GetPSFromRC(aRenderingContext);
1954 : if (reinterpret_cast<HPS>(window->window) != hps) {
1955 : window->window = reinterpret_cast<void*>(hps);
1956 : doupdatewindow = true;
1957 : }
1958 : LONG lPSid = GpiSavePS(hps);
1959 : RECTL rclViewport;
1960 : if (GpiQueryDevice(hps) != NULLHANDLE) { // ensure that we have an associated HDC
1961 : if (GpiQueryPageViewport(hps, &rclViewport)) {
1962 : rclViewport.xLeft += (LONG)xoff;
1963 : rclViewport.xRight += (LONG)xoff;
1964 : rclViewport.yBottom += (LONG)yoff;
1965 : rclViewport.yTop += (LONG)yoff;
1966 : GpiSetPageViewport(hps, &rclViewport);
1967 : }
1968 : }
1969 :
1970 : if ((window->x != origin.x) || (window->y != origin.y)) {
1971 : window->x = origin.x;
1972 : window->y = origin.y;
1973 : doupdatewindow = true;
1974 : }
1975 :
1976 : // if our location or visible area has changed, we need to tell the plugin
1977 : if (doupdatewindow) {
1978 : inst->SetWindow(window);
1979 : }
1980 :
1981 : mInstanceOwner->Paint(aDirtyRect, hps);
1982 : if (lPSid >= 1) {
1983 : GpiRestorePS(hps, lPSid);
1984 : }
1985 : surf->MarkDirty();
1986 : }
1987 : }
1988 : #endif
1989 0 : }
1990 :
1991 : NS_IMETHODIMP
1992 0 : nsObjectFrame::HandleEvent(nsPresContext* aPresContext,
1993 : nsGUIEvent* anEvent,
1994 : nsEventStatus* anEventStatus)
1995 : {
1996 0 : NS_ENSURE_ARG_POINTER(anEvent);
1997 0 : NS_ENSURE_ARG_POINTER(anEventStatus);
1998 0 : nsresult rv = NS_OK;
1999 :
2000 0 : if (!mInstanceOwner)
2001 0 : return NS_ERROR_NULL_POINTER;
2002 :
2003 0 : mInstanceOwner->ConsiderNewEventloopNestingLevel();
2004 :
2005 0 : if (anEvent->message == NS_PLUGIN_ACTIVATE) {
2006 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2007 0 : nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(GetContent());
2008 0 : if (fm && elem)
2009 0 : return fm->SetFocus(elem, 0);
2010 : }
2011 0 : else if (anEvent->message == NS_PLUGIN_FOCUS) {
2012 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2013 0 : if (fm)
2014 0 : return fm->FocusPlugin(GetContent());
2015 : }
2016 :
2017 0 : if (mInstanceOwner->SendNativeEvents() &&
2018 : NS_IS_PLUGIN_EVENT(anEvent)) {
2019 0 : *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
2020 0 : return rv;
2021 : }
2022 :
2023 : #ifdef XP_WIN
2024 : rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
2025 : return rv;
2026 : #endif
2027 :
2028 : #ifdef XP_MACOSX
2029 : // we want to process some native mouse events in the cocoa event model
2030 : if ((anEvent->message == NS_MOUSE_ENTER || anEvent->message == NS_MOUSE_SCROLL) &&
2031 : mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
2032 : *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
2033 : return rv;
2034 : }
2035 : #endif
2036 :
2037 0 : if (anEvent->message == NS_DESTROY) {
2038 : #ifdef MAC_CARBON_PLUGINS
2039 : mInstanceOwner->CancelTimer();
2040 : #endif
2041 0 : return rv;
2042 : }
2043 :
2044 0 : return nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
2045 : }
2046 :
2047 : #ifdef XP_MACOSX
2048 : // Needed to make the routing of mouse events while dragging conform to
2049 : // standard OS X practice, and to the Cocoa NPAPI spec. See bug 525078.
2050 : NS_IMETHODIMP
2051 : nsObjectFrame::HandlePress(nsPresContext* aPresContext,
2052 : nsGUIEvent* anEvent,
2053 : nsEventStatus* anEventStatus)
2054 : {
2055 : nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
2056 : return nsObjectFrameSuper::HandlePress(aPresContext, anEvent, anEventStatus);
2057 : }
2058 : #endif
2059 :
2060 : nsresult
2061 0 : nsObjectFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance)
2062 : {
2063 0 : *aPluginInstance = nsnull;
2064 :
2065 0 : if (!mInstanceOwner) {
2066 0 : return NS_OK;
2067 : }
2068 :
2069 0 : return mInstanceOwner->GetInstance(aPluginInstance);
2070 : }
2071 :
2072 : NS_IMETHODIMP
2073 0 : nsObjectFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor)
2074 : {
2075 0 : if (!mInstanceOwner) {
2076 0 : return NS_ERROR_FAILURE;
2077 : }
2078 :
2079 0 : nsRefPtr<nsNPAPIPluginInstance> inst;
2080 0 : mInstanceOwner->GetInstance(getter_AddRefs(inst));
2081 0 : if (!inst) {
2082 0 : return NS_ERROR_FAILURE;
2083 : }
2084 :
2085 0 : bool useDOMCursor = static_cast<nsNPAPIPluginInstance*>(inst.get())->UsesDOMForCursor();
2086 0 : if (!useDOMCursor) {
2087 0 : return NS_ERROR_FAILURE;
2088 : }
2089 :
2090 0 : return nsObjectFrameSuper::GetCursor(aPoint, aCursor);
2091 : }
2092 :
2093 : void
2094 0 : nsObjectFrame::SetIsDocumentActive(bool aIsActive)
2095 : {
2096 : #ifndef XP_MACOSX
2097 0 : if (mInstanceOwner) {
2098 0 : mInstanceOwner->UpdateDocumentActiveState(aIsActive);
2099 : }
2100 : #endif
2101 0 : }
2102 :
2103 : // static
2104 : nsIObjectFrame *
2105 0 : nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)
2106 : {
2107 0 : nsIFrame* child = aRoot->GetFirstPrincipalChild();
2108 :
2109 0 : while (child) {
2110 0 : nsIObjectFrame* outFrame = do_QueryFrame(child);
2111 0 : if (outFrame) {
2112 0 : nsRefPtr<nsNPAPIPluginInstance> pi;
2113 0 : outFrame->GetPluginInstance(getter_AddRefs(pi)); // make sure we have a REAL plugin
2114 0 : if (pi)
2115 0 : return outFrame;
2116 : }
2117 :
2118 0 : outFrame = GetNextObjectFrame(aPresContext, child);
2119 0 : if (outFrame)
2120 0 : return outFrame;
2121 0 : child = child->GetNextSibling();
2122 : }
2123 :
2124 0 : return nsnull;
2125 : }
2126 :
2127 : /*static*/ void
2128 0 : nsObjectFrame::BeginSwapDocShells(nsIContent* aContent, void*)
2129 : {
2130 0 : NS_PRECONDITION(aContent, "");
2131 :
2132 : // This function is called from a document content enumerator so we need
2133 : // to filter out the nsObjectFrames and ignore the rest.
2134 0 : nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame());
2135 0 : if (!obj)
2136 0 : return;
2137 :
2138 0 : nsObjectFrame* objectFrame = static_cast<nsObjectFrame*>(obj);
2139 0 : NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(),
2140 : "Plugin windows must not be toplevel");
2141 0 : nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
2142 0 : NS_ASSERTION(rootPC, "unable to unregister the plugin frame");
2143 0 : rootPC->UnregisterPluginForGeometryUpdates(objectFrame);
2144 : }
2145 :
2146 : /*static*/ void
2147 0 : nsObjectFrame::EndSwapDocShells(nsIContent* aContent, void*)
2148 : {
2149 0 : NS_PRECONDITION(aContent, "");
2150 :
2151 : // This function is called from a document content enumerator so we need
2152 : // to filter out the nsObjectFrames and ignore the rest.
2153 0 : nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame());
2154 0 : if (!obj)
2155 0 : return;
2156 :
2157 0 : nsObjectFrame* objectFrame = static_cast<nsObjectFrame*>(obj);
2158 0 : nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
2159 0 : NS_ASSERTION(rootPC, "unable to register the plugin frame");
2160 0 : nsIWidget* widget = objectFrame->GetWidget();
2161 0 : if (widget) {
2162 : // Reparent the widget.
2163 : nsIWidget* parent =
2164 0 : rootPC->PresShell()->GetRootFrame()->GetNearestWidget();
2165 0 : widget->SetParent(parent);
2166 0 : objectFrame->CallSetWindow();
2167 :
2168 : // Register for geometry updates and make a request.
2169 0 : rootPC->RegisterPluginForGeometryUpdates(objectFrame);
2170 0 : rootPC->RequestUpdatePluginGeometry(objectFrame);
2171 : }
2172 : }
2173 :
2174 : nsIFrame*
2175 0 : NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
2176 : {
2177 0 : return new (aPresShell) nsObjectFrame(aContext);
2178 : }
2179 :
2180 : bool
2181 0 : nsObjectFrame::PaintedByGecko()
2182 : {
2183 : #ifdef XP_MACOSX
2184 : return true;
2185 : #else
2186 0 : return !mWidget;
2187 : #endif
2188 : }
2189 :
2190 4392 : NS_IMPL_FRAMEARENA_HELPERS(nsObjectFrame)
|