/src/mozilla-central/layout/generic/nsPluginFrame.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* rendering objects for replaced elements implemented by a plugin */ |
8 | | |
9 | | #include "nsPluginFrame.h" |
10 | | |
11 | | #include "gfx2DGlue.h" |
12 | | #include "gfxContext.h" |
13 | | #include "gfxMatrix.h" |
14 | | #include "mozilla/gfx/2D.h" |
15 | | #include "mozilla/BasicEvents.h" |
16 | | #include "mozilla/MouseEvents.h" |
17 | | #ifdef XP_WIN |
18 | | // This is needed for DoublePassRenderingEvent. |
19 | | #include "mozilla/plugins/PluginMessageUtils.h" |
20 | | #endif |
21 | | |
22 | | #include "nscore.h" |
23 | | #include "nsCOMPtr.h" |
24 | | #include "nsPresContext.h" |
25 | | #include "nsIPresShell.h" |
26 | | #include "nsWidgetsCID.h" |
27 | | #include "nsView.h" |
28 | | #include "nsViewManager.h" |
29 | | #include "nsString.h" |
30 | | #include "nsGkAtoms.h" |
31 | | #include "nsIPluginInstanceOwner.h" |
32 | | #include "nsNPAPIPluginInstance.h" |
33 | | #include "npapi.h" |
34 | | #include "nsIObjectLoadingContent.h" |
35 | | #include "nsContentUtils.h" |
36 | | #include "nsDisplayList.h" |
37 | | #include "nsFocusManager.h" |
38 | | #include "nsLayoutUtils.h" |
39 | | #include "nsFrameManager.h" |
40 | | #include "nsIObserverService.h" |
41 | | #include "GeckoProfiler.h" |
42 | | #include <algorithm> |
43 | | |
44 | | #include "nsIObjectFrame.h" |
45 | | #include "nsPluginNativeWindow.h" |
46 | | #include "FrameLayerBuilder.h" |
47 | | |
48 | | #include "ImageLayers.h" |
49 | | #include "nsPluginInstanceOwner.h" |
50 | | |
51 | | #ifdef XP_WIN |
52 | | #include "gfxWindowsNativeDrawing.h" |
53 | | #include "gfxWindowsSurface.h" |
54 | | #endif |
55 | | |
56 | | #include "Layers.h" |
57 | | #include "ReadbackLayer.h" |
58 | | #include "ImageContainer.h" |
59 | | #include "mozilla/layers/WebRenderLayerManager.h" |
60 | | |
61 | | // accessibility support |
62 | | #ifdef ACCESSIBILITY |
63 | | #include "nsAccessibilityService.h" |
64 | | #endif |
65 | | |
66 | | #include "mozilla/Logging.h" |
67 | | |
68 | | #ifdef XP_MACOSX |
69 | | #include "gfxQuartzNativeDrawing.h" |
70 | | #include "mozilla/gfx/QuartzSupport.h" |
71 | | #endif |
72 | | |
73 | | #ifdef MOZ_X11 |
74 | | #include "mozilla/X11Util.h" |
75 | | using mozilla::DefaultXDisplay; |
76 | | #endif |
77 | | |
78 | | #ifdef XP_WIN |
79 | | #include <wtypes.h> |
80 | | #include <winuser.h> |
81 | | #endif |
82 | | |
83 | | #include "mozilla/dom/TabChild.h" |
84 | | |
85 | | #ifdef CreateEvent // Thank you MS. |
86 | | #undef CreateEvent |
87 | | #endif |
88 | | |
89 | | static mozilla::LazyLogModule sPluginFrameLog("nsPluginFrame"); |
90 | | |
91 | | using namespace mozilla; |
92 | | using namespace mozilla::gfx; |
93 | | using namespace mozilla::layers; |
94 | | |
95 | | class PluginBackgroundSink : public ReadbackSink { |
96 | | public: |
97 | | PluginBackgroundSink(nsPluginFrame* aFrame, uint64_t aStartSequenceNumber) |
98 | 0 | : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {} |
99 | | ~PluginBackgroundSink() override |
100 | 0 | { |
101 | 0 | if (mFrame) { |
102 | 0 | mFrame->mBackgroundSink = nullptr; |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | | void SetUnknown(uint64_t aSequenceNumber) override |
107 | 0 | { |
108 | 0 | if (!AcceptUpdate(aSequenceNumber)) |
109 | 0 | return; |
110 | 0 | mFrame->mInstanceOwner->SetBackgroundUnknown(); |
111 | 0 | } |
112 | | |
113 | | already_AddRefed<DrawTarget> |
114 | | BeginUpdate(const nsIntRect& aRect, uint64_t aSequenceNumber) override |
115 | 0 | { |
116 | 0 | if (!AcceptUpdate(aSequenceNumber)) |
117 | 0 | return nullptr; |
118 | 0 | return mFrame->mInstanceOwner->BeginUpdateBackground(aRect); |
119 | 0 | } |
120 | | |
121 | | void EndUpdate(const nsIntRect& aRect) override |
122 | 0 | { |
123 | 0 | return mFrame->mInstanceOwner->EndUpdateBackground(aRect); |
124 | 0 | } |
125 | | |
126 | 0 | void Destroy() { mFrame = nullptr; } |
127 | | |
128 | | protected: |
129 | 0 | bool AcceptUpdate(uint64_t aSequenceNumber) { |
130 | 0 | if (aSequenceNumber > mLastSequenceNumber && mFrame && |
131 | 0 | mFrame->mInstanceOwner) { |
132 | 0 | mLastSequenceNumber = aSequenceNumber; |
133 | 0 | return true; |
134 | 0 | } |
135 | 0 | return false; |
136 | 0 | } |
137 | | |
138 | | uint64_t mLastSequenceNumber; |
139 | | nsPluginFrame* mFrame; |
140 | | }; |
141 | | |
142 | | nsPluginFrame::nsPluginFrame(ComputedStyle* aStyle) |
143 | | : nsFrame(aStyle, kClassID) |
144 | | , mInstanceOwner(nullptr) |
145 | | , mOuterView(nullptr) |
146 | | , mInnerView(nullptr) |
147 | | , mBackgroundSink(nullptr) |
148 | | , mReflowCallbackPosted(false) |
149 | 0 | { |
150 | 0 | MOZ_LOG(sPluginFrameLog, LogLevel::Debug, |
151 | 0 | ("Created new nsPluginFrame %p\n", this)); |
152 | 0 | } |
153 | | |
154 | | nsPluginFrame::~nsPluginFrame() |
155 | 0 | { |
156 | 0 | MOZ_LOG(sPluginFrameLog, LogLevel::Debug, |
157 | 0 | ("nsPluginFrame %p deleted\n", this)); |
158 | 0 | } |
159 | | |
160 | 0 | NS_QUERYFRAME_HEAD(nsPluginFrame) |
161 | 0 | NS_QUERYFRAME_ENTRY(nsPluginFrame) |
162 | 0 | NS_QUERYFRAME_ENTRY(nsIObjectFrame) |
163 | 0 | NS_QUERYFRAME_TAIL_INHERITING(nsFrame) |
164 | | |
165 | | #ifdef ACCESSIBILITY |
166 | | a11y::AccType |
167 | | nsPluginFrame::AccessibleType() |
168 | 0 | { |
169 | 0 | return a11y::ePluginType; |
170 | 0 | } |
171 | | |
172 | | #ifdef XP_WIN |
173 | | NS_IMETHODIMP nsPluginFrame::GetPluginPort(HWND *aPort) |
174 | | { |
175 | | *aPort = (HWND) mInstanceOwner->GetPluginPort(); |
176 | | return NS_OK; |
177 | | } |
178 | | #endif |
179 | | #endif |
180 | | |
181 | | void |
182 | | nsPluginFrame::Init(nsIContent* aContent, |
183 | | nsContainerFrame* aParent, |
184 | | nsIFrame* aPrevInFlow) |
185 | 0 | { |
186 | 0 | MOZ_LOG(sPluginFrameLog, LogLevel::Debug, |
187 | 0 | ("Initializing nsPluginFrame %p for content %p\n", this, aContent)); |
188 | 0 |
|
189 | 0 | nsFrame::Init(aContent, aParent, aPrevInFlow); |
190 | 0 | CreateView(); |
191 | 0 | } |
192 | | |
193 | | void |
194 | | nsPluginFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) |
195 | 0 | { |
196 | 0 | if (mReflowCallbackPosted) { |
197 | 0 | PresShell()->CancelReflowCallback(this); |
198 | 0 | } |
199 | 0 |
|
200 | 0 | // Ensure our DidComposite observer is gone. |
201 | 0 | mDidCompositeObserver = nullptr; |
202 | 0 |
|
203 | 0 | // Tell content owner of the instance to disconnect its frame. |
204 | 0 | nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent)); |
205 | 0 | NS_ASSERTION(objContent, "Why not an object loading content?"); |
206 | 0 |
|
207 | 0 | // The content might not have a reference to the instance owner any longer in |
208 | 0 | // the case of re-entry during instantiation or teardown, so make sure we're |
209 | 0 | // dissociated. |
210 | 0 | if (mInstanceOwner) { |
211 | 0 | mInstanceOwner->SetFrame(nullptr); |
212 | 0 | } |
213 | 0 | objContent->HasNewFrame(nullptr); |
214 | 0 |
|
215 | 0 | if (mBackgroundSink) { |
216 | 0 | mBackgroundSink->Destroy(); |
217 | 0 | } |
218 | 0 |
|
219 | 0 | nsFrame::DestroyFrom(aDestructRoot, aPostDestroyData); |
220 | 0 | } |
221 | | |
222 | | /* virtual */ void |
223 | | nsPluginFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) |
224 | 0 | { |
225 | 0 | if (HasView()) { |
226 | 0 | nsView* view = GetView(); |
227 | 0 | nsViewManager* vm = view->GetViewManager(); |
228 | 0 | if (vm) { |
229 | 0 | nsViewVisibility visibility = |
230 | 0 | IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow; |
231 | 0 | vm->SetViewVisibility(view, visibility); |
232 | 0 | } |
233 | 0 | } |
234 | 0 |
|
235 | 0 | nsFrame::DidSetComputedStyle(aOldComputedStyle); |
236 | 0 | } |
237 | | |
238 | | #ifdef DEBUG_FRAME_DUMP |
239 | | nsresult |
240 | | nsPluginFrame::GetFrameName(nsAString& aResult) const |
241 | | { |
242 | | return MakeFrameName(NS_LITERAL_STRING("PluginFrame"), aResult); |
243 | | } |
244 | | #endif |
245 | | |
246 | | nsresult |
247 | | nsPluginFrame::PrepForDrawing(nsIWidget *aWidget) |
248 | 0 | { |
249 | 0 | mWidget = aWidget; |
250 | 0 |
|
251 | 0 | nsView* view = GetView(); |
252 | 0 | NS_ASSERTION(view, "Object frames must have views"); |
253 | 0 | if (!view) { |
254 | 0 | return NS_ERROR_FAILURE; |
255 | 0 | } |
256 | 0 | |
257 | 0 | nsViewManager* viewMan = view->GetViewManager(); |
258 | 0 | // mark the view as hidden since we don't know the (x,y) until Paint |
259 | 0 | // XXX is the above comment correct? |
260 | 0 | viewMan->SetViewVisibility(view, nsViewVisibility_kHide); |
261 | 0 |
|
262 | 0 | //this is ugly. it was ripped off from didreflow(). MMP |
263 | 0 | // Position and size view relative to its parent, not relative to our |
264 | 0 | // parent frame (our parent frame may not have a view). |
265 | 0 |
|
266 | 0 | nsView* parentWithView; |
267 | 0 | nsPoint origin; |
268 | 0 | nsRect r(0, 0, mRect.width, mRect.height); |
269 | 0 |
|
270 | 0 | GetOffsetFromView(origin, &parentWithView); |
271 | 0 | viewMan->ResizeView(view, r); |
272 | 0 | viewMan->MoveViewTo(view, origin.x, origin.y); |
273 | 0 |
|
274 | 0 | nsPresContext* presContext = PresContext(); |
275 | 0 | nsRootPresContext* rpc = presContext->GetRootPresContext(); |
276 | 0 | if (!rpc) { |
277 | 0 | return NS_ERROR_FAILURE; |
278 | 0 | } |
279 | 0 | |
280 | 0 | if (mWidget) { |
281 | 0 | // Disallow windowed plugins in popups |
282 | 0 | nsIFrame* rootFrame = rpc->PresShell()->GetRootFrame(); |
283 | 0 | nsIWidget* parentWidget = rootFrame->GetNearestWidget(); |
284 | 0 | if (!parentWidget || nsLayoutUtils::GetDisplayRootFrame(this) != rootFrame) { |
285 | 0 | return NS_ERROR_FAILURE; |
286 | 0 | } |
287 | 0 | |
288 | 0 | // We can already have mInnerView if our instance owner went away and then |
289 | 0 | // came back. So clear the old one before creating a new one. |
290 | 0 | if (mInnerView) { |
291 | 0 | if (mInnerView->GetWidget()) { |
292 | 0 | // The widget listener should have already been cleared by |
293 | 0 | // SetInstanceOwner (with a null instance owner). |
294 | 0 | MOZ_RELEASE_ASSERT(mInnerView->GetWidget()->GetWidgetListener() == nullptr); |
295 | 0 | } |
296 | 0 | mInnerView->Destroy(); |
297 | 0 | mInnerView = nullptr; |
298 | 0 | } |
299 | 0 | mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view); |
300 | 0 | if (!mInnerView) { |
301 | 0 | NS_ERROR("Could not create inner view"); |
302 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
303 | 0 | } |
304 | 0 | viewMan->InsertChild(view, mInnerView, nullptr, true); |
305 | 0 |
|
306 | 0 | mWidget->SetParent(parentWidget); |
307 | 0 | mWidget->Enable(true); |
308 | 0 | mWidget->Show(true); |
309 | 0 |
|
310 | 0 | // Set the plugin window to have an empty clip region until we know |
311 | 0 | // what our true position, size and clip region are. These |
312 | 0 | // will be reset when nsRootPresContext computes our true |
313 | 0 | // geometry. The plugin window does need to have a good size here, so |
314 | 0 | // set the size explicitly to a reasonable guess. |
315 | 0 | AutoTArray<nsIWidget::Configuration,1> configurations; |
316 | 0 | nsIWidget::Configuration* configuration = configurations.AppendElement(); |
317 | 0 | nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); |
318 | 0 | configuration->mChild = mWidget; |
319 | 0 | configuration->mBounds.width = NSAppUnitsToIntPixels(mRect.width, appUnitsPerDevPixel); |
320 | 0 | configuration->mBounds.height = NSAppUnitsToIntPixels(mRect.height, appUnitsPerDevPixel); |
321 | 0 | parentWidget->ConfigureChildren(configurations); |
322 | 0 |
|
323 | 0 | mInnerView->AttachWidgetEventHandler(mWidget); |
324 | 0 |
|
325 | | #ifdef XP_MACOSX |
326 | | // On Mac, we need to invalidate ourselves since even windowed |
327 | | // plugins are painted through Thebes and we need to ensure |
328 | | // the PaintedLayer containing the plugin is updated. |
329 | | if (parentWidget == GetNearestWidget()) { |
330 | | InvalidateFrame(); |
331 | | } |
332 | | #endif |
333 | |
|
334 | 0 | RegisterPluginForGeometryUpdates(); |
335 | 0 |
|
336 | 0 | // Here we set the background color for this widget because some plugins will use |
337 | 0 | // the child window background color when painting. If it's not set, it may default to gray |
338 | 0 | // Sometimes, a frame doesn't have a background color or is transparent. In this |
339 | 0 | // case, walk up the frame tree until we do find a frame with a background color |
340 | 0 | for (nsIFrame* frame = this; frame; frame = frame->GetParent()) { |
341 | 0 | nscolor bgcolor = frame-> |
342 | 0 | GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor); |
343 | 0 | if (NS_GET_A(bgcolor) > 0) { // make sure we got an actual color |
344 | 0 | mWidget->SetBackgroundColor(bgcolor); |
345 | 0 | break; |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } else { |
349 | 0 | // Changing to windowless mode changes the NPWindow geometry. |
350 | 0 | FixupWindow(GetContentRectRelativeToSelf().Size()); |
351 | 0 | RegisterPluginForGeometryUpdates(); |
352 | 0 | } |
353 | 0 |
|
354 | 0 | if (!IsHidden()) { |
355 | 0 | viewMan->SetViewVisibility(view, nsViewVisibility_kShow); |
356 | 0 | } |
357 | 0 |
|
358 | 0 | #ifdef ACCESSIBILITY |
359 | 0 | nsAccessibilityService* accService = nsIPresShell::AccService(); |
360 | 0 | if (accService) { |
361 | 0 | accService->RecreateAccessible(PresShell(), mContent); |
362 | 0 | } |
363 | 0 | #endif |
364 | 0 |
|
365 | 0 | return NS_OK; |
366 | 0 | } |
367 | | |
368 | 0 | #define EMBED_DEF_WIDTH 240 |
369 | 0 | #define EMBED_DEF_HEIGHT 200 |
370 | | |
371 | | /* virtual */ nscoord |
372 | | nsPluginFrame::GetMinISize(gfxContext *aRenderingContext) |
373 | 0 | { |
374 | 0 | nscoord result = 0; |
375 | 0 |
|
376 | 0 | if (!IsHidden(false)) { |
377 | 0 | if (mContent->IsHTMLElement(nsGkAtoms::embed)) { |
378 | 0 | bool vertical = GetWritingMode().IsVertical(); |
379 | 0 | result = nsPresContext::CSSPixelsToAppUnits( |
380 | 0 | vertical ? EMBED_DEF_HEIGHT : EMBED_DEF_WIDTH); |
381 | 0 | } |
382 | 0 | } |
383 | 0 |
|
384 | 0 | DISPLAY_MIN_INLINE_SIZE(this, result); |
385 | 0 | return result; |
386 | 0 | } |
387 | | |
388 | | /* virtual */ nscoord |
389 | | nsPluginFrame::GetPrefISize(gfxContext *aRenderingContext) |
390 | 0 | { |
391 | 0 | return nsPluginFrame::GetMinISize(aRenderingContext); |
392 | 0 | } |
393 | | |
394 | | void |
395 | | nsPluginFrame::GetWidgetConfiguration(nsTArray<nsIWidget::Configuration>* aConfigurations) |
396 | 0 | { |
397 | 0 | if (!mWidget) { |
398 | 0 | return; |
399 | 0 | } |
400 | 0 | |
401 | 0 | if (!mWidget->GetParent()) { |
402 | 0 | // Plugin widgets should not be toplevel except when they're out of the |
403 | 0 | // document, in which case the plugin should not be registered for |
404 | 0 | // geometry updates and this should not be called. But apparently we |
405 | 0 | // have bugs where mWidget sometimes is toplevel here. Bail out. |
406 | 0 | NS_ERROR("Plugin widgets registered for geometry updates should not be toplevel"); |
407 | 0 | return; |
408 | 0 | } |
409 | 0 |
|
410 | 0 | nsIWidget::Configuration* configuration = aConfigurations->AppendElement(); |
411 | 0 | configuration->mChild = mWidget; |
412 | 0 | configuration->mBounds = mNextConfigurationBounds; |
413 | 0 | configuration->mClipRegion = mNextConfigurationClipRegion; |
414 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
415 | 0 | if (XRE_IsContentProcess()) { |
416 | 0 | configuration->mWindowID = (uintptr_t)mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT); |
417 | 0 | configuration->mVisible = mWidget->IsVisible(); |
418 | 0 |
|
419 | 0 | } |
420 | 0 | #endif // defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
421 | 0 | } |
422 | | |
423 | | void |
424 | | nsPluginFrame::GetDesiredSize(nsPresContext* aPresContext, |
425 | | const ReflowInput& aReflowInput, |
426 | | ReflowOutput& aMetrics) |
427 | 0 | { |
428 | 0 | // By default, we have no area |
429 | 0 | aMetrics.ClearSize(); |
430 | 0 |
|
431 | 0 | if (IsHidden(false)) { |
432 | 0 | return; |
433 | 0 | } |
434 | 0 | |
435 | 0 | aMetrics.Width() = aReflowInput.ComputedWidth(); |
436 | 0 | aMetrics.Height() = aReflowInput.ComputedHeight(); |
437 | 0 |
|
438 | 0 | // for EMBED, default to 240x200 for compatibility |
439 | 0 | if (mContent->IsHTMLElement(nsGkAtoms::embed)) { |
440 | 0 | if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) { |
441 | 0 | aMetrics.Width() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH), |
442 | 0 | aReflowInput.ComputedMinWidth(), |
443 | 0 | aReflowInput.ComputedMaxWidth()); |
444 | 0 | } |
445 | 0 | if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) { |
446 | 0 | aMetrics.Height() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT), |
447 | 0 | aReflowInput.ComputedMinHeight(), |
448 | 0 | aReflowInput.ComputedMaxHeight()); |
449 | 0 | } |
450 | 0 |
|
451 | 0 | #if defined(MOZ_WIDGET_GTK) |
452 | 0 | // We need to make sure that the size of the object frame does not |
453 | 0 | // exceed the maximum size of X coordinates. See bug #225357 for |
454 | 0 | // more information. In theory Gtk2 can handle large coordinates, |
455 | 0 | // but underlying plugins can't. |
456 | 0 | aMetrics.Height() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Height()); |
457 | 0 | aMetrics.Width() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Width()); |
458 | 0 | #endif |
459 | 0 | } |
460 | 0 |
|
461 | 0 | // At this point, the width has an unconstrained value only if we have |
462 | 0 | // nothing to go on (no width set, no information from the plugin, nothing). |
463 | 0 | // Make up a number. |
464 | 0 | if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) { |
465 | 0 | aMetrics.Width() = |
466 | 0 | (aReflowInput.ComputedMinWidth() != NS_UNCONSTRAINEDSIZE) ? |
467 | 0 | aReflowInput.ComputedMinWidth() : 0; |
468 | 0 | } |
469 | 0 |
|
470 | 0 | // At this point, the height has an unconstrained value only in two cases: |
471 | 0 | // a) We are in standards mode with percent heights and parent is auto-height |
472 | 0 | // b) We have no height information at all. |
473 | 0 | // In either case, we have to make up a number. |
474 | 0 | if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) { |
475 | 0 | aMetrics.Height() = |
476 | 0 | (aReflowInput.ComputedMinHeight() != NS_UNCONSTRAINEDSIZE) ? |
477 | 0 | aReflowInput.ComputedMinHeight() : 0; |
478 | 0 | } |
479 | 0 |
|
480 | 0 | // XXXbz don't add in the border and padding, because we screw up our |
481 | 0 | // plugin's size and positioning if we do... Eventually we _do_ want to |
482 | 0 | // paint borders, though! At that point, we will need to adjust the desired |
483 | 0 | // size either here or in Reflow.... Further, we will need to fix Paint() to |
484 | 0 | // call the superclass in all cases. |
485 | 0 | } |
486 | | |
487 | | void |
488 | | nsPluginFrame::Reflow(nsPresContext* aPresContext, |
489 | | ReflowOutput& aMetrics, |
490 | | const ReflowInput& aReflowInput, |
491 | | nsReflowStatus& aStatus) |
492 | 0 | { |
493 | 0 | MarkInReflow(); |
494 | 0 | DO_GLOBAL_REFLOW_COUNT("nsPluginFrame"); |
495 | 0 | DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus); |
496 | 0 | MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); |
497 | 0 |
|
498 | 0 | // Get our desired size |
499 | 0 | GetDesiredSize(aPresContext, aReflowInput, aMetrics); |
500 | 0 | aMetrics.SetOverflowAreasToDesiredBounds(); |
501 | 0 | FinishAndStoreOverflow(&aMetrics); |
502 | 0 |
|
503 | 0 | // delay plugin instantiation until all children have |
504 | 0 | // arrived. Otherwise there may be PARAMs or other stuff that the |
505 | 0 | // plugin needs to see that haven't arrived yet. |
506 | 0 | if (!GetContent()->IsDoneAddingChildren()) { |
507 | 0 | return; |
508 | 0 | } |
509 | 0 | |
510 | 0 | // if we are printing or print previewing, bail for now |
511 | 0 | if (aPresContext->Medium() == nsGkAtoms::print) { |
512 | 0 | return; |
513 | 0 | } |
514 | 0 | |
515 | 0 | nsRect r(0, 0, aMetrics.Width(), aMetrics.Height()); |
516 | 0 | r.Deflate(aReflowInput.ComputedPhysicalBorderPadding()); |
517 | 0 |
|
518 | 0 | if (mInnerView) { |
519 | 0 | nsViewManager* vm = mInnerView->GetViewManager(); |
520 | 0 | vm->MoveViewTo(mInnerView, r.x, r.y); |
521 | 0 | vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), r.Size()), true); |
522 | 0 | } |
523 | 0 |
|
524 | 0 | FixupWindow(r.Size()); |
525 | 0 | if (!mReflowCallbackPosted) { |
526 | 0 | mReflowCallbackPosted = true; |
527 | 0 | aPresContext->PresShell()->PostReflowCallback(this); |
528 | 0 | } |
529 | 0 |
|
530 | 0 | NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics); |
531 | 0 | } |
532 | | |
533 | | ///////////// nsIReflowCallback /////////////// |
534 | | |
535 | | bool |
536 | | nsPluginFrame::ReflowFinished() |
537 | 0 | { |
538 | 0 | mReflowCallbackPosted = false; |
539 | 0 | CallSetWindow(); |
540 | 0 | return true; |
541 | 0 | } |
542 | | |
543 | | void |
544 | | nsPluginFrame::ReflowCallbackCanceled() |
545 | 0 | { |
546 | 0 | mReflowCallbackPosted = false; |
547 | 0 | } |
548 | | |
549 | | void |
550 | | nsPluginFrame::FixupWindow(const nsSize& aSize) |
551 | 0 | { |
552 | 0 | nsPresContext* presContext = PresContext(); |
553 | 0 |
|
554 | 0 | if (!mInstanceOwner) |
555 | 0 | return; |
556 | 0 | |
557 | 0 | NPWindow *window; |
558 | 0 | mInstanceOwner->GetWindow(window); |
559 | 0 |
|
560 | 0 | NS_ENSURE_TRUE_VOID(window); |
561 | 0 |
|
562 | 0 | bool windowless = (window->type == NPWindowTypeDrawable); |
563 | 0 |
|
564 | 0 | nsIntPoint origin = GetWindowOriginInPixels(windowless); |
565 | 0 |
|
566 | 0 | // window must be in "display pixels" |
567 | | #if defined(XP_MACOSX) |
568 | | // window must be in "display pixels" |
569 | | double scaleFactor = 1.0; |
570 | | if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) { |
571 | | scaleFactor = 1.0; |
572 | | } |
573 | | int intScaleFactor = ceil(scaleFactor); |
574 | | window->x = origin.x / intScaleFactor; |
575 | | window->y = origin.y / intScaleFactor; |
576 | | window->width = presContext->AppUnitsToDevPixels(aSize.width) / intScaleFactor; |
577 | | window->height = presContext->AppUnitsToDevPixels(aSize.height) / intScaleFactor; |
578 | | #else |
579 | | window->x = origin.x; |
580 | 0 | window->y = origin.y; |
581 | 0 | window->width = presContext->AppUnitsToDevPixels(aSize.width); |
582 | 0 | window->height = presContext->AppUnitsToDevPixels(aSize.height); |
583 | 0 | #endif |
584 | 0 |
|
585 | 0 | #ifndef XP_MACOSX |
586 | 0 | mInstanceOwner->UpdateWindowPositionAndClipRect(false); |
587 | 0 | #endif |
588 | 0 |
|
589 | 0 | NotifyPluginReflowObservers(); |
590 | 0 | } |
591 | | |
592 | | nsresult |
593 | | nsPluginFrame::CallSetWindow(bool aCheckIsHidden) |
594 | 0 | { |
595 | 0 | NPWindow *win = nullptr; |
596 | 0 |
|
597 | 0 | nsresult rv = NS_ERROR_FAILURE; |
598 | 0 | RefPtr<nsNPAPIPluginInstance> pi; |
599 | 0 | if (!mInstanceOwner || |
600 | 0 | NS_FAILED(rv = mInstanceOwner->GetInstance(getter_AddRefs(pi))) || |
601 | 0 | !pi || |
602 | 0 | NS_FAILED(rv = mInstanceOwner->GetWindow(win)) || |
603 | 0 | !win) |
604 | 0 | return rv; |
605 | 0 | |
606 | 0 | nsPluginNativeWindow *window = (nsPluginNativeWindow *)win; |
607 | 0 |
|
608 | 0 | if (aCheckIsHidden && IsHidden()) |
609 | 0 | return NS_ERROR_FAILURE; |
610 | 0 | |
611 | 0 | // Calling either nsPluginInstanceOwner::FixUpPluginWindow() (here, |
612 | 0 | // on OS X) or SetWindow() (below, on all platforms) can destroy this |
613 | 0 | // frame. (FixUpPluginWindow() calls SetWindow()). So grab a safe |
614 | 0 | // reference to mInstanceOwner which we can use below, if needed. |
615 | 0 | RefPtr<nsPluginInstanceOwner> instanceOwnerRef(mInstanceOwner); |
616 | 0 |
|
617 | 0 | // refresh the plugin port as well |
618 | | #ifdef XP_MACOSX |
619 | | mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable); |
620 | | // Bail now if our frame has been destroyed. |
621 | | if (!instanceOwnerRef->GetFrame()) { |
622 | | return NS_ERROR_FAILURE; |
623 | | } |
624 | | #endif |
625 | | window->window = mInstanceOwner->GetPluginPort(); |
626 | 0 |
|
627 | 0 | // Adjust plugin dimensions according to pixel snap results |
628 | 0 | // and reduce amount of SetWindow calls |
629 | 0 | nsPresContext* presContext = PresContext(); |
630 | 0 | nsRootPresContext* rootPC = presContext->GetRootPresContext(); |
631 | 0 | if (!rootPC) |
632 | 0 | return NS_ERROR_FAILURE; |
633 | 0 | int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); |
634 | 0 | nsIFrame* rootFrame = rootPC->PresShell()->GetRootFrame(); |
635 | 0 | nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame); |
636 | 0 | nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel); |
637 | 0 |
|
638 | 0 | // In e10s, this returns the offset to the top level window, in non-e10s |
639 | 0 | // it return 0,0. |
640 | 0 | LayoutDeviceIntPoint intOffset = GetRemoteTabChromeOffset(); |
641 | 0 | intBounds.x += intOffset.x; |
642 | 0 | intBounds.y += intOffset.y; |
643 | 0 |
|
644 | | #if defined(XP_MACOSX) |
645 | | // window must be in "display pixels" |
646 | | double scaleFactor = 1.0; |
647 | | if (NS_FAILED(instanceOwnerRef->GetContentsScaleFactor(&scaleFactor))) { |
648 | | scaleFactor = 1.0; |
649 | | } |
650 | | |
651 | | size_t intScaleFactor = ceil(scaleFactor); |
652 | | window->x = intBounds.x / intScaleFactor; |
653 | | window->y = intBounds.y / intScaleFactor; |
654 | | window->width = intBounds.width / intScaleFactor; |
655 | | window->height = intBounds.height / intScaleFactor; |
656 | | #else |
657 | | window->x = intBounds.x; |
658 | 0 | window->y = intBounds.y; |
659 | 0 | window->width = intBounds.width; |
660 | 0 | window->height = intBounds.height; |
661 | 0 | #endif |
662 | 0 | // BE CAREFUL: By the time we get here the PluginFrame is sometimes destroyed |
663 | 0 | // and poisoned. If we reference local fields (implicit this deref), |
664 | 0 | // we will crash. |
665 | 0 | instanceOwnerRef->ResolutionMayHaveChanged(); |
666 | 0 |
|
667 | 0 | // This will call pi->SetWindow and take care of window subclassing |
668 | 0 | // if needed, see bug 132759. Calling SetWindow can destroy this frame |
669 | 0 | // so check for that before doing anything else with this frame's memory. |
670 | 0 | if (instanceOwnerRef->UseAsyncRendering()) { |
671 | 0 | rv = pi->AsyncSetWindow(window); |
672 | 0 | } |
673 | 0 | else { |
674 | 0 | rv = window->CallSetWindow(pi); |
675 | 0 | } |
676 | 0 |
|
677 | 0 | instanceOwnerRef->ReleasePluginPort(window->window); |
678 | 0 |
|
679 | 0 | return rv; |
680 | 0 | } |
681 | | |
682 | | void |
683 | | nsPluginFrame::RegisterPluginForGeometryUpdates() |
684 | 0 | { |
685 | 0 | nsRootPresContext* rpc = PresContext()->GetRootPresContext(); |
686 | 0 | NS_ASSERTION(rpc, "We should have a root pres context!"); |
687 | 0 | if (mRootPresContextRegisteredWith == rpc || !rpc) { |
688 | 0 | // Already registered with current root pres context, |
689 | 0 | // or null root pres context... |
690 | 0 | return; |
691 | 0 | } |
692 | 0 | if (mRootPresContextRegisteredWith && mRootPresContextRegisteredWith != rpc) { |
693 | 0 | // Registered to some other root pres context. Unregister, and |
694 | 0 | // re-register with our current one... |
695 | 0 | UnregisterPluginForGeometryUpdates(); |
696 | 0 | } |
697 | 0 | mRootPresContextRegisteredWith = rpc; |
698 | 0 | mRootPresContextRegisteredWith->RegisterPluginForGeometryUpdates(mContent); |
699 | 0 | } |
700 | | |
701 | | void |
702 | | nsPluginFrame::UnregisterPluginForGeometryUpdates() |
703 | 0 | { |
704 | 0 | if (!mRootPresContextRegisteredWith) { |
705 | 0 | // Not registered... |
706 | 0 | return; |
707 | 0 | } |
708 | 0 | mRootPresContextRegisteredWith->UnregisterPluginForGeometryUpdates(mContent); |
709 | 0 | mRootPresContextRegisteredWith = nullptr; |
710 | 0 | } |
711 | | |
712 | | void |
713 | | nsPluginFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner) |
714 | 0 | { |
715 | 0 | // The ownership model here is historically fuzzy. This should only be called |
716 | 0 | // by nsPluginInstanceOwner when it is given a new frame, and |
717 | 0 | // nsObjectLoadingContent should be arbitrating frame-ownership via its |
718 | 0 | // HasNewFrame callback. |
719 | 0 | mInstanceOwner = aOwner; |
720 | 0 |
|
721 | 0 | // Reset the DidCompositeObserver since the owner changed. |
722 | 0 | mDidCompositeObserver = nullptr; |
723 | 0 |
|
724 | 0 | if (mInstanceOwner) { |
725 | 0 | return; |
726 | 0 | } |
727 | 0 | |
728 | 0 | UnregisterPluginForGeometryUpdates(); |
729 | 0 | if (mWidget && mInnerView) { |
730 | 0 | mInnerView->DetachWidgetEventHandler(mWidget); |
731 | 0 | // Make sure the plugin is hidden in case an update of plugin geometry |
732 | 0 | // hasn't happened since this plugin became hidden. |
733 | 0 | nsIWidget* parent = mWidget->GetParent(); |
734 | 0 | if (parent) { |
735 | 0 | nsTArray<nsIWidget::Configuration> configurations; |
736 | 0 | nsIWidget::Configuration* configuration = configurations.AppendElement(); |
737 | 0 | configuration->mChild = mWidget; |
738 | 0 | parent->ConfigureChildren(configurations); |
739 | 0 |
|
740 | 0 | mWidget->Show(false); |
741 | 0 | mWidget->Enable(false); |
742 | 0 | mWidget->SetParent(nullptr); |
743 | 0 | } |
744 | 0 | } |
745 | 0 | } |
746 | | |
747 | | bool |
748 | | nsPluginFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse) |
749 | 0 | { |
750 | 0 | if (aTabIndex) |
751 | 0 | *aTabIndex = -1; |
752 | 0 | return nsFrame::IsFocusable(aTabIndex, aWithMouse); |
753 | 0 | } |
754 | | |
755 | | bool |
756 | | nsPluginFrame::IsHidden(bool aCheckVisibilityStyle) const |
757 | 0 | { |
758 | 0 | if (aCheckVisibilityStyle) { |
759 | 0 | if (!StyleVisibility()->IsVisibleOrCollapsed()) |
760 | 0 | return true; |
761 | 0 | } |
762 | 0 | |
763 | 0 | // only <embed> tags support the HIDDEN attribute |
764 | 0 | if (mContent->IsHTMLElement(nsGkAtoms::embed)) { |
765 | 0 | // Yes, these are really the kooky ways that you could tell 4.x |
766 | 0 | // not to hide the <embed> once you'd put the 'hidden' attribute |
767 | 0 | // on the tag... |
768 | 0 |
|
769 | 0 | // HIDDEN w/ no attributes gets translated as we are hidden for |
770 | 0 | // compatibility w/ 4.x and IE so we don't create a non-painting |
771 | 0 | // widget in layout. See bug 188959. |
772 | 0 | nsAutoString hidden; |
773 | 0 | if (mContent->AsElement()->GetAttr(kNameSpaceID_None, |
774 | 0 | nsGkAtoms::hidden, |
775 | 0 | hidden) && |
776 | 0 | (hidden.IsEmpty() || |
777 | 0 | (!hidden.LowerCaseEqualsLiteral("false") && |
778 | 0 | !hidden.LowerCaseEqualsLiteral("no") && |
779 | 0 | !hidden.LowerCaseEqualsLiteral("off")))) { |
780 | 0 | return true; |
781 | 0 | } |
782 | 0 | } |
783 | 0 | |
784 | 0 | return false; |
785 | 0 | } |
786 | | |
787 | | mozilla::LayoutDeviceIntPoint |
788 | | nsPluginFrame::GetRemoteTabChromeOffset() |
789 | 0 | { |
790 | 0 | LayoutDeviceIntPoint offset; |
791 | 0 | if (XRE_IsContentProcess()) { |
792 | 0 | if (nsPIDOMWindowOuter* window = GetContent()->OwnerDoc()->GetWindow()) { |
793 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetTop()) { |
794 | 0 | dom::TabChild* tc = dom::TabChild::GetFrom(topWindow); |
795 | 0 | if (tc) { |
796 | 0 | offset += tc->GetChromeOffset(); |
797 | 0 | } |
798 | 0 | } |
799 | 0 | } |
800 | 0 | } |
801 | 0 | return offset; |
802 | 0 | } |
803 | | |
804 | | nsIntPoint |
805 | | nsPluginFrame::GetWindowOriginInPixels(bool aWindowless) |
806 | 0 | { |
807 | 0 | nsView * parentWithView; |
808 | 0 | nsPoint origin(0,0); |
809 | 0 |
|
810 | 0 | GetOffsetFromView(origin, &parentWithView); |
811 | 0 |
|
812 | 0 | // if it's windowless, let's make sure we have our origin set right |
813 | 0 | // it may need to be corrected, like after scrolling |
814 | 0 | if (aWindowless && parentWithView) { |
815 | 0 | nsPoint offsetToWidget; |
816 | 0 | parentWithView->GetNearestWidget(&offsetToWidget); |
817 | 0 | origin += offsetToWidget; |
818 | 0 | } |
819 | 0 | origin += GetContentRectRelativeToSelf().TopLeft(); |
820 | 0 |
|
821 | 0 | nsIntPoint pt(PresContext()->AppUnitsToDevPixels(origin.x), |
822 | 0 | PresContext()->AppUnitsToDevPixels(origin.y)); |
823 | 0 |
|
824 | 0 | // If we're in the content process offsetToWidget is tied to the top level |
825 | 0 | // widget we can access in the child process, which is the tab. We need the |
826 | 0 | // offset all the way up to the top level native window here. (If this is |
827 | 0 | // non-e10s this routine will return 0,0.) |
828 | 0 | if (aWindowless) { |
829 | 0 | mozilla::LayoutDeviceIntPoint lpt = GetRemoteTabChromeOffset(); |
830 | 0 | pt += nsIntPoint(lpt.x, lpt.y); |
831 | 0 | } |
832 | 0 |
|
833 | 0 | return pt; |
834 | 0 | } |
835 | | |
836 | | void |
837 | | nsPluginFrame::DidReflow(nsPresContext* aPresContext, |
838 | | const ReflowInput* aReflowInput) |
839 | 0 | { |
840 | 0 | // Do this check before calling the superclass, as that clears |
841 | 0 | // NS_FRAME_FIRST_REFLOW |
842 | 0 | if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { |
843 | 0 | nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent)); |
844 | 0 | NS_ASSERTION(objContent, "Why not an object loading content?"); |
845 | 0 | objContent->HasNewFrame(this); |
846 | 0 | } |
847 | 0 |
|
848 | 0 | nsFrame::DidReflow(aPresContext, aReflowInput); |
849 | 0 |
|
850 | 0 | if (HasView()) { |
851 | 0 | nsView* view = GetView(); |
852 | 0 | nsViewManager* vm = view->GetViewManager(); |
853 | 0 | if (vm) |
854 | 0 | vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow); |
855 | 0 | } |
856 | 0 | } |
857 | | |
858 | | /* static */ void |
859 | | nsPluginFrame::PaintPrintPlugin(nsIFrame* aFrame, gfxContext* aCtx, |
860 | | const nsRect& aDirtyRect, nsPoint aPt) |
861 | 0 | { |
862 | 0 | // Translate the context: |
863 | 0 | nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft(); |
864 | 0 | gfxPoint devPixelPt = |
865 | 0 | nsLayoutUtils::PointToGfxPoint(pt, aFrame->PresContext()->AppUnitsPerDevPixel()); |
866 | 0 |
|
867 | 0 | gfxContextMatrixAutoSaveRestore autoSR(aCtx); |
868 | 0 | aCtx->SetMatrixDouble(aCtx->CurrentMatrixDouble().PreTranslate(devPixelPt)); |
869 | 0 |
|
870 | 0 | // FIXME - Bug 385435: Doesn't aDirtyRect need translating too? |
871 | 0 |
|
872 | 0 | static_cast<nsPluginFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect); |
873 | 0 | } |
874 | | |
875 | | /** |
876 | | * nsDisplayPluginReadback creates an active ReadbackLayer. The ReadbackLayer |
877 | | * obtains from the compositor the contents of the window underneath |
878 | | * the ReadbackLayer, which we then use as an opaque buffer for plugins to |
879 | | * asynchronously draw onto. |
880 | | */ |
881 | | class nsDisplayPluginReadback : public nsDisplayItem { |
882 | | public: |
883 | | nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) |
884 | | : nsDisplayItem(aBuilder, aFrame) |
885 | 0 | { |
886 | 0 | MOZ_COUNT_CTOR(nsDisplayPluginReadback); |
887 | 0 | } |
888 | | #ifdef NS_BUILD_REFCNT_LOGGING |
889 | | ~nsDisplayPluginReadback() override { |
890 | | MOZ_COUNT_DTOR(nsDisplayPluginReadback); |
891 | | } |
892 | | #endif |
893 | | |
894 | | nsRect GetBounds(nsDisplayListBuilder* aBuilder, |
895 | | bool* aSnap) const override; |
896 | | |
897 | | NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK) |
898 | | |
899 | | already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, |
900 | | LayerManager* aManager, |
901 | | const ContainerLayerParameters& aContainerParameters) override |
902 | 0 | { |
903 | 0 | return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters); |
904 | 0 | } |
905 | | |
906 | | LayerState GetLayerState(nsDisplayListBuilder* aBuilder, |
907 | | LayerManager* aManager, |
908 | | const ContainerLayerParameters& aParameters) override |
909 | 0 | { |
910 | 0 | return LAYER_ACTIVE; |
911 | 0 | } |
912 | | |
913 | | virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override |
914 | 0 | { |
915 | 0 | return new nsDisplayPluginGeometry(this, aBuilder); |
916 | 0 | } |
917 | | }; |
918 | | |
919 | | static nsRect |
920 | | GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, |
921 | | const nsDisplayItem* aItem, |
922 | | nsIFrame* aFrame) |
923 | 0 | { |
924 | 0 | // XXX For slightly more accurate region computations we should pixel-snap this |
925 | 0 | return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame(); |
926 | 0 | } |
927 | | |
928 | | nsRect |
929 | | nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, |
930 | | bool* aSnap) const |
931 | 0 | { |
932 | 0 | *aSnap = false; |
933 | 0 | return GetDisplayItemBounds(aBuilder, this, mFrame); |
934 | 0 | } |
935 | | |
936 | | nsRect |
937 | | nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const |
938 | 0 | { |
939 | 0 | *aSnap = true; |
940 | 0 | return GetDisplayItemBounds(aBuilder, this, mFrame); |
941 | 0 | } |
942 | | |
943 | | void |
944 | | nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder, |
945 | | gfxContext* aCtx) |
946 | 0 | { |
947 | 0 | nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame); |
948 | 0 | bool snap; |
949 | 0 | f->PaintPlugin(aBuilder, *aCtx, GetPaintRect(), GetBounds(aBuilder, &snap)); |
950 | 0 | } |
951 | | |
952 | | static nsRect |
953 | | GetClippedBoundsIncludingAllScrollClips(nsDisplayItem* aItem, |
954 | | nsDisplayListBuilder* aBuilder) |
955 | 0 | { |
956 | 0 | nsRect r = aItem->GetClippedBounds(aBuilder); |
957 | 0 | for (auto* sc = aItem->GetClipChain(); sc; sc = sc->mParent) { |
958 | 0 | r = sc->mClip.ApplyNonRoundedIntersection(r); |
959 | 0 | } |
960 | 0 | return r; |
961 | 0 | } |
962 | | |
963 | | bool |
964 | | nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder, |
965 | | nsRegion* aVisibleRegion) |
966 | 0 | { |
967 | 0 | if (aBuilder->IsForPluginGeometry()) { |
968 | 0 | nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame); |
969 | 0 | if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) { |
970 | 0 | // Since transforms induce reference frames, we don't need to worry |
971 | 0 | // about this method fluffing out due to non-rectilinear transforms. |
972 | 0 | nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(f, |
973 | 0 | f->GetContentRectRelativeToSelf(), ReferenceFrame()); |
974 | 0 | nscoord appUnitsPerDevPixel = |
975 | 0 | ReferenceFrame()->PresContext()->AppUnitsPerDevPixel(); |
976 | 0 | f->mNextConfigurationBounds = LayoutDeviceIntRect::FromUnknownRect( |
977 | 0 | rAncestor.ToNearestPixels(appUnitsPerDevPixel)); |
978 | 0 |
|
979 | 0 | nsRegion visibleRegion; |
980 | 0 | // Apply all scroll clips when computing the clipped bounds of this item. |
981 | 0 | // We hide windowed plugins during APZ scrolling, so there never is an |
982 | 0 | // async transform that we need to take into account when clipping. |
983 | 0 | visibleRegion.And(*aVisibleRegion, GetClippedBoundsIncludingAllScrollClips(this, aBuilder)); |
984 | 0 | // Make visibleRegion relative to f |
985 | 0 | visibleRegion.MoveBy(-ToReferenceFrame()); |
986 | 0 |
|
987 | 0 | f->mNextConfigurationClipRegion.Clear(); |
988 | 0 | for (auto iter = visibleRegion.RectIter(); !iter.Done(); iter.Next()) { |
989 | 0 | nsRect rAncestor = |
990 | 0 | nsLayoutUtils::TransformFrameRectToAncestor(f, iter.Get(), ReferenceFrame()); |
991 | 0 | LayoutDeviceIntRect rPixels = |
992 | 0 | LayoutDeviceIntRect::FromUnknownRect(rAncestor.ToNearestPixels(appUnitsPerDevPixel)) - |
993 | 0 | f->mNextConfigurationBounds.TopLeft(); |
994 | 0 | if (!rPixels.IsEmpty()) { |
995 | 0 | f->mNextConfigurationClipRegion.AppendElement(rPixels); |
996 | 0 | } |
997 | 0 | } |
998 | 0 | } |
999 | 0 |
|
1000 | 0 | if (f->mInnerView) { |
1001 | 0 | // This should produce basically the same rectangle (but not relative |
1002 | 0 | // to the root frame). We only call this here for the side-effect of |
1003 | 0 | // setting mViewToWidgetOffset on the view. |
1004 | 0 | f->mInnerView->CalcWidgetBounds(eWindowType_plugin); |
1005 | 0 | } |
1006 | 0 | } |
1007 | 0 |
|
1008 | 0 | return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion); |
1009 | 0 | } |
1010 | | |
1011 | | nsRegion |
1012 | | nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, |
1013 | | bool* aSnap) const |
1014 | 0 | { |
1015 | 0 | *aSnap = false; |
1016 | 0 | nsRegion result; |
1017 | 0 | nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame); |
1018 | 0 | if (!aBuilder->IsForPluginGeometry()) { |
1019 | 0 | nsIWidget* widget = f->GetWidget(); |
1020 | 0 | if (widget) { |
1021 | 0 | // Be conservative and treat plugins with widgets as not opaque, |
1022 | 0 | // because that's simple and we might need the content under the widget |
1023 | 0 | // if the widget is unexpectedly clipped away. (As can happen when |
1024 | 0 | // chrome content over a plugin forces us to clip out the plugin for |
1025 | 0 | // security reasons.) |
1026 | 0 | // We shouldn't be repainting the content under plugins much anyway |
1027 | 0 | // since there generally shouldn't be anything to invalidate or paint |
1028 | 0 | // in PaintedLayers there. |
1029 | 0 | return result; |
1030 | 0 | } |
1031 | 0 | } |
1032 | 0 | |
1033 | 0 | if (f->IsOpaque()) { |
1034 | 0 | nsRect bounds = GetBounds(aBuilder, aSnap); |
1035 | 0 | if (aBuilder->IsForPluginGeometry() || |
1036 | 0 | (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(bounds)) { |
1037 | 0 | // We can treat this as opaque |
1038 | 0 | result = bounds; |
1039 | 0 | } |
1040 | 0 | } |
1041 | 0 |
|
1042 | 0 | return result; |
1043 | 0 | } |
1044 | | |
1045 | | bool |
1046 | | nsDisplayPlugin::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder, |
1047 | | mozilla::wr::IpcResourceUpdateQueue& aResources, |
1048 | | const StackingContextHelper& aSc, |
1049 | | mozilla::layers::WebRenderLayerManager* aManager, |
1050 | | nsDisplayListBuilder* aDisplayListBuilder) |
1051 | 0 | { |
1052 | 0 | return static_cast<nsPluginFrame*>(mFrame)->CreateWebRenderCommands(this, |
1053 | 0 | aBuilder, |
1054 | 0 | aResources, |
1055 | 0 | aSc, |
1056 | 0 | aManager, |
1057 | 0 | aDisplayListBuilder); |
1058 | 0 | } |
1059 | | |
1060 | | nsresult |
1061 | 0 | nsPluginFrame::PluginEventNotifier::Run() { |
1062 | 0 | nsCOMPtr<nsIObserverService> obsSvc = |
1063 | 0 | mozilla::services::GetObserverService(); |
1064 | 0 | obsSvc->NotifyObservers(nullptr, "plugin-changed-event", mEventType.get()); |
1065 | 0 | return NS_OK; |
1066 | 0 | } |
1067 | | |
1068 | | void |
1069 | | nsPluginFrame::NotifyPluginReflowObservers() |
1070 | 0 | { |
1071 | 0 | nsContentUtils::AddScriptRunner(new PluginEventNotifier(NS_LITERAL_STRING("reflow"))); |
1072 | 0 | } |
1073 | | |
1074 | | void |
1075 | | nsPluginFrame::DidSetWidgetGeometry() |
1076 | 0 | { |
1077 | | #if defined(XP_MACOSX) |
1078 | | if (mInstanceOwner && !IsHidden()) { |
1079 | | mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable); |
1080 | | } |
1081 | | #else |
1082 | 0 | if (!mWidget && mInstanceOwner) { |
1083 | 0 | // UpdateWindowVisibility will notify the plugin of position changes |
1084 | 0 | // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow. |
1085 | 0 | // We treat windowless plugins inside popups as always visible, since |
1086 | 0 | // plugins inside popups don't get valid mNextConfigurationBounds |
1087 | 0 | // set up. |
1088 | 0 | mInstanceOwner->UpdateWindowVisibility( |
1089 | 0 | nsLayoutUtils::IsPopup(nsLayoutUtils::GetDisplayRootFrame(this)) || |
1090 | 0 | !mNextConfigurationBounds.IsEmpty()); |
1091 | 0 | } |
1092 | 0 | #endif |
1093 | 0 | } |
1094 | | |
1095 | | bool |
1096 | | nsPluginFrame::IsOpaque() const |
1097 | 0 | { |
1098 | | #if defined(XP_MACOSX) |
1099 | | return false; |
1100 | | #else |
1101 | |
|
1102 | 0 | if (mInstanceOwner && mInstanceOwner->UseAsyncRendering()) { |
1103 | 0 | return false; |
1104 | 0 | } |
1105 | 0 | return !IsTransparentMode(); |
1106 | 0 | #endif |
1107 | 0 | } |
1108 | | |
1109 | | bool |
1110 | | nsPluginFrame::IsTransparentMode() const |
1111 | 0 | { |
1112 | | #if defined(XP_MACOSX) |
1113 | | return false; |
1114 | | #else |
1115 | 0 | if (!mInstanceOwner) |
1116 | 0 | return false; |
1117 | 0 | |
1118 | 0 | NPWindow *window = nullptr; |
1119 | 0 | mInstanceOwner->GetWindow(window); |
1120 | 0 | if (!window) { |
1121 | 0 | return false; |
1122 | 0 | } |
1123 | 0 | |
1124 | 0 | if (window->type != NPWindowTypeDrawable) |
1125 | 0 | return false; |
1126 | 0 | |
1127 | 0 | nsresult rv; |
1128 | 0 | RefPtr<nsNPAPIPluginInstance> pi; |
1129 | 0 | rv = mInstanceOwner->GetInstance(getter_AddRefs(pi)); |
1130 | 0 | if (NS_FAILED(rv) || !pi) |
1131 | 0 | return false; |
1132 | 0 | |
1133 | 0 | bool transparent = false; |
1134 | 0 | pi->IsTransparent(&transparent); |
1135 | 0 | return transparent; |
1136 | 0 | #endif |
1137 | 0 | } |
1138 | | |
1139 | | void |
1140 | | nsPluginFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
1141 | | const nsDisplayListSet& aLists) |
1142 | 0 | { |
1143 | 0 | // XXX why are we painting collapsed object frames? |
1144 | 0 | if (!IsVisibleOrCollapsedForPainting(aBuilder)) |
1145 | 0 | return; |
1146 | 0 | |
1147 | 0 | DisplayBorderBackgroundOutline(aBuilder, aLists); |
1148 | 0 |
|
1149 | 0 | nsPresContext::nsPresContextType type = PresContext()->Type(); |
1150 | 0 |
|
1151 | 0 | // If we are painting in Print Preview do nothing.... |
1152 | 0 | if (type == nsPresContext::eContext_PrintPreview) |
1153 | 0 | return; |
1154 | 0 | |
1155 | 0 | DO_GLOBAL_REFLOW_COUNT_DSP("nsPluginFrame"); |
1156 | 0 |
|
1157 | 0 | #ifndef XP_MACOSX |
1158 | 0 | if (mWidget && aBuilder->IsInTransform()) { |
1159 | 0 | // Windowed plugins should not be rendered inside a transform. |
1160 | 0 | return; |
1161 | 0 | } |
1162 | 0 | #endif |
1163 | 0 | |
1164 | 0 | if (aBuilder->IsForPainting() && mInstanceOwner) { |
1165 | 0 | // Update plugin frame for both content scaling and full zoom changes. |
1166 | 0 | mInstanceOwner->ResolutionMayHaveChanged(); |
1167 | | #ifdef XP_MACOSX |
1168 | | mInstanceOwner->WindowFocusMayHaveChanged(); |
1169 | | #endif |
1170 | 0 | if (mInstanceOwner->UseAsyncRendering()) { |
1171 | 0 | NPWindow* window = nullptr; |
1172 | 0 | mInstanceOwner->GetWindow(window); |
1173 | 0 | bool isVisible = window && window->width > 0 && window->height > 0; |
1174 | 0 | if (isVisible && aBuilder->ShouldSyncDecodeImages()) { |
1175 | 0 | #ifndef XP_MACOSX |
1176 | 0 | mInstanceOwner->UpdateWindowVisibility(true); |
1177 | 0 | #endif |
1178 | 0 | } |
1179 | 0 |
|
1180 | 0 | mInstanceOwner->NotifyPaintWaiter(aBuilder); |
1181 | 0 | } |
1182 | 0 | } |
1183 | 0 |
|
1184 | 0 | DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox |
1185 | 0 | clip(aBuilder, this); |
1186 | 0 |
|
1187 | 0 | // determine if we are printing |
1188 | 0 | if (type == nsPresContext::eContext_Print) { |
1189 | 0 | aLists.Content()->AppendToTop( |
1190 | 0 | MakeDisplayItem<nsDisplayGeneric>(aBuilder, this, PaintPrintPlugin, "PrintPlugin", |
1191 | 0 | DisplayItemType::TYPE_PRINT_PLUGIN)); |
1192 | 0 | } else { |
1193 | 0 | LayerState state = GetLayerState(aBuilder, nullptr); |
1194 | 0 | if (state == LAYER_INACTIVE && |
1195 | 0 | nsDisplayItem::ForceActiveLayers()) { |
1196 | 0 | state = LAYER_ACTIVE; |
1197 | 0 | } |
1198 | 0 | if (aBuilder->IsPaintingToWindow() && |
1199 | 0 | state == LAYER_ACTIVE && |
1200 | 0 | IsTransparentMode()) { |
1201 | 0 | aLists.Content()->AppendToTop( |
1202 | 0 | MakeDisplayItem<nsDisplayPluginReadback>(aBuilder, this)); |
1203 | 0 | } |
1204 | 0 |
|
1205 | 0 | aLists.Content()->AppendToTop( |
1206 | 0 | MakeDisplayItem<nsDisplayPlugin>(aBuilder, this)); |
1207 | 0 | } |
1208 | 0 | } |
1209 | | |
1210 | | void |
1211 | | nsPluginFrame::PrintPlugin(gfxContext& aRenderingContext, |
1212 | | const nsRect& aDirtyRect) |
1213 | 0 | { |
1214 | 0 | nsCOMPtr<nsIObjectLoadingContent> obj(do_QueryInterface(mContent)); |
1215 | 0 | if (!obj) |
1216 | 0 | return; |
1217 | 0 | |
1218 | 0 | nsIFrame* frame = nullptr; |
1219 | 0 | obj->GetPrintFrame(&frame); |
1220 | 0 | if (!frame) |
1221 | 0 | return; |
1222 | 0 | |
1223 | 0 | nsPresContext* presContext = PresContext(); |
1224 | 0 | // make sure this is REALLY an nsIObjectFrame |
1225 | 0 | // we may need to go through the children to get it |
1226 | 0 | nsIObjectFrame* objectFrame = do_QueryFrame(frame); |
1227 | 0 | if (!objectFrame) |
1228 | 0 | objectFrame = GetNextObjectFrame(presContext,frame); |
1229 | 0 | if (!objectFrame) |
1230 | 0 | return; |
1231 | 0 | |
1232 | 0 | // finally we can get our plugin instance |
1233 | 0 | RefPtr<nsNPAPIPluginInstance> pi; |
1234 | 0 | if (NS_FAILED(objectFrame->GetPluginInstance(getter_AddRefs(pi))) || !pi) |
1235 | 0 | return; |
1236 | 0 | |
1237 | 0 | // now we need to setup the correct location for printing |
1238 | 0 | NPWindow window; |
1239 | 0 | window.window = nullptr; |
1240 | 0 |
|
1241 | 0 | // prepare embedded mode printing struct |
1242 | 0 | NPPrint npprint; |
1243 | 0 | npprint.mode = NP_EMBED; |
1244 | 0 |
|
1245 | 0 | // we need to find out if we are windowless or not |
1246 | 0 | bool windowless = false; |
1247 | 0 | pi->IsWindowless(&windowless); |
1248 | 0 | window.type = windowless ? NPWindowTypeDrawable : NPWindowTypeWindow; |
1249 | 0 |
|
1250 | 0 | window.clipRect.bottom = 0; window.clipRect.top = 0; |
1251 | 0 | window.clipRect.left = 0; window.clipRect.right = 0; |
1252 | 0 |
|
1253 | 0 | // platform specific printing code |
1254 | 0 | #if defined(XP_UNIX) || defined(XP_MACOSX) |
1255 | 0 | // Doesn't work in a thebes world, or on OS X. |
1256 | 0 | (void)window; |
1257 | 0 | (void)npprint; |
1258 | | #elif defined(XP_WIN) |
1259 | | |
1260 | | /* On Windows, we use the win32 printing surface to print. This, in |
1261 | | * turn, uses the Cairo paginated surface, which in turn uses the |
1262 | | * meta surface to record all operations and then play them back. |
1263 | | * This doesn't work too well for plugins, because if plugins render |
1264 | | * directly into the DC, the meta surface won't have any knowledge |
1265 | | * of them, and so at the end when it actually does the replay step, |
1266 | | * it'll fill the background with white and draw over whatever was |
1267 | | * rendered before. |
1268 | | * |
1269 | | * So, to avoid this, we use PushGroup, which creates a new windows |
1270 | | * surface, the plugin renders to that, and then we use normal |
1271 | | * cairo methods to composite that in such that it's recorded using the |
1272 | | * meta surface. |
1273 | | */ |
1274 | | |
1275 | | /* we'll already be translated into the right spot by gfxWindowsNativeDrawing */ |
1276 | | nsSize contentSize = GetContentRectRelativeToSelf().Size(); |
1277 | | window.x = 0; |
1278 | | window.y = 0; |
1279 | | window.width = presContext->AppUnitsToDevPixels(contentSize.width); |
1280 | | window.height = presContext->AppUnitsToDevPixels(contentSize.height); |
1281 | | |
1282 | | aRenderingContext.Save(); |
1283 | | |
1284 | | /* Make sure plugins don't do any damage outside of where they're supposed to */ |
1285 | | aRenderingContext.NewPath(); |
1286 | | gfxRect r(window.x, window.y, window.width, window.height); |
1287 | | aRenderingContext.Rectangle(r); |
1288 | | aRenderingContext.Clip(); |
1289 | | |
1290 | | gfxWindowsNativeDrawing nativeDraw(&aRenderingContext, r); |
1291 | | do { |
1292 | | HDC dc = nativeDraw.BeginNativeDrawing(); |
1293 | | if (!dc) |
1294 | | return; |
1295 | | |
1296 | | // XXX don't we need to call nativeDraw.TransformToNativeRect here? |
1297 | | npprint.print.embedPrint.platformPrint = dc; |
1298 | | npprint.print.embedPrint.window = window; |
1299 | | // send off print info to plugin |
1300 | | pi->Print(&npprint); |
1301 | | |
1302 | | nativeDraw.EndNativeDrawing(); |
1303 | | } while (nativeDraw.ShouldRenderAgain()); |
1304 | | nativeDraw.PaintToContext(); |
1305 | | |
1306 | | aRenderingContext.Restore(); |
1307 | | #endif |
1308 | |
|
1309 | 0 | // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same? |
1310 | 0 | // XXX Calling DidReflow here makes no sense!!! |
1311 | 0 | frame->DidReflow(presContext, nullptr); // DidReflow will take care of it |
1312 | 0 | } |
1313 | | |
1314 | | nsRect |
1315 | | nsPluginFrame::GetPaintedRect(const nsDisplayPlugin* aItem) const |
1316 | 0 | { |
1317 | 0 | if (!mInstanceOwner) |
1318 | 0 | return nsRect(); |
1319 | 0 | nsRect r = GetContentRectRelativeToSelf(); |
1320 | 0 | if (!mInstanceOwner->UseAsyncRendering()) |
1321 | 0 | return r; |
1322 | 0 | |
1323 | 0 | nsIntSize size = mInstanceOwner->GetCurrentImageSize(); |
1324 | 0 | nsPresContext* pc = PresContext(); |
1325 | 0 | r.IntersectRect(r, nsRect(0, 0, pc->DevPixelsToAppUnits(size.width), |
1326 | 0 | pc->DevPixelsToAppUnits(size.height))); |
1327 | 0 | return r; |
1328 | 0 | } |
1329 | | |
1330 | | LayerState |
1331 | | nsPluginFrame::GetLayerState(nsDisplayListBuilder* aBuilder, |
1332 | | LayerManager* aManager) |
1333 | 0 | { |
1334 | 0 | if (!mInstanceOwner) |
1335 | 0 | return LAYER_NONE; |
1336 | 0 | |
1337 | 0 | if (mInstanceOwner->NeedsScrollImageLayer()) { |
1338 | 0 | return LAYER_ACTIVE; |
1339 | 0 | } |
1340 | 0 | |
1341 | 0 | if (!mInstanceOwner->UseAsyncRendering()) { |
1342 | 0 | return LAYER_NONE; |
1343 | 0 | } |
1344 | 0 | |
1345 | 0 | return LAYER_ACTIVE_FORCE; |
1346 | 0 | } |
1347 | | |
1348 | | class PluginFrameDidCompositeObserver final : public DidCompositeObserver |
1349 | | { |
1350 | | public: |
1351 | | PluginFrameDidCompositeObserver(nsPluginInstanceOwner* aOwner, LayerManager* aLayerManager) |
1352 | | : mInstanceOwner(aOwner), |
1353 | | mLayerManager(aLayerManager) |
1354 | 0 | { |
1355 | 0 | } |
1356 | 0 | ~PluginFrameDidCompositeObserver() { |
1357 | 0 | mLayerManager->RemoveDidCompositeObserver(this); |
1358 | 0 | } |
1359 | 0 | void DidComposite() override { |
1360 | 0 | mInstanceOwner->DidComposite(); |
1361 | 0 | } |
1362 | 0 | bool IsValid(LayerManager* aLayerManager) { |
1363 | 0 | return aLayerManager == mLayerManager; |
1364 | 0 | } |
1365 | | |
1366 | | private: |
1367 | | nsPluginInstanceOwner* mInstanceOwner; |
1368 | | RefPtr<LayerManager> mLayerManager; |
1369 | | }; |
1370 | | |
1371 | | bool |
1372 | | nsPluginFrame::GetBounds(nsDisplayItem* aItem, IntSize& aSize, gfxRect& aRect) |
1373 | 0 | { |
1374 | 0 | if (!mInstanceOwner) |
1375 | 0 | return false; |
1376 | 0 | |
1377 | 0 | NPWindow* window = nullptr; |
1378 | 0 | mInstanceOwner->GetWindow(window); |
1379 | 0 | if (!window) |
1380 | 0 | return false; |
1381 | 0 | |
1382 | 0 | if (window->width <= 0 || window->height <= 0) |
1383 | 0 | return false; |
1384 | 0 | |
1385 | | #if defined(XP_MACOSX) |
1386 | | // window is in "display pixels", but size needs to be in device pixels |
1387 | | // window must be in "display pixels" |
1388 | | double scaleFactor = 1.0; |
1389 | | if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) { |
1390 | | scaleFactor = 1.0; |
1391 | | } |
1392 | | |
1393 | | size_t intScaleFactor = ceil(scaleFactor); |
1394 | | #else |
1395 | 0 | size_t intScaleFactor = 1; |
1396 | 0 | #endif |
1397 | 0 |
|
1398 | 0 | aSize = IntSize(window->width * intScaleFactor, window->height * intScaleFactor); |
1399 | 0 |
|
1400 | 0 | nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame(); |
1401 | 0 | aRect = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel()); |
1402 | 0 | // to provide crisper and faster drawing. |
1403 | 0 | aRect.Round(); |
1404 | 0 |
|
1405 | 0 | return true; |
1406 | 0 | } |
1407 | | |
1408 | | bool |
1409 | | nsPluginFrame::CreateWebRenderCommands(nsDisplayItem* aItem, |
1410 | | mozilla::wr::DisplayListBuilder& aBuilder, |
1411 | | mozilla::wr::IpcResourceUpdateQueue& aResources, |
1412 | | const StackingContextHelper& aSc, |
1413 | | mozilla::layers::WebRenderLayerManager* aManager, |
1414 | | nsDisplayListBuilder* aDisplayListBuilder) |
1415 | 0 | { |
1416 | 0 | IntSize size; |
1417 | 0 | gfxRect r; |
1418 | 0 | if (!GetBounds(aItem, size, r)) { |
1419 | 0 | return true; |
1420 | 0 | } |
1421 | 0 | |
1422 | 0 | RefPtr<ImageContainer> container; |
1423 | 0 | // Image for Windowed plugins that support window capturing for scroll |
1424 | 0 | // operations or async windowless rendering. |
1425 | 0 | container = mInstanceOwner->GetImageContainer(); |
1426 | 0 | if (!container) { |
1427 | 0 | // This can occur if our instance is gone or if the current plugin |
1428 | 0 | // configuration does not require a backing image layer. |
1429 | 0 | return true; |
1430 | 0 | } |
1431 | 0 | |
1432 | | #ifdef XP_MACOSX |
1433 | | if (!mInstanceOwner->UseAsyncRendering()) { |
1434 | | mInstanceOwner->DoCocoaEventDrawRect(r, nullptr); |
1435 | | } |
1436 | | #endif |
1437 | | |
1438 | 0 | RefPtr<LayerManager> lm = aDisplayListBuilder->GetWidgetLayerManager(); |
1439 | 0 | if (!mDidCompositeObserver || !mDidCompositeObserver->IsValid(lm)) { |
1440 | 0 | mDidCompositeObserver = MakeUnique<PluginFrameDidCompositeObserver>(mInstanceOwner, lm); |
1441 | 0 | } |
1442 | 0 | lm->AddDidCompositeObserver(mDidCompositeObserver.get()); |
1443 | 0 |
|
1444 | 0 | // If the image container is empty, we don't want to fallback. Any other |
1445 | 0 | // failure will be due to resource constraints and fallback is unlikely to |
1446 | 0 | // help us. Hence we can ignore the return value from PushImage. |
1447 | 0 | LayoutDeviceRect dest(r.x, r.y, size.width, size.height); |
1448 | 0 | aManager->CommandBuilder().PushImage(aItem, container, aBuilder, aResources, aSc, dest); |
1449 | 0 | return true; |
1450 | 0 | } |
1451 | | |
1452 | | |
1453 | | already_AddRefed<Layer> |
1454 | | nsPluginFrame::BuildLayer(nsDisplayListBuilder* aBuilder, |
1455 | | LayerManager* aManager, |
1456 | | nsDisplayItem* aItem, |
1457 | | const ContainerLayerParameters& aContainerParameters) |
1458 | 0 | { |
1459 | 0 | IntSize size; |
1460 | 0 | gfxRect r; |
1461 | 0 | if (!GetBounds(aItem, size, r)) { |
1462 | 0 | return nullptr; |
1463 | 0 | } |
1464 | 0 | |
1465 | 0 | RefPtr<Layer> layer = |
1466 | 0 | (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); |
1467 | 0 |
|
1468 | 0 | if (aItem->GetType() == DisplayItemType::TYPE_PLUGIN) { |
1469 | 0 | RefPtr<ImageContainer> container; |
1470 | 0 | // Image for Windowed plugins that support window capturing for scroll |
1471 | 0 | // operations or async windowless rendering. |
1472 | 0 | container = mInstanceOwner->GetImageContainer(); |
1473 | 0 | if (!container) { |
1474 | 0 | // This can occur if our instance is gone or if the current plugin |
1475 | 0 | // configuration does not require a backing image layer. |
1476 | 0 | return nullptr; |
1477 | 0 | } |
1478 | 0 | |
1479 | 0 | if (!layer) { |
1480 | 0 | mInstanceOwner->NotifyPaintWaiter(aBuilder); |
1481 | 0 | // Initialize ImageLayer |
1482 | 0 | layer = aManager->CreateImageLayer(); |
1483 | 0 | if (!layer) |
1484 | 0 | return nullptr; |
1485 | 0 | } |
1486 | 0 | |
1487 | 0 | NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type"); |
1488 | 0 | ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get()); |
1489 | | #ifdef XP_MACOSX |
1490 | | if (!mInstanceOwner->UseAsyncRendering()) { |
1491 | | mInstanceOwner->DoCocoaEventDrawRect(r, nullptr); |
1492 | | } |
1493 | | #endif |
1494 | |
|
1495 | 0 | imglayer->SetScaleToSize(size, ScaleMode::STRETCH); |
1496 | 0 | imglayer->SetContainer(container); |
1497 | 0 | SamplingFilter samplingFilter = nsLayoutUtils::GetSamplingFilterForFrame(this); |
1498 | | #ifdef MOZ_GFX_OPTIMIZE_MOBILE |
1499 | | if (!aManager->IsCompositingCheap()) { |
1500 | | // Pixman just horrible with bilinear filter scaling |
1501 | | samplingFilter = SamplingFilter::POINT; |
1502 | | } |
1503 | | #endif |
1504 | | imglayer->SetSamplingFilter(samplingFilter); |
1505 | 0 |
|
1506 | 0 | layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0); |
1507 | 0 |
|
1508 | 0 | if (aBuilder->IsPaintingToWindow() && |
1509 | 0 | aBuilder->GetWidgetLayerManager() && |
1510 | 0 | (aBuilder->GetWidgetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT || |
1511 | 0 | aBuilder->GetWidgetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR) && |
1512 | 0 | mInstanceOwner->UseAsyncRendering()) |
1513 | 0 | { |
1514 | 0 | RefPtr<LayerManager> lm = aBuilder->GetWidgetLayerManager(); |
1515 | 0 | if (!mDidCompositeObserver || !mDidCompositeObserver->IsValid(lm)) { |
1516 | 0 | mDidCompositeObserver = MakeUnique<PluginFrameDidCompositeObserver>(mInstanceOwner, lm); |
1517 | 0 | } |
1518 | 0 | lm->AddDidCompositeObserver(mDidCompositeObserver.get()); |
1519 | 0 | } |
1520 | 0 | } else { |
1521 | 0 | NS_ASSERTION(aItem->GetType() == DisplayItemType::TYPE_PLUGIN_READBACK, |
1522 | 0 | "Unknown item type"); |
1523 | 0 | MOZ_ASSERT(!IsOpaque(), "Opaque plugins don't use backgrounds"); |
1524 | 0 |
|
1525 | 0 | if (!layer) { |
1526 | 0 | layer = aManager->CreateReadbackLayer(); |
1527 | 0 | if (!layer) |
1528 | 0 | return nullptr; |
1529 | 0 | } |
1530 | 0 | NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type"); |
1531 | 0 |
|
1532 | 0 | ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get()); |
1533 | 0 | if (readback->GetSize() != size) { |
1534 | 0 | // This will destroy any old background sink and notify us that the |
1535 | 0 | // background is now unknown |
1536 | 0 | readback->SetSink(nullptr); |
1537 | 0 | readback->SetSize(size); |
1538 | 0 |
|
1539 | 0 | if (mBackgroundSink) { |
1540 | 0 | // Maybe we still have a background sink associated with another |
1541 | 0 | // readback layer that wasn't recycled for some reason? Unhook it |
1542 | 0 | // now so that if this frame goes away, it doesn't have a dangling |
1543 | 0 | // reference to us. |
1544 | 0 | mBackgroundSink->Destroy(); |
1545 | 0 | } |
1546 | 0 | mBackgroundSink = |
1547 | 0 | new PluginBackgroundSink(this, |
1548 | 0 | readback->AllocateSequenceNumber()); |
1549 | 0 | readback->SetSink(mBackgroundSink); |
1550 | 0 | // The layer has taken ownership of our sink. When either the sink dies |
1551 | 0 | // or the frame dies, the connection from the surviving object is nulled out. |
1552 | 0 | } |
1553 | 0 | } |
1554 | 0 |
|
1555 | 0 | // Set a transform on the layer to draw the plugin in the right place |
1556 | 0 | gfxPoint p = r.TopLeft() + aContainerParameters.mOffset; |
1557 | 0 | Matrix transform = Matrix::Translation(p.x, p.y); |
1558 | 0 |
|
1559 | 0 | layer->SetBaseTransform(Matrix4x4::From2D(transform)); |
1560 | 0 | return layer.forget(); |
1561 | 0 | } |
1562 | | |
1563 | | void |
1564 | | nsPluginFrame::PaintPlugin(nsDisplayListBuilder* aBuilder, |
1565 | | gfxContext& aRenderingContext, |
1566 | | const nsRect& aDirtyRect, const nsRect& aPluginRect) |
1567 | 0 | { |
1568 | | #if defined(DEBUG) |
1569 | | // On Desktop, we should have built a layer as we no longer support in-process |
1570 | | // plugins or synchronous painting. We can only get here for windowed plugins |
1571 | | // (which draw themselves), or via some error/unload state. |
1572 | | if (mInstanceOwner) { |
1573 | | NPWindow *window = nullptr; |
1574 | | mInstanceOwner->GetWindow(window); |
1575 | | MOZ_ASSERT(!window || window->type == NPWindowTypeWindow); |
1576 | | } |
1577 | | #endif |
1578 | | } |
1579 | | |
1580 | | nsresult |
1581 | | nsPluginFrame::HandleEvent(nsPresContext* aPresContext, |
1582 | | WidgetGUIEvent* anEvent, |
1583 | | nsEventStatus* anEventStatus) |
1584 | 0 | { |
1585 | 0 | NS_ENSURE_ARG_POINTER(anEvent); |
1586 | 0 | NS_ENSURE_ARG_POINTER(anEventStatus); |
1587 | 0 | nsresult rv = NS_OK; |
1588 | 0 |
|
1589 | 0 | if (!mInstanceOwner) |
1590 | 0 | return NS_ERROR_NULL_POINTER; |
1591 | 0 | |
1592 | 0 | mInstanceOwner->ConsiderNewEventloopNestingLevel(); |
1593 | 0 |
|
1594 | 0 | if (anEvent->mMessage == ePluginActivate) { |
1595 | 0 | nsIFocusManager* fm = nsFocusManager::GetFocusManager(); |
1596 | 0 | if (fm) { |
1597 | 0 | RefPtr<Element> elem = GetContent()->AsElement(); |
1598 | 0 | return fm->SetFocus(elem, 0); |
1599 | 0 | } |
1600 | 0 | } |
1601 | 0 | else if (anEvent->mMessage == ePluginFocus) { |
1602 | 0 | nsIFocusManager* fm = nsFocusManager::GetFocusManager(); |
1603 | 0 | if (fm) { |
1604 | 0 | RefPtr<Element> elem = GetContent()->AsElement(); |
1605 | 0 | return fm->FocusPlugin(elem); |
1606 | 0 | } |
1607 | 0 | } |
1608 | 0 | |
1609 | 0 | if (mInstanceOwner->SendNativeEvents() && |
1610 | 0 | anEvent->IsNativeEventDelivererForPlugin()) { |
1611 | 0 | *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent); |
1612 | 0 | // Due to plugin code reentering Gecko, this frame may be dead at this |
1613 | 0 | // point. |
1614 | 0 | return rv; |
1615 | 0 | } |
1616 | 0 | |
1617 | | #ifdef XP_WIN |
1618 | | rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus); |
1619 | | return rv; |
1620 | | #endif |
1621 | | |
1622 | | #ifdef XP_MACOSX |
1623 | | // we want to process some native mouse events in the cocoa event model |
1624 | | if ((anEvent->mMessage == eMouseEnterIntoWidget || |
1625 | | anEvent->mMessage == eWheel) && |
1626 | | mInstanceOwner->GetEventModel() == NPEventModelCocoa) { |
1627 | | *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent); |
1628 | | // Due to plugin code reentering Gecko, this frame may be dead at this |
1629 | | // point. |
1630 | | return rv; |
1631 | | } |
1632 | | |
1633 | | // These two calls to nsIPresShell::SetCapturingContext() (on mouse-down |
1634 | | // and mouse-up) are needed to make the routing of mouse events while |
1635 | | // dragging conform to standard OS X practice, and to the Cocoa NPAPI spec. |
1636 | | // See bug 525078 and bug 909678. |
1637 | | if (anEvent->mMessage == eMouseDown) { |
1638 | | nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); |
1639 | | } |
1640 | | #endif |
1641 | | |
1642 | 0 | rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus); |
1643 | 0 |
|
1644 | 0 | // We need to be careful from this point because the call to |
1645 | 0 | // nsFrame::HandleEvent() might have killed us. |
1646 | 0 |
|
1647 | | #ifdef XP_MACOSX |
1648 | | if (anEvent->mMessage == eMouseUp) { |
1649 | | nsIPresShell::SetCapturingContent(nullptr, 0); |
1650 | | } |
1651 | | #endif |
1652 | |
|
1653 | 0 | return rv; |
1654 | 0 | } |
1655 | | |
1656 | | void |
1657 | | nsPluginFrame::HandleWheelEventAsDefaultAction(WidgetWheelEvent* aWheelEvent) |
1658 | 0 | { |
1659 | 0 | MOZ_ASSERT(WantsToHandleWheelEventAsDefaultAction()); |
1660 | 0 | MOZ_ASSERT(!aWheelEvent->DefaultPrevented()); |
1661 | 0 |
|
1662 | 0 | if (NS_WARN_IF(!mInstanceOwner) || |
1663 | 0 | NS_WARN_IF(aWheelEvent->mMessage != eWheel)) { |
1664 | 0 | return; |
1665 | 0 | } |
1666 | 0 | |
1667 | 0 | // If the wheel event has native message, it should may be handled by |
1668 | 0 | // HandleEvent() in the future. In such case, we should do nothing here. |
1669 | 0 | if (NS_WARN_IF(!!aWheelEvent->mPluginEvent)) { |
1670 | 0 | return; |
1671 | 0 | } |
1672 | 0 | |
1673 | 0 | mInstanceOwner->ProcessEvent(*aWheelEvent); |
1674 | 0 | // We need to assume that the event is always consumed/handled by the |
1675 | 0 | // plugin. There is no way to know if it's actually consumed/handled. |
1676 | 0 | aWheelEvent->mViewPortIsOverscrolled = false; |
1677 | 0 | aWheelEvent->mOverflowDeltaX = 0; |
1678 | 0 | aWheelEvent->mOverflowDeltaY = 0; |
1679 | 0 | // Consume the event explicitly. |
1680 | 0 | aWheelEvent->PreventDefault(); |
1681 | 0 | } |
1682 | | |
1683 | | bool |
1684 | | nsPluginFrame::WantsToHandleWheelEventAsDefaultAction() const |
1685 | 0 | { |
1686 | | #ifdef XP_WIN |
1687 | | if (!mInstanceOwner) { |
1688 | | return false; |
1689 | | } |
1690 | | NPWindow* window = nullptr; |
1691 | | mInstanceOwner->GetWindow(window); |
1692 | | // On Windows, only when the plugin is windowless, we need to send wheel |
1693 | | // events as default action. |
1694 | | return window->type == NPWindowTypeDrawable; |
1695 | | #else |
1696 | | return false; |
1697 | 0 | #endif |
1698 | 0 | } |
1699 | | |
1700 | | nsresult |
1701 | | nsPluginFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance) |
1702 | 0 | { |
1703 | 0 | *aPluginInstance = nullptr; |
1704 | 0 |
|
1705 | 0 | if (!mInstanceOwner) { |
1706 | 0 | return NS_OK; |
1707 | 0 | } |
1708 | 0 | |
1709 | 0 | return mInstanceOwner->GetInstance(aPluginInstance); |
1710 | 0 | } |
1711 | | |
1712 | | nsresult |
1713 | | nsPluginFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) |
1714 | 0 | { |
1715 | 0 | if (!mInstanceOwner) { |
1716 | 0 | return NS_ERROR_FAILURE; |
1717 | 0 | } |
1718 | 0 | |
1719 | 0 | RefPtr<nsNPAPIPluginInstance> inst; |
1720 | 0 | mInstanceOwner->GetInstance(getter_AddRefs(inst)); |
1721 | 0 | if (!inst) { |
1722 | 0 | return NS_ERROR_FAILURE; |
1723 | 0 | } |
1724 | 0 | |
1725 | 0 | bool useDOMCursor = static_cast<nsNPAPIPluginInstance*>(inst.get())->UsesDOMForCursor(); |
1726 | 0 | if (!useDOMCursor) { |
1727 | 0 | return NS_ERROR_FAILURE; |
1728 | 0 | } |
1729 | 0 | |
1730 | 0 | return nsFrame::GetCursor(aPoint, aCursor); |
1731 | 0 | } |
1732 | | |
1733 | | void |
1734 | | nsPluginFrame::SetIsDocumentActive(bool aIsActive) |
1735 | 0 | { |
1736 | 0 | if (mInstanceOwner) { |
1737 | 0 | mInstanceOwner->UpdateDocumentActiveState(aIsActive); |
1738 | 0 | } |
1739 | 0 | } |
1740 | | |
1741 | | // static |
1742 | | nsIObjectFrame * |
1743 | | nsPluginFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot) |
1744 | 0 | { |
1745 | 0 | for (nsIFrame* child : aRoot->PrincipalChildList()) { |
1746 | 0 | nsIObjectFrame* outFrame = do_QueryFrame(child); |
1747 | 0 | if (outFrame) { |
1748 | 0 | RefPtr<nsNPAPIPluginInstance> pi; |
1749 | 0 | outFrame->GetPluginInstance(getter_AddRefs(pi)); // make sure we have a REAL plugin |
1750 | 0 | if (pi) |
1751 | 0 | return outFrame; |
1752 | 0 | } |
1753 | 0 | |
1754 | 0 | outFrame = GetNextObjectFrame(aPresContext, child); |
1755 | 0 | if (outFrame) |
1756 | 0 | return outFrame; |
1757 | 0 | } |
1758 | 0 |
|
1759 | 0 | return nullptr; |
1760 | 0 | } |
1761 | | |
1762 | | /*static*/ void |
1763 | | nsPluginFrame::BeginSwapDocShells(nsISupports* aSupports, void*) |
1764 | 0 | { |
1765 | 0 | MOZ_ASSERT(aSupports, "null parameter"); |
1766 | 0 | nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports)); |
1767 | 0 | if (!content) { |
1768 | 0 | return; |
1769 | 0 | } |
1770 | 0 | |
1771 | 0 | // This function is called from a document content enumerator so we need |
1772 | 0 | // to filter out the nsPluginFrames and ignore the rest. |
1773 | 0 | nsIObjectFrame* obj = do_QueryFrame(content->GetPrimaryFrame()); |
1774 | 0 | if (!obj) |
1775 | 0 | return; |
1776 | 0 | |
1777 | 0 | nsPluginFrame* objectFrame = static_cast<nsPluginFrame*>(obj); |
1778 | 0 | NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(), |
1779 | 0 | "Plugin windows must not be toplevel"); |
1780 | 0 | objectFrame->UnregisterPluginForGeometryUpdates(); |
1781 | 0 | } |
1782 | | |
1783 | | /*static*/ void |
1784 | | nsPluginFrame::EndSwapDocShells(nsISupports* aSupports, void*) |
1785 | 0 | { |
1786 | 0 | MOZ_ASSERT(aSupports, "null parameter"); |
1787 | 0 | nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports)); |
1788 | 0 | if (!content) { |
1789 | 0 | return; |
1790 | 0 | } |
1791 | 0 | |
1792 | 0 | // This function is called from a document content enumerator so we need |
1793 | 0 | // to filter out the nsPluginFrames and ignore the rest. |
1794 | 0 | nsIObjectFrame* obj = do_QueryFrame(content->GetPrimaryFrame()); |
1795 | 0 | if (!obj) |
1796 | 0 | return; |
1797 | 0 | |
1798 | 0 | nsPluginFrame* objectFrame = static_cast<nsPluginFrame*>(obj); |
1799 | 0 | nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext(); |
1800 | 0 | NS_ASSERTION(rootPC, "unable to register the plugin frame"); |
1801 | 0 | nsIWidget* widget = objectFrame->mWidget; |
1802 | 0 | if (widget) { |
1803 | 0 | // Reparent the widget. |
1804 | 0 | nsIWidget* parent = |
1805 | 0 | rootPC->PresShell()->GetRootFrame()->GetNearestWidget(); |
1806 | 0 | widget->SetParent(parent); |
1807 | 0 | AutoWeakFrame weakFrame(objectFrame); |
1808 | 0 | objectFrame->CallSetWindow(); |
1809 | 0 | if (!weakFrame.IsAlive()) { |
1810 | 0 | return; |
1811 | 0 | } |
1812 | 0 | } |
1813 | 0 | |
1814 | 0 | if (objectFrame->mInstanceOwner) { |
1815 | 0 | objectFrame->RegisterPluginForGeometryUpdates(); |
1816 | 0 | } |
1817 | 0 | } |
1818 | | |
1819 | | nsIFrame* |
1820 | | NS_NewObjectFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle) |
1821 | 0 | { |
1822 | 0 | return new (aPresShell) nsPluginFrame(aStyle); |
1823 | 0 | } |
1824 | | |
1825 | | bool |
1826 | | nsPluginFrame::IsPaintedByGecko() const |
1827 | 0 | { |
1828 | | #ifdef XP_MACOSX |
1829 | | return true; |
1830 | | #else |
1831 | | return !mWidget; |
1832 | 0 | #endif |
1833 | 0 | } |
1834 | | |
1835 | | NS_IMPL_FRAMEARENA_HELPERS(nsPluginFrame) |