dom/ipc/TabChild.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:b01a6802c3c9
1 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
2 /* vim: set sw=2 sts=2 ts=8 et 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 #include "base/basictypes.h"
8
9 #include "TabChild.h"
10
11 #include "Layers.h"
12 #include "ContentChild.h"
13 #include "IndexedDBChild.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/ClearOnShutdown.h"
16 #include "mozilla/EventListenerManager.h"
17 #include "mozilla/IntentionalCrash.h"
18 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
19 #include "mozilla/ipc/DocumentRendererChild.h"
20 #include "mozilla/ipc/FileDescriptorUtils.h"
21 #include "mozilla/layers/ActiveElementManager.h"
22 #include "mozilla/layers/APZCCallbackHelper.h"
23 #include "mozilla/layers/AsyncPanZoomController.h"
24 #include "mozilla/layers/CompositorChild.h"
25 #include "mozilla/layers/ImageBridgeChild.h"
26 #include "mozilla/layers/ShadowLayers.h"
27 #include "mozilla/layout/RenderFrameChild.h"
28 #include "mozilla/MouseEvents.h"
29 #include "mozilla/Services.h"
30 #include "mozilla/StaticPtr.h"
31 #include "mozilla/TextEvents.h"
32 #include "mozilla/TouchEvents.h"
33 #include "mozilla/unused.h"
34 #include "mozIApplication.h"
35 #include "nsContentUtils.h"
36 #include "nsCxPusher.h"
37 #include "nsEmbedCID.h"
38 #include <algorithm>
39 #ifdef MOZ_CRASHREPORTER
40 #include "nsExceptionHandler.h"
41 #endif
42 #include "nsFilePickerProxy.h"
43 #include "mozilla/dom/Element.h"
44 #include "nsIBaseWindow.h"
45 #include "nsICachedFileDescriptorListener.h"
46 #include "nsIDocumentInlines.h"
47 #include "nsIDocShellTreeOwner.h"
48 #include "nsIDOMEvent.h"
49 #include "nsIDOMWindow.h"
50 #include "nsIDOMWindowUtils.h"
51 #include "nsIDocShell.h"
52 #include "nsIURI.h"
53 #include "nsIURIFixup.h"
54 #include "nsCDefaultURIFixup.h"
55 #include "nsIWebBrowser.h"
56 #include "nsIWebBrowserFocus.h"
57 #include "nsIWebBrowserSetup.h"
58 #include "nsIWebProgress.h"
59 #include "nsIXULRuntime.h"
60 #include "nsInterfaceHashtable.h"
61 #include "nsPIDOMWindow.h"
62 #include "nsPIWindowRoot.h"
63 #include "nsLayoutUtils.h"
64 #include "nsPrintfCString.h"
65 #include "nsThreadUtils.h"
66 #include "nsWeakReference.h"
67 #include "PermissionMessageUtils.h"
68 #include "PCOMContentPermissionRequestChild.h"
69 #include "PuppetWidget.h"
70 #include "StructuredCloneUtils.h"
71 #include "nsViewportInfo.h"
72 #include "JavaScriptChild.h"
73 #include "nsILoadContext.h"
74 #include "ipc/nsGUIEventIPC.h"
75 #include "mozilla/gfx/Matrix.h"
76 #include "UnitTransforms.h"
77 #include "ClientLayerManager.h"
78
79 #include "nsColorPickerProxy.h"
80
81 #ifdef DEBUG
82 #include "PCOMContentPermissionRequestChild.h"
83 #endif /* DEBUG */
84
85 #define BROWSER_ELEMENT_CHILD_SCRIPT \
86 NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
87
88 using namespace mozilla;
89 using namespace mozilla::dom;
90 using namespace mozilla::dom::ipc;
91 using namespace mozilla::ipc;
92 using namespace mozilla::layers;
93 using namespace mozilla::layout;
94 using namespace mozilla::docshell;
95 using namespace mozilla::dom::indexedDB;
96 using namespace mozilla::widget;
97 using namespace mozilla::jsipc;
98
99 NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener)
100
101 static const CSSSize kDefaultViewportSize(980, 480);
102
103 static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
104 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
105
106 static bool sCpowsEnabled = false;
107 static int32_t sActiveDurationMs = 10;
108 static bool sActiveDurationMsSet = false;
109
110 typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
111 static TabChildMap* sTabChildren;
112
113 TabChildBase::TabChildBase()
114 : mOldViewportWidth(0.0f)
115 , mContentDocumentIsDisplayed(false)
116 , mTabChildGlobal(nullptr)
117 , mInnerSize(0, 0)
118 {
119 }
120
121 NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase)
122 NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase)
123 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChildBase)
124 NS_INTERFACE_MAP_ENTRY(nsISupports)
125 NS_INTERFACE_MAP_END
126
127 NS_IMPL_CYCLE_COLLECTION(TabChildBase, mTabChildGlobal, mGlobal)
128
129 void
130 TabChildBase::InitializeRootMetrics()
131 {
132 // Calculate a really simple resolution that we probably won't
133 // be keeping, as well as putting the scroll offset back to
134 // the top-left of the page.
135 mLastRootMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
136 mLastRootMetrics.mCompositionBounds = ParentLayerIntRect(
137 ParentLayerIntPoint(),
138 ViewAs<ParentLayerPixel>(mInnerSize, PixelCastJustification::ScreenToParentLayerForRoot));
139 mLastRootMetrics.SetZoom(mLastRootMetrics.CalculateIntrinsicScale());
140 mLastRootMetrics.mDevPixelsPerCSSPixel = WebWidget()->GetDefaultScale();
141 // We use ScreenToLayerScale(1) below in order to turn the
142 // async zoom amount into the gecko zoom amount.
143 mLastRootMetrics.mCumulativeResolution =
144 mLastRootMetrics.GetZoom() / mLastRootMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
145 // This is the root layer, so the cumulative resolution is the same
146 // as the resolution.
147 mLastRootMetrics.mResolution = mLastRootMetrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
148 mLastRootMetrics.SetScrollOffset(CSSPoint(0, 0));
149 }
150
151 bool
152 TabChildBase::HasValidInnerSize()
153 {
154 return (mInnerSize.width != 0) && (mInnerSize.height != 0);
155 }
156
157 void
158 TabChildBase::SetCSSViewport(const CSSSize& aSize)
159 {
160 mOldViewportWidth = aSize.width;
161
162 if (mContentDocumentIsDisplayed) {
163 nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
164 utils->SetCSSViewport(aSize.width, aSize.height);
165 }
166 }
167
168 CSSSize
169 TabChildBase::GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport)
170 {
171 nsCOMPtr<Element> htmlDOMElement = aDocument->GetHtmlElement();
172 HTMLBodyElement* bodyDOMElement = aDocument->GetBodyElement();
173
174 if (!htmlDOMElement && !bodyDOMElement) {
175 // For non-HTML content (e.g. SVG), just assume page size == viewport size.
176 return aViewport;
177 }
178
179 int32_t htmlWidth = 0, htmlHeight = 0;
180 if (htmlDOMElement) {
181 htmlWidth = htmlDOMElement->ScrollWidth();
182 htmlHeight = htmlDOMElement->ScrollHeight();
183 }
184 int32_t bodyWidth = 0, bodyHeight = 0;
185 if (bodyDOMElement) {
186 bodyWidth = bodyDOMElement->ScrollWidth();
187 bodyHeight = bodyDOMElement->ScrollHeight();
188 }
189 return CSSSize(std::max(htmlWidth, bodyWidth),
190 std::max(htmlHeight, bodyHeight));
191 }
192
193 bool
194 TabChildBase::HandlePossibleViewportChange()
195 {
196 if (!IsAsyncPanZoomEnabled()) {
197 return false;
198 }
199
200 nsCOMPtr<nsIDocument> document(GetDocument());
201 nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
202
203 nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
204 uint32_t presShellId;
205 mozilla::layers::FrameMetrics::ViewID viewId;
206 bool scrollIdentifiersValid = APZCCallbackHelper::GetScrollIdentifiers(
207 document->GetDocumentElement(), &presShellId, &viewId);
208 if (scrollIdentifiersValid) {
209 ZoomConstraints constraints(
210 viewportInfo.IsZoomAllowed(),
211 viewportInfo.IsDoubleTapZoomAllowed(),
212 viewportInfo.GetMinZoom(),
213 viewportInfo.GetMaxZoom());
214 DoUpdateZoomConstraints(presShellId,
215 viewId,
216 /* isRoot = */ true,
217 constraints);
218 }
219
220 float screenW = mInnerSize.width;
221 float screenH = mInnerSize.height;
222 CSSSize viewport(viewportInfo.GetSize());
223
224 // We're not being displayed in any way; don't bother doing anything because
225 // that will just confuse future adjustments.
226 if (!screenW || !screenH) {
227 return false;
228 }
229
230 float oldBrowserWidth = mOldViewportWidth;
231 mLastRootMetrics.mViewport.SizeTo(viewport);
232 if (!oldBrowserWidth) {
233 oldBrowserWidth = kDefaultViewportSize.width;
234 }
235 SetCSSViewport(viewport);
236
237 // If this page has not been painted yet, then this must be getting run
238 // because a meta-viewport element was added (via the DOMMetaAdded handler).
239 // in this case, we should not do anything that forces a reflow (see bug
240 // 759678) such as requesting the page size or sending a viewport update. this
241 // code will get run again in the before-first-paint handler and that point we
242 // will run though all of it. the reason we even bother executing up to this
243 // point on the DOMMetaAdded handler is so that scripts that use
244 // window.innerWidth before they are painted have a correct value (bug
245 // 771575).
246 if (!mContentDocumentIsDisplayed) {
247 return false;
248 }
249
250 float oldScreenWidth = mLastRootMetrics.mCompositionBounds.width;
251 if (!oldScreenWidth) {
252 oldScreenWidth = mInnerSize.width;
253 }
254
255 FrameMetrics metrics(mLastRootMetrics);
256 metrics.mViewport = CSSRect(CSSPoint(), viewport);
257 metrics.mCompositionBounds = ParentLayerIntRect(
258 ParentLayerIntPoint(),
259 ViewAs<ParentLayerPixel>(mInnerSize, PixelCastJustification::ScreenToParentLayerForRoot));
260 metrics.SetRootCompositionSize(
261 ScreenSize(mInnerSize) * ScreenToLayoutDeviceScale(1.0f) / metrics.mDevPixelsPerCSSPixel);
262
263 // This change to the zoom accounts for all types of changes I can conceive:
264 // 1. screen size changes, CSS viewport does not (pages with no meta viewport
265 // or a fixed size viewport)
266 // 2. screen size changes, CSS viewport also does (pages with a device-width
267 // viewport)
268 // 3. screen size remains constant, but CSS viewport changes (meta viewport
269 // tag is added or removed)
270 // 4. neither screen size nor CSS viewport changes
271 //
272 // In all of these cases, we maintain how much actual content is visible
273 // within the screen width. Note that "actual content" may be different with
274 // respect to CSS pixels because of the CSS viewport size changing.
275 float oldIntrinsicScale = oldScreenWidth / oldBrowserWidth;
276 metrics.ZoomBy(metrics.CalculateIntrinsicScale().scale / oldIntrinsicScale);
277
278 // Changing the zoom when we're not doing a first paint will get ignored
279 // by AsyncPanZoomController and causes a blurry flash.
280 bool isFirstPaint;
281 nsresult rv = utils->GetIsFirstPaint(&isFirstPaint);
282 if (NS_FAILED(rv) || isFirstPaint) {
283 // FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
284 // 0.0 to mean "did not calculate a zoom". In that case, we default
285 // it to the intrinsic scale.
286 if (viewportInfo.GetDefaultZoom().scale < 0.01f) {
287 viewportInfo.SetDefaultZoom(metrics.CalculateIntrinsicScale());
288 }
289
290 CSSToScreenScale defaultZoom = viewportInfo.GetDefaultZoom();
291 MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom &&
292 defaultZoom <= viewportInfo.GetMaxZoom());
293 metrics.SetZoom(defaultZoom);
294
295 metrics.SetScrollId(viewId);
296 }
297
298 metrics.mCumulativeResolution = metrics.GetZoom() / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
299 // This is the root layer, so the cumulative resolution is the same
300 // as the resolution.
301 metrics.mResolution = metrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
302 utils->SetResolution(metrics.mResolution.scale, metrics.mResolution.scale);
303
304 CSSSize scrollPort = metrics.CalculateCompositedSizeInCssPixels();
305 utils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
306
307 // The call to GetPageSize forces a resize event to content, so we need to
308 // make sure that we have the right CSS viewport and
309 // scrollPositionClampingScrollPortSize set up before that happens.
310
311 CSSSize pageSize = GetPageSize(document, viewport);
312 if (!pageSize.width) {
313 // Return early rather than divide by 0.
314 return false;
315 }
316 metrics.mScrollableRect = CSSRect(CSSPoint(), pageSize);
317
318 // Calculate a display port _after_ having a scrollable rect because the
319 // display port is clamped to the scrollable rect.
320 metrics.SetDisplayPortMargins(AsyncPanZoomController::CalculatePendingDisplayPort(
321 // The page must have been refreshed in some way such as a new document or
322 // new CSS viewport, so we know that there's no velocity, acceleration, and
323 // we have no idea how long painting will take.
324 metrics, ScreenPoint(0.0f, 0.0f), 0.0));
325 metrics.SetUseDisplayPortMargins();
326
327 // Force a repaint with these metrics. This, among other things, sets the
328 // displayport, so we start with async painting.
329 mLastRootMetrics = ProcessUpdateFrame(metrics);
330
331 if (viewportInfo.IsZoomAllowed() && scrollIdentifiersValid) {
332 // If the CSS viewport is narrower than the screen (i.e. width <= device-width)
333 // then we disable double-tap-to-zoom behaviour.
334 bool allowDoubleTapZoom = (viewport.width > screenW / metrics.mDevPixelsPerCSSPixel.scale);
335 if (allowDoubleTapZoom != viewportInfo.IsDoubleTapZoomAllowed()) {
336 viewportInfo.SetAllowDoubleTapZoom(allowDoubleTapZoom);
337
338 ZoomConstraints constraints(
339 viewportInfo.IsZoomAllowed(),
340 viewportInfo.IsDoubleTapZoomAllowed(),
341 viewportInfo.GetMinZoom(),
342 viewportInfo.GetMaxZoom());
343 DoUpdateZoomConstraints(presShellId,
344 viewId,
345 /* isRoot = */ true,
346 constraints);
347 }
348 }
349
350 return true;
351 }
352
353 already_AddRefed<nsIDOMWindowUtils>
354 TabChildBase::GetDOMWindowUtils()
355 {
356 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
357 nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
358 return utils.forget();
359 }
360
361 already_AddRefed<nsIDocument>
362 TabChildBase::GetDocument()
363 {
364 nsCOMPtr<nsIDOMDocument> domDoc;
365 WebNavigation()->GetDocument(getter_AddRefs(domDoc));
366 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
367 return doc.forget();
368 }
369
370 void
371 TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName,
372 const nsAString& aJSONData)
373 {
374 AutoSafeJSContext cx;
375 JS::Rooted<JS::Value> json(cx, JSVAL_NULL);
376 StructuredCloneData cloneData;
377 JSAutoStructuredCloneBuffer buffer;
378 if (JS_ParseJSON(cx,
379 static_cast<const jschar*>(aJSONData.BeginReading()),
380 aJSONData.Length(),
381 &json)) {
382 WriteStructuredClone(cx, json, buffer, cloneData.mClosure);
383 cloneData.mData = buffer.data();
384 cloneData.mDataLength = buffer.nbytes();
385 }
386
387 nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
388 // Let the BrowserElementScrolling helper (if it exists) for this
389 // content manipulate the frame state.
390 nsRefPtr<nsFrameMessageManager> mm =
391 static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
392 mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
393 aMessageName, false, &cloneData, nullptr, nullptr, nullptr);
394 }
395
396 bool
397 TabChildBase::UpdateFrameHandler(const FrameMetrics& aFrameMetrics)
398 {
399 MOZ_ASSERT(aFrameMetrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID);
400
401 if (aFrameMetrics.mIsRoot) {
402 nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
403 if (APZCCallbackHelper::HasValidPresShellId(utils, aFrameMetrics)) {
404 mLastRootMetrics = ProcessUpdateFrame(aFrameMetrics);
405 APZCCallbackHelper::UpdateCallbackTransform(aFrameMetrics, mLastRootMetrics);
406 return true;
407 }
408 } else {
409 // aFrameMetrics.mIsRoot is false, so we are trying to update a subframe.
410 // This requires special handling.
411 nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(
412 aFrameMetrics.GetScrollId());
413 if (content) {
414 FrameMetrics newSubFrameMetrics(aFrameMetrics);
415 APZCCallbackHelper::UpdateSubFrame(content, newSubFrameMetrics);
416 APZCCallbackHelper::UpdateCallbackTransform(aFrameMetrics, newSubFrameMetrics);
417 return true;
418 }
419 }
420
421 // We've recieved a message that is out of date and we want to ignore.
422 // However we can't reply without painting so we reply by painting the
423 // exact same thing as we did before.
424 mLastRootMetrics = ProcessUpdateFrame(mLastRootMetrics);
425 return true;
426 }
427
428 FrameMetrics
429 TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
430 {
431 if (!mGlobal || !mTabChildGlobal) {
432 return aFrameMetrics;
433 }
434
435 nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
436
437 FrameMetrics newMetrics = aFrameMetrics;
438 APZCCallbackHelper::UpdateRootFrame(utils, newMetrics);
439
440 CSSSize cssCompositedSize = newMetrics.CalculateCompositedSizeInCssPixels();
441 // The BrowserElementScrolling helper must know about these updated metrics
442 // for other functions it performs, such as double tap handling.
443 // Note, %f must not be used because it is locale specific!
444 nsString data;
445 data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.GetScrollOffset().x));
446 data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.GetScrollOffset().y));
447 data.AppendLiteral(", \"viewport\" : ");
448 data.AppendLiteral("{ \"width\" : ");
449 data.AppendFloat(newMetrics.mViewport.width);
450 data.AppendLiteral(", \"height\" : ");
451 data.AppendFloat(newMetrics.mViewport.height);
452 data.AppendLiteral(" }");
453 data.AppendLiteral(", \"cssPageRect\" : ");
454 data.AppendLiteral("{ \"x\" : ");
455 data.AppendFloat(newMetrics.mScrollableRect.x);
456 data.AppendLiteral(", \"y\" : ");
457 data.AppendFloat(newMetrics.mScrollableRect.y);
458 data.AppendLiteral(", \"width\" : ");
459 data.AppendFloat(newMetrics.mScrollableRect.width);
460 data.AppendLiteral(", \"height\" : ");
461 data.AppendFloat(newMetrics.mScrollableRect.height);
462 data.AppendLiteral(" }");
463 data.AppendPrintf(", \"resolution\" : "); // TODO: check if it's actually used?
464 data.AppendPrintf("{ \"width\" : ");
465 data.AppendFloat(newMetrics.CalculateIntrinsicScale().scale);
466 data.AppendPrintf(" }");
467 data.AppendLiteral(", \"cssCompositedRect\" : ");
468 data.AppendLiteral("{ \"width\" : ");
469 data.AppendFloat(cssCompositedSize.width);
470 data.AppendLiteral(", \"height\" : ");
471 data.AppendFloat(cssCompositedSize.height);
472 data.AppendLiteral(" }");
473 data.AppendLiteral(" }");
474
475 DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
476 return newMetrics;
477 }
478
479 nsEventStatus
480 TabChildBase::DispatchSynthesizedMouseEvent(uint32_t aMsg, uint64_t aTime,
481 const LayoutDevicePoint& aRefPoint,
482 nsIWidget* aWidget)
483 {
484 MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
485 aMsg == NS_MOUSE_BUTTON_UP);
486
487 WidgetMouseEvent event(true, aMsg, nullptr,
488 WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
489 event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
490 event.time = aTime;
491 event.button = WidgetMouseEvent::eLeftButton;
492 event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
493 if (aMsg != NS_MOUSE_MOVE) {
494 event.clickCount = 1;
495 }
496 event.widget = aWidget;
497
498 return DispatchWidgetEvent(event);
499 }
500
501 nsEventStatus
502 TabChildBase::DispatchWidgetEvent(WidgetGUIEvent& event)
503 {
504 if (!event.widget)
505 return nsEventStatus_eConsumeNoDefault;
506
507 nsEventStatus status;
508 NS_ENSURE_SUCCESS(event.widget->DispatchEvent(&event, status),
509 nsEventStatus_eConsumeNoDefault);
510 return status;
511 }
512
513 bool
514 TabChildBase::IsAsyncPanZoomEnabled()
515 {
516 return mScrolling == ASYNC_PAN_ZOOM;
517 }
518
519 NS_IMETHODIMP
520 ContentListener::HandleEvent(nsIDOMEvent* aEvent)
521 {
522 RemoteDOMEvent remoteEvent;
523 remoteEvent.mEvent = do_QueryInterface(aEvent);
524 NS_ENSURE_STATE(remoteEvent.mEvent);
525 mTabChild->SendEvent(remoteEvent);
526 return NS_OK;
527 }
528
529 class TabChild::CachedFileDescriptorInfo
530 {
531 struct PathOnlyComparatorHelper
532 {
533 bool Equals(const nsAutoPtr<CachedFileDescriptorInfo>& a,
534 const CachedFileDescriptorInfo& b) const
535 {
536 return a->mPath == b.mPath;
537 }
538 };
539
540 struct PathAndCallbackComparatorHelper
541 {
542 bool Equals(const nsAutoPtr<CachedFileDescriptorInfo>& a,
543 const CachedFileDescriptorInfo& b) const
544 {
545 return a->mPath == b.mPath &&
546 a->mCallback == b.mCallback;
547 }
548 };
549
550 public:
551 nsString mPath;
552 FileDescriptor mFileDescriptor;
553 nsCOMPtr<nsICachedFileDescriptorListener> mCallback;
554 bool mCanceled;
555
556 CachedFileDescriptorInfo(const nsAString& aPath)
557 : mPath(aPath), mCanceled(false)
558 { }
559
560 CachedFileDescriptorInfo(const nsAString& aPath,
561 const FileDescriptor& aFileDescriptor)
562 : mPath(aPath), mFileDescriptor(aFileDescriptor), mCanceled(false)
563 { }
564
565 CachedFileDescriptorInfo(const nsAString& aPath,
566 nsICachedFileDescriptorListener* aCallback)
567 : mPath(aPath), mCallback(aCallback), mCanceled(false)
568 { }
569
570 PathOnlyComparatorHelper PathOnlyComparator() const
571 {
572 return PathOnlyComparatorHelper();
573 }
574
575 PathAndCallbackComparatorHelper PathAndCallbackComparator() const
576 {
577 return PathAndCallbackComparatorHelper();
578 }
579
580 void FireCallback() const
581 {
582 mCallback->OnCachedFileDescriptor(mPath, mFileDescriptor);
583 }
584 };
585
586 class TabChild::CachedFileDescriptorCallbackRunnable : public nsRunnable
587 {
588 typedef TabChild::CachedFileDescriptorInfo CachedFileDescriptorInfo;
589
590 nsAutoPtr<CachedFileDescriptorInfo> mInfo;
591
592 public:
593 CachedFileDescriptorCallbackRunnable(CachedFileDescriptorInfo* aInfo)
594 : mInfo(aInfo)
595 {
596 MOZ_ASSERT(NS_IsMainThread());
597 MOZ_ASSERT(aInfo);
598 MOZ_ASSERT(!aInfo->mPath.IsEmpty());
599 MOZ_ASSERT(aInfo->mCallback);
600 }
601
602 void Dispatch()
603 {
604 MOZ_ASSERT(NS_IsMainThread());
605
606 nsresult rv = NS_DispatchToCurrentThread(this);
607 NS_ENSURE_SUCCESS_VOID(rv);
608 }
609
610 private:
611 NS_IMETHOD Run()
612 {
613 MOZ_ASSERT(NS_IsMainThread());
614 MOZ_ASSERT(mInfo);
615
616 mInfo->FireCallback();
617 return NS_OK;
618 }
619 };
620
621 StaticRefPtr<TabChild> sPreallocatedTab;
622
623 /*static*/ void
624 TabChild::PreloadSlowThings()
625 {
626 MOZ_ASSERT(!sPreallocatedTab);
627
628 nsRefPtr<TabChild> tab(new TabChild(ContentChild::GetSingleton(),
629 TabContext(), /* chromeFlags */ 0));
630 if (!NS_SUCCEEDED(tab->Init()) ||
631 !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
632 return;
633 }
634 // Just load and compile these scripts, but don't run them.
635 tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
636 // Load, compile, and run these scripts.
637 tab->RecvLoadRemoteScript(
638 NS_LITERAL_STRING("chrome://global/content/preload.js"),
639 true);
640
641 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(tab->WebNavigation());
642 if (nsIPresShell* presShell = docShell->GetPresShell()) {
643 // Initialize and do an initial reflow of the about:blank
644 // PresShell to let it preload some things for us.
645 presShell->Initialize(0, 0);
646 nsIDocument* doc = presShell->GetDocument();
647 doc->FlushPendingNotifications(Flush_Layout);
648 // ... but after it's done, make sure it doesn't do any more
649 // work.
650 presShell->MakeZombie();
651 }
652
653 sPreallocatedTab = tab;
654 ClearOnShutdown(&sPreallocatedTab);
655 }
656
657 /*static*/ already_AddRefed<TabChild>
658 TabChild::Create(ContentChild* aManager, const TabContext &aContext, uint32_t aChromeFlags)
659 {
660 if (sPreallocatedTab &&
661 sPreallocatedTab->mChromeFlags == aChromeFlags &&
662 aContext.IsBrowserOrApp()) {
663
664 nsRefPtr<TabChild> child = sPreallocatedTab.get();
665 sPreallocatedTab = nullptr;
666
667 MOZ_ASSERT(!child->mTriedBrowserInit);
668
669 child->SetTabContext(aContext);
670 child->NotifyTabContextUpdated();
671 return child.forget();
672 }
673
674 nsRefPtr<TabChild> iframe = new TabChild(aManager,
675 aContext, aChromeFlags);
676 return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
677 }
678
679
680 TabChild::TabChild(ContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags)
681 : TabContext(aContext)
682 , mRemoteFrame(nullptr)
683 , mManager(aManager)
684 , mChromeFlags(aChromeFlags)
685 , mLayersId(0)
686 , mOuterRect(0, 0, 0, 0)
687 , mActivePointerId(-1)
688 , mTapHoldTimer(nullptr)
689 , mAppPackageFileDescriptorRecved(false)
690 , mLastBackgroundColor(NS_RGB(255, 255, 255))
691 , mDidFakeShow(false)
692 , mNotified(false)
693 , mTriedBrowserInit(false)
694 , mOrientation(eScreenOrientation_PortraitPrimary)
695 , mUpdateHitRegion(false)
696 , mContextMenuHandled(false)
697 , mWaitingTouchListeners(false)
698 , mIgnoreKeyPressEvent(false)
699 , mActiveElementManager(new ActiveElementManager())
700 {
701 if (!sActiveDurationMsSet) {
702 Preferences::AddIntVarCache(&sActiveDurationMs,
703 "ui.touch_activation.duration_ms",
704 sActiveDurationMs);
705 sActiveDurationMsSet = true;
706 }
707 }
708
709 NS_IMETHODIMP
710 TabChild::HandleEvent(nsIDOMEvent* aEvent)
711 {
712 nsAutoString eventType;
713 aEvent->GetType(eventType);
714 if (eventType.EqualsLiteral("DOMMetaAdded")) {
715 // This meta data may or may not have been a meta viewport tag. If it was,
716 // we should handle it immediately.
717 HandlePossibleViewportChange();
718 }
719
720 return NS_OK;
721 }
722
723 NS_IMETHODIMP
724 TabChild::Observe(nsISupports *aSubject,
725 const char *aTopic,
726 const char16_t *aData)
727 {
728 if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
729 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
730 nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
731 if (tabChild == this) {
732 nsCOMPtr<nsIDocument> doc(GetDocument());
733 uint32_t presShellId;
734 ViewID viewId;
735 if (APZCCallbackHelper::GetScrollIdentifiers(doc->GetDocumentElement(),
736 &presShellId, &viewId)) {
737 CSSRect rect;
738 sscanf(NS_ConvertUTF16toUTF8(aData).get(),
739 "{\"x\":%f,\"y\":%f,\"w\":%f,\"h\":%f}",
740 &rect.x, &rect.y, &rect.width, &rect.height);
741 SendZoomToRect(presShellId, viewId, rect);
742 }
743 }
744 } else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
745 if (IsAsyncPanZoomEnabled()) {
746 nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
747 nsCOMPtr<nsIDocument> doc(GetDocument());
748
749 if (SameCOMIdentity(subject, doc)) {
750 nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
751 utils->SetIsFirstPaint(true);
752
753 mContentDocumentIsDisplayed = true;
754
755 // Reset CSS viewport and zoom to default on new page, then
756 // calculate them properly using the actual metadata from the
757 // page.
758 SetCSSViewport(kDefaultViewportSize);
759
760 // In some cases before-first-paint gets called before
761 // RecvUpdateDimensions is called and therefore before we have an
762 // mInnerSize value set. In such cases defer initializing the viewport
763 // until we we get an inner size.
764 if (HasValidInnerSize()) {
765 InitializeRootMetrics();
766 utils->SetResolution(mLastRootMetrics.mResolution.scale,
767 mLastRootMetrics.mResolution.scale);
768 HandlePossibleViewportChange();
769 }
770 }
771 }
772 }
773
774 return NS_OK;
775 }
776
777 NS_IMETHODIMP
778 TabChild::OnStateChange(nsIWebProgress* aWebProgress,
779 nsIRequest* aRequest,
780 uint32_t aStateFlags,
781 nsresult aStatus)
782 {
783 NS_NOTREACHED("not implemented in TabChild");
784 return NS_OK;
785 }
786
787 NS_IMETHODIMP
788 TabChild::OnProgressChange(nsIWebProgress* aWebProgress,
789 nsIRequest* aRequest,
790 int32_t aCurSelfProgress,
791 int32_t aMaxSelfProgress,
792 int32_t aCurTotalProgress,
793 int32_t aMaxTotalProgress)
794 {
795 NS_NOTREACHED("not implemented in TabChild");
796 return NS_OK;
797 }
798
799 NS_IMETHODIMP
800 TabChild::OnLocationChange(nsIWebProgress* aWebProgress,
801 nsIRequest* aRequest,
802 nsIURI *aLocation,
803 uint32_t aFlags)
804 {
805 if (!IsAsyncPanZoomEnabled()) {
806 return NS_OK;
807 }
808
809 nsCOMPtr<nsIDOMWindow> window;
810 aWebProgress->GetDOMWindow(getter_AddRefs(window));
811 if (!window) {
812 return NS_OK;
813 }
814
815 nsCOMPtr<nsIDOMDocument> progressDoc;
816 window->GetDocument(getter_AddRefs(progressDoc));
817 if (!progressDoc) {
818 return NS_OK;
819 }
820
821 nsCOMPtr<nsIDOMDocument> domDoc;
822 WebNavigation()->GetDocument(getter_AddRefs(domDoc));
823 if (!domDoc || !SameCOMIdentity(domDoc, progressDoc)) {
824 return NS_OK;
825 }
826
827 nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
828 if (!urifixup) {
829 return NS_OK;
830 }
831
832 nsCOMPtr<nsIURI> exposableURI;
833 urifixup->CreateExposableURI(aLocation, getter_AddRefs(exposableURI));
834 if (!exposableURI) {
835 return NS_OK;
836 }
837
838 if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
839 mContentDocumentIsDisplayed = false;
840 } else if (mLastURI != nullptr) {
841 bool exposableEqualsLast, exposableEqualsNew;
842 exposableURI->Equals(mLastURI.get(), &exposableEqualsLast);
843 exposableURI->Equals(aLocation, &exposableEqualsNew);
844 if (exposableEqualsLast && !exposableEqualsNew) {
845 mContentDocumentIsDisplayed = false;
846 }
847 }
848
849 return NS_OK;
850 }
851
852 NS_IMETHODIMP
853 TabChild::OnStatusChange(nsIWebProgress* aWebProgress,
854 nsIRequest* aRequest,
855 nsresult aStatus,
856 const char16_t* aMessage)
857 {
858 NS_NOTREACHED("not implemented in TabChild");
859 return NS_OK;
860 }
861
862 NS_IMETHODIMP
863 TabChild::OnSecurityChange(nsIWebProgress* aWebProgress,
864 nsIRequest* aRequest,
865 uint32_t aState)
866 {
867 NS_NOTREACHED("not implemented in TabChild");
868 return NS_OK;
869 }
870
871 bool
872 TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId,
873 const ViewID& aViewId,
874 const bool& aIsRoot,
875 const ZoomConstraints& aConstraints)
876 {
877 return SendUpdateZoomConstraints(aPresShellId,
878 aViewId,
879 aIsRoot,
880 aConstraints);
881 }
882
883 nsresult
884 TabChild::Init()
885 {
886 nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
887 if (!webBrowser) {
888 NS_ERROR("Couldn't create a nsWebBrowser?");
889 return NS_ERROR_FAILURE;
890 }
891
892 webBrowser->SetContainerWindow(this);
893 mWebNav = do_QueryInterface(webBrowser);
894 NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
895
896 nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(WebNavigation()));
897 docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
898
899 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
900 if (!baseWindow) {
901 NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
902 return NS_ERROR_FAILURE;
903 }
904
905 mWidget = nsIWidget::CreatePuppetWidget(this);
906 if (!mWidget) {
907 NS_ERROR("couldn't create fake widget");
908 return NS_ERROR_FAILURE;
909 }
910 mWidget->Create(
911 nullptr, 0, // no parents
912 nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)),
913 nullptr, // HandleWidgetEvent
914 nullptr // nsDeviceContext
915 );
916
917 baseWindow->InitWindow(0, mWidget, 0, 0, 0, 0);
918 baseWindow->Create();
919
920 NotifyTabContextUpdated();
921
922 // IPC uses a WebBrowser object for which DNS prefetching is turned off
923 // by default. But here we really want it, so enable it explicitly
924 nsCOMPtr<nsIWebBrowserSetup> webBrowserSetup =
925 do_QueryInterface(baseWindow);
926 if (webBrowserSetup) {
927 webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH,
928 true);
929 } else {
930 NS_WARNING("baseWindow doesn't QI to nsIWebBrowserSetup, skipping "
931 "DNS prefetching enable step.");
932 }
933
934 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
935 MOZ_ASSERT(docShell);
936
937 docShell->SetAffectPrivateSessionLifetime(
938 mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
939 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
940 MOZ_ASSERT(loadContext);
941 loadContext->SetPrivateBrowsing(
942 mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW);
943 loadContext->SetRemoteTabs(
944 mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
945
946 nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
947 NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
948 webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION);
949
950 // Few lines before, baseWindow->Create() will end up creating a new
951 // window root in nsGlobalWindow::SetDocShell.
952 // Then this chrome event handler, will be inherited to inner windows.
953 // We want to also set it to the docshell so that inner windows
954 // and any code that has access to the docshell
955 // can all listen to the same chrome event handler.
956 // XXX: ideally, we would set a chrome event handler earlier,
957 // and all windows, even the root one, will use the docshell one.
958 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
959 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
960 nsCOMPtr<EventTarget> chromeHandler =
961 do_QueryInterface(window->GetChromeEventHandler());
962 docShell->SetChromeEventHandler(chromeHandler);
963
964 return NS_OK;
965 }
966
967 void
968 TabChild::NotifyTabContextUpdated()
969 {
970 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
971 MOZ_ASSERT(docShell);
972
973 if (docShell) {
974 // nsDocShell will do the right thing if we pass NO_APP_ID or
975 // UNKNOWN_APP_ID for aOwnOrContainingAppId.
976 if (IsBrowserElement()) {
977 docShell->SetIsBrowserInsideApp(BrowserOwnerAppId());
978 } else {
979 docShell->SetIsApp(OwnAppId());
980 }
981 }
982 }
983
984 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChild)
985 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
986 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
987 NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
988 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
989 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
990 NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
991 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
992 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
993 NS_INTERFACE_MAP_ENTRY(nsITabChild)
994 NS_INTERFACE_MAP_ENTRY(nsIObserver)
995 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
996 NS_INTERFACE_MAP_ENTRY(nsITooltipListener)
997 NS_INTERFACE_MAP_END_INHERITING(TabChildBase)
998
999 NS_IMPL_ADDREF_INHERITED(TabChild, TabChildBase);
1000 NS_IMPL_RELEASE_INHERITED(TabChild, TabChildBase);
1001
1002 NS_IMETHODIMP
1003 TabChild::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
1004 {
1005 return SetStatusWithContext(aStatusType,
1006 aStatus ? static_cast<const nsString &>(nsDependentString(aStatus))
1007 : EmptyString(),
1008 nullptr);
1009 }
1010
1011 NS_IMETHODIMP
1012 TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser)
1013 {
1014 NS_NOTREACHED("TabChild::GetWebBrowser not supported in TabChild");
1015
1016 return NS_ERROR_NOT_IMPLEMENTED;
1017 }
1018
1019 NS_IMETHODIMP
1020 TabChild::SetWebBrowser(nsIWebBrowser* aWebBrowser)
1021 {
1022 NS_NOTREACHED("TabChild::SetWebBrowser not supported in TabChild");
1023
1024 return NS_ERROR_NOT_IMPLEMENTED;
1025 }
1026
1027 NS_IMETHODIMP
1028 TabChild::GetChromeFlags(uint32_t* aChromeFlags)
1029 {
1030 *aChromeFlags = mChromeFlags;
1031 return NS_OK;
1032 }
1033
1034 NS_IMETHODIMP
1035 TabChild::SetChromeFlags(uint32_t aChromeFlags)
1036 {
1037 NS_NOTREACHED("trying to SetChromeFlags from content process?");
1038
1039 return NS_ERROR_NOT_IMPLEMENTED;
1040 }
1041
1042 NS_IMETHODIMP
1043 TabChild::DestroyBrowserWindow()
1044 {
1045 NS_NOTREACHED("TabChild::DestroyBrowserWindow not supported in TabChild");
1046
1047 return NS_ERROR_NOT_IMPLEMENTED;
1048 }
1049
1050 NS_IMETHODIMP
1051 TabChild::SizeBrowserTo(int32_t aCX, int32_t aCY)
1052 {
1053 NS_NOTREACHED("TabChild::SizeBrowserTo not supported in TabChild");
1054
1055 return NS_ERROR_NOT_IMPLEMENTED;
1056 }
1057
1058 NS_IMETHODIMP
1059 TabChild::ShowAsModal()
1060 {
1061 NS_NOTREACHED("TabChild::ShowAsModal not supported in TabChild");
1062
1063 return NS_ERROR_NOT_IMPLEMENTED;
1064 }
1065
1066 NS_IMETHODIMP
1067 TabChild::IsWindowModal(bool* aRetVal)
1068 {
1069 *aRetVal = false;
1070 return NS_OK;
1071 }
1072
1073 NS_IMETHODIMP
1074 TabChild::ExitModalEventLoop(nsresult aStatus)
1075 {
1076 NS_NOTREACHED("TabChild::ExitModalEventLoop not supported in TabChild");
1077
1078 return NS_ERROR_NOT_IMPLEMENTED;
1079 }
1080
1081 NS_IMETHODIMP
1082 TabChild::SetStatusWithContext(uint32_t aStatusType,
1083 const nsAString& aStatusText,
1084 nsISupports* aStatusContext)
1085 {
1086 // We can only send the status after the ipc machinery is set up,
1087 // mRemoteFrame is a good indicator.
1088 if (mRemoteFrame)
1089 SendSetStatus(aStatusType, nsString(aStatusText));
1090 return NS_OK;
1091 }
1092
1093 NS_IMETHODIMP
1094 TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
1095 int32_t aCx, int32_t aCy)
1096 {
1097 NS_NOTREACHED("TabChild::SetDimensions not supported in TabChild");
1098
1099 return NS_ERROR_NOT_IMPLEMENTED;
1100 }
1101
1102 NS_IMETHODIMP
1103 TabChild::GetDimensions(uint32_t aFlags, int32_t* aX,
1104 int32_t* aY, int32_t* aCx, int32_t* aCy)
1105 {
1106 if (aX) {
1107 *aX = mOuterRect.x;
1108 }
1109 if (aY) {
1110 *aY = mOuterRect.y;
1111 }
1112 if (aCx) {
1113 *aCx = mOuterRect.width;
1114 }
1115 if (aCy) {
1116 *aCy = mOuterRect.height;
1117 }
1118
1119 return NS_OK;
1120 }
1121
1122 NS_IMETHODIMP
1123 TabChild::SetFocus()
1124 {
1125 NS_WARNING("TabChild::SetFocus not supported in TabChild");
1126
1127 return NS_ERROR_NOT_IMPLEMENTED;
1128 }
1129
1130 NS_IMETHODIMP
1131 TabChild::GetVisibility(bool* aVisibility)
1132 {
1133 *aVisibility = true;
1134 return NS_OK;
1135 }
1136
1137 NS_IMETHODIMP
1138 TabChild::SetVisibility(bool aVisibility)
1139 {
1140 // should the platform support this? Bug 666365
1141 return NS_OK;
1142 }
1143
1144 NS_IMETHODIMP
1145 TabChild::GetTitle(char16_t** aTitle)
1146 {
1147 NS_NOTREACHED("TabChild::GetTitle not supported in TabChild");
1148
1149 return NS_ERROR_NOT_IMPLEMENTED;
1150 }
1151
1152 NS_IMETHODIMP
1153 TabChild::SetTitle(const char16_t* aTitle)
1154 {
1155 // JavaScript sends the "DOMTitleChanged" event to the parent
1156 // via the message manager.
1157 return NS_OK;
1158 }
1159
1160 NS_IMETHODIMP
1161 TabChild::GetSiteWindow(void** aSiteWindow)
1162 {
1163 NS_NOTREACHED("TabChild::GetSiteWindow not supported in TabChild");
1164
1165 return NS_ERROR_NOT_IMPLEMENTED;
1166 }
1167
1168 NS_IMETHODIMP
1169 TabChild::Blur()
1170 {
1171 NS_WARNING("TabChild::Blur not supported in TabChild");
1172
1173 return NS_ERROR_NOT_IMPLEMENTED;
1174 }
1175
1176 NS_IMETHODIMP
1177 TabChild::FocusNextElement()
1178 {
1179 SendMoveFocus(true);
1180 return NS_OK;
1181 }
1182
1183 NS_IMETHODIMP
1184 TabChild::FocusPrevElement()
1185 {
1186 SendMoveFocus(false);
1187 return NS_OK;
1188 }
1189
1190 NS_IMETHODIMP
1191 TabChild::GetInterface(const nsIID & aIID, void **aSink)
1192 {
1193 // XXXbz should we restrict the set of interfaces we hand out here?
1194 // See bug 537429
1195 return QueryInterface(aIID, aSink);
1196 }
1197
1198 NS_IMETHODIMP
1199 TabChild::ProvideWindow(nsIDOMWindow* aParent, uint32_t aChromeFlags,
1200 bool aCalledFromJS,
1201 bool aPositionSpecified, bool aSizeSpecified,
1202 nsIURI* aURI, const nsAString& aName,
1203 const nsACString& aFeatures, bool* aWindowIsNew,
1204 nsIDOMWindow** aReturn)
1205 {
1206 *aReturn = nullptr;
1207
1208 // If aParent is inside an <iframe mozbrowser> or <iframe mozapp> and this
1209 // isn't a request to open a modal-type window, we're going to create a new
1210 // <iframe mozbrowser/mozapp> and return its window here.
1211 nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
1212 if (docshell && docshell->GetIsInBrowserOrApp() &&
1213 !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
1214 nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
1215 nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
1216
1217 // Note that BrowserFrameProvideWindow may return NS_ERROR_ABORT if the
1218 // open window call was canceled. It's important that we pass this error
1219 // code back to our caller.
1220 return BrowserFrameProvideWindow(aParent, aURI, aName, aFeatures,
1221 aWindowIsNew, aReturn);
1222 }
1223
1224 // Otherwise, create a new top-level window.
1225 PBrowserChild* newChild;
1226 if (!CallCreateWindow(&newChild)) {
1227 return NS_ERROR_NOT_AVAILABLE;
1228 }
1229
1230 *aWindowIsNew = true;
1231 nsCOMPtr<nsIDOMWindow> win =
1232 do_GetInterface(static_cast<TabChild*>(newChild)->WebNavigation());
1233 win.forget(aReturn);
1234 return NS_OK;
1235 }
1236
1237 nsresult
1238 TabChild::BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
1239 nsIURI* aURI,
1240 const nsAString& aName,
1241 const nsACString& aFeatures,
1242 bool* aWindowIsNew,
1243 nsIDOMWindow** aReturn)
1244 {
1245 *aReturn = nullptr;
1246
1247 nsRefPtr<TabChild> newChild =
1248 new TabChild(ContentChild::GetSingleton(),
1249 /* TabContext */ *this, /* chromeFlags */ 0);
1250 if (!NS_SUCCEEDED(newChild->Init())) {
1251 return NS_ERROR_ABORT;
1252 }
1253
1254 // We must use PopupIPCTabContext here; ContentParent will not accept the
1255 // result of this->AsIPCTabContext() (which will be a
1256 // BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
1257 // reasons.
1258 PopupIPCTabContext context;
1259 context.openerChild() = this;
1260 context.isBrowserElement() = IsBrowserElement();
1261
1262 unused << Manager()->SendPBrowserConstructor(
1263 // We release this ref in DeallocPBrowserChild
1264 nsRefPtr<TabChild>(newChild).forget().take(),
1265 IPCTabContext(context, mScrolling), /* chromeFlags */ 0);
1266
1267 nsAutoCString spec;
1268 if (aURI) {
1269 aURI->GetSpec(spec);
1270 }
1271
1272 NS_ConvertUTF8toUTF16 url(spec);
1273 nsString name(aName);
1274 NS_ConvertUTF8toUTF16 features(aFeatures);
1275 newChild->SendBrowserFrameOpenWindow(this, url, name,
1276 features, aWindowIsNew);
1277 if (!*aWindowIsNew) {
1278 PBrowserChild::Send__delete__(newChild);
1279 return NS_ERROR_ABORT;
1280 }
1281
1282 // Unfortunately we don't get a window unless we've shown the frame. That's
1283 // pretty bogus; see bug 763602.
1284 newChild->DoFakeShow();
1285
1286 nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
1287 win.forget(aReturn);
1288 return NS_OK;
1289 }
1290
1291 #ifdef DEBUG
1292 PContentPermissionRequestChild*
1293 TabChild:: SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
1294 const InfallibleTArray<PermissionRequest>& aRequests,
1295 const IPC::Principal& aPrincipal)
1296 {
1297 PCOMContentPermissionRequestChild* child = static_cast<PCOMContentPermissionRequestChild*>(aActor);
1298 PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aRequests, aPrincipal);
1299 child->mIPCOpen = true;
1300 return request;
1301 }
1302 #endif /* DEBUG */
1303
1304 void
1305 TabChild::DestroyWindow()
1306 {
1307 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
1308 if (baseWindow)
1309 baseWindow->Destroy();
1310
1311 // NB: the order of mWidget->Destroy() and mRemoteFrame->Destroy()
1312 // is important: we want to kill off remote layers before their
1313 // frames
1314 if (mWidget) {
1315 mWidget->Destroy();
1316 }
1317
1318 if (mRemoteFrame) {
1319 mRemoteFrame->Destroy();
1320 mRemoteFrame = nullptr;
1321 }
1322
1323
1324 if (mLayersId != 0) {
1325 MOZ_ASSERT(sTabChildren);
1326 sTabChildren->Remove(mLayersId);
1327 if (!sTabChildren->Count()) {
1328 delete sTabChildren;
1329 sTabChildren = nullptr;
1330 }
1331 mLayersId = 0;
1332 }
1333 }
1334
1335 bool
1336 TabChild::UseDirectCompositor()
1337 {
1338 return !!CompositorChild::Get();
1339 }
1340
1341 void
1342 TabChild::ActorDestroy(ActorDestroyReason why)
1343 {
1344 if (mTabChildGlobal) {
1345 // The messageManager relays messages via the TabChild which
1346 // no longer exists.
1347 static_cast<nsFrameMessageManager*>
1348 (mTabChildGlobal->mMessageManager.get())->Disconnect();
1349 mTabChildGlobal->mMessageManager = nullptr;
1350 }
1351 }
1352
1353 TabChild::~TabChild()
1354 {
1355 DestroyWindow();
1356
1357 nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
1358 if (webBrowser) {
1359 webBrowser->SetContainerWindow(nullptr);
1360 }
1361 }
1362
1363 void
1364 TabChild::SetProcessNameToAppName()
1365 {
1366 nsCOMPtr<mozIApplication> app = GetOwnApp();
1367 if (!app) {
1368 return;
1369 }
1370
1371 nsAutoString appName;
1372 nsresult rv = app->GetName(appName);
1373 if (NS_FAILED(rv)) {
1374 NS_WARNING("Failed to retrieve app name");
1375 return;
1376 }
1377
1378 ContentChild::GetSingleton()->SetProcessName(appName, true);
1379 }
1380
1381 bool
1382 TabChild::IsRootContentDocument()
1383 {
1384 // A TabChild is a "root content document" if it's
1385 //
1386 // - <iframe mozapp> not inside another <iframe mozapp>,
1387 // - <iframe mozbrowser> (not mozapp), or
1388 // - a vanilla remote frame (<html:iframe remote=true> or <xul:browser
1389 // remote=true>).
1390 //
1391 // Put another way, an iframe is /not/ a "root content document" iff it's a
1392 // mozapp inside a mozapp. (This corresponds exactly to !HasAppOwnerApp.)
1393 //
1394 // Note that we're lying through our teeth here (thus the scare quotes).
1395 // <html:iframe remote=true> or <xul:browser remote=true> inside another
1396 // content iframe is not actually a root content document, but we say it is.
1397 //
1398 // We do this because we make a remote frame opaque iff
1399 // IsRootContentDocument(), and making vanilla remote frames transparent
1400 // breaks our remote reftests.
1401
1402 return !HasAppOwnerApp();
1403 }
1404
1405 bool
1406 TabChild::RecvLoadURL(const nsCString& uri)
1407 {
1408 SetProcessNameToAppName();
1409
1410 nsresult rv = WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(uri).get(),
1411 nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
1412 nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER,
1413 nullptr, nullptr, nullptr);
1414 if (NS_FAILED(rv)) {
1415 NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?");
1416 }
1417
1418 #ifdef MOZ_CRASHREPORTER
1419 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), uri);
1420 #endif
1421
1422 return true;
1423 }
1424
1425 bool
1426 TabChild::RecvCacheFileDescriptor(const nsString& aPath,
1427 const FileDescriptor& aFileDescriptor)
1428 {
1429 MOZ_ASSERT(NS_IsMainThread());
1430 MOZ_ASSERT(!aPath.IsEmpty());
1431 MOZ_ASSERT(!mAppPackageFileDescriptorRecved);
1432
1433 mAppPackageFileDescriptorRecved = true;
1434
1435 // aFileDescriptor may be invalid here, but the callback will choose how to
1436 // handle it.
1437
1438 // First see if we already have a request for this path.
1439 const CachedFileDescriptorInfo search(aPath);
1440 uint32_t index =
1441 mCachedFileDescriptorInfos.IndexOf(search, 0,
1442 search.PathOnlyComparator());
1443 if (index == mCachedFileDescriptorInfos.NoIndex) {
1444 // We haven't had any requests for this path yet. Assume that we will
1445 // in a little while and save the file descriptor here.
1446 mCachedFileDescriptorInfos.AppendElement(
1447 new CachedFileDescriptorInfo(aPath, aFileDescriptor));
1448 return true;
1449 }
1450
1451 nsAutoPtr<CachedFileDescriptorInfo>& info =
1452 mCachedFileDescriptorInfos[index];
1453
1454 MOZ_ASSERT(info);
1455 MOZ_ASSERT(info->mPath == aPath);
1456 MOZ_ASSERT(!info->mFileDescriptor.IsValid());
1457 MOZ_ASSERT(info->mCallback);
1458
1459 // If this callback has been canceled then we can simply close the file
1460 // descriptor and forget about the callback.
1461 if (info->mCanceled) {
1462 // Only close if this is a valid file descriptor.
1463 if (aFileDescriptor.IsValid()) {
1464 nsRefPtr<CloseFileRunnable> runnable =
1465 new CloseFileRunnable(aFileDescriptor);
1466 runnable->Dispatch();
1467 }
1468 } else {
1469 // Not canceled so fire the callback.
1470 info->mFileDescriptor = aFileDescriptor;
1471
1472 // We don't need a runnable here because we should already be at the top
1473 // of the event loop. Just fire immediately.
1474 info->FireCallback();
1475 }
1476
1477 mCachedFileDescriptorInfos.RemoveElementAt(index);
1478 return true;
1479 }
1480
1481 bool
1482 TabChild::GetCachedFileDescriptor(const nsAString& aPath,
1483 nsICachedFileDescriptorListener* aCallback)
1484 {
1485 MOZ_ASSERT(NS_IsMainThread());
1486 MOZ_ASSERT(!aPath.IsEmpty());
1487 MOZ_ASSERT(aCallback);
1488
1489 // First see if we've already received a cached file descriptor for this
1490 // path.
1491 const CachedFileDescriptorInfo search(aPath);
1492 uint32_t index =
1493 mCachedFileDescriptorInfos.IndexOf(search, 0,
1494 search.PathOnlyComparator());
1495 if (index == mCachedFileDescriptorInfos.NoIndex) {
1496 // We haven't received a file descriptor for this path yet. Assume that
1497 // we will in a little while and save the request here.
1498 if (!mAppPackageFileDescriptorRecved) {
1499 mCachedFileDescriptorInfos.AppendElement(
1500 new CachedFileDescriptorInfo(aPath, aCallback));
1501 }
1502 return false;
1503 }
1504
1505 nsAutoPtr<CachedFileDescriptorInfo>& info =
1506 mCachedFileDescriptorInfos[index];
1507
1508 MOZ_ASSERT(info);
1509 MOZ_ASSERT(info->mPath == aPath);
1510
1511 // If we got a previous request for this file descriptor that was then
1512 // canceled, insert the new request ahead of the old in the queue so that
1513 // it will be serviced first.
1514 if (info->mCanceled) {
1515 // This insertion will change the array and invalidate |info|, so
1516 // be careful not to touch |info| after this.
1517 mCachedFileDescriptorInfos.InsertElementAt(index,
1518 new CachedFileDescriptorInfo(aPath, aCallback));
1519 return false;
1520 }
1521
1522 MOZ_ASSERT(!info->mCallback);
1523 info->mCallback = aCallback;
1524
1525 nsRefPtr<CachedFileDescriptorCallbackRunnable> runnable =
1526 new CachedFileDescriptorCallbackRunnable(info.forget());
1527 runnable->Dispatch();
1528
1529 mCachedFileDescriptorInfos.RemoveElementAt(index);
1530 return true;
1531 }
1532
1533 void
1534 TabChild::CancelCachedFileDescriptorCallback(
1535 const nsAString& aPath,
1536 nsICachedFileDescriptorListener* aCallback)
1537 {
1538 MOZ_ASSERT(NS_IsMainThread());
1539 MOZ_ASSERT(!aPath.IsEmpty());
1540 MOZ_ASSERT(aCallback);
1541
1542 if (mAppPackageFileDescriptorRecved) {
1543 // Already received cached file descriptor for the app package. Nothing to do here.
1544 return;
1545 }
1546
1547 const CachedFileDescriptorInfo search(aPath, aCallback);
1548 uint32_t index =
1549 mCachedFileDescriptorInfos.IndexOf(search, 0,
1550 search.PathAndCallbackComparator());
1551 if (index == mCachedFileDescriptorInfos.NoIndex) {
1552 // Nothing to do here.
1553 return;
1554 }
1555
1556 nsAutoPtr<CachedFileDescriptorInfo>& info =
1557 mCachedFileDescriptorInfos[index];
1558
1559 MOZ_ASSERT(info);
1560 MOZ_ASSERT(info->mPath == aPath);
1561 MOZ_ASSERT(!info->mFileDescriptor.IsValid());
1562 MOZ_ASSERT(info->mCallback == aCallback);
1563 MOZ_ASSERT(!info->mCanceled);
1564
1565 // Set this flag so that we will close the file descriptor when it arrives.
1566 info->mCanceled = true;
1567 }
1568
1569 void
1570 TabChild::DoFakeShow()
1571 {
1572 RecvShow(nsIntSize(0, 0));
1573 mDidFakeShow = true;
1574 }
1575
1576 bool
1577 TabChild::RecvShow(const nsIntSize& size)
1578 {
1579
1580 if (mDidFakeShow) {
1581 return true;
1582 }
1583
1584 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
1585 if (!baseWindow) {
1586 NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow");
1587 return false;
1588 }
1589
1590 if (!InitRenderingState()) {
1591 // We can fail to initialize our widget if the <browser
1592 // remote> has already been destroyed, and we couldn't hook
1593 // into the parent-process's layer system. That's not a fatal
1594 // error.
1595 return true;
1596 }
1597
1598 baseWindow->SetVisibility(true);
1599
1600 return InitTabChildGlobal();
1601 }
1602
1603 bool
1604 TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size, const ScreenOrientation& orientation)
1605 {
1606 if (!mRemoteFrame) {
1607 return true;
1608 }
1609
1610 mOuterRect.x = rect.x;
1611 mOuterRect.y = rect.y;
1612 mOuterRect.width = rect.width;
1613 mOuterRect.height = rect.height;
1614
1615 bool initialSizing = !HasValidInnerSize()
1616 && (size.width != 0 && size.height != 0);
1617
1618 mOrientation = orientation;
1619 mInnerSize = ScreenIntSize::FromUnknownSize(
1620 gfx::IntSize(size.width, size.height));
1621 mWidget->Resize(0, 0, size.width, size.height,
1622 true);
1623
1624 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
1625 baseWin->SetPositionAndSize(0, 0, size.width, size.height,
1626 true);
1627
1628 if (initialSizing && mContentDocumentIsDisplayed) {
1629 // If this is the first time we're getting a valid mInnerSize, and the
1630 // before-first-paint event has already been handled, then we need to set
1631 // up our default viewport here. See the corresponding call to
1632 // InitializeRootMetrics in the before-first-paint handler.
1633 InitializeRootMetrics();
1634 }
1635
1636 HandlePossibleViewportChange();
1637
1638 return true;
1639 }
1640
1641 bool
1642 TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
1643 {
1644 return TabChildBase::UpdateFrameHandler(aFrameMetrics);
1645 }
1646
1647 bool
1648 TabChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
1649 const uint32_t& aScrollGeneration)
1650 {
1651 APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
1652 return true;
1653 }
1654
1655 bool
1656 TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
1657 {
1658 if (!mGlobal || !mTabChildGlobal) {
1659 return true;
1660 }
1661
1662 CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
1663 nsString data;
1664 data.AppendLiteral("{ \"x\" : ");
1665 data.AppendFloat(point.x);
1666 data.AppendLiteral(", \"y\" : ");
1667 data.AppendFloat(point.y);
1668 data.AppendLiteral(" }");
1669
1670 DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
1671
1672 return true;
1673 }
1674
1675 bool
1676 TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
1677 {
1678 if (!mGlobal || !mTabChildGlobal) {
1679 return true;
1680 }
1681
1682 LayoutDevicePoint currentPoint = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();;
1683
1684 MessageLoop::current()->PostDelayedTask(
1685 FROM_HERE,
1686 NewRunnableMethod(this, &TabChild::FireSingleTapEvent, currentPoint),
1687 sActiveDurationMs);
1688 return true;
1689 }
1690
1691 void
1692 TabChild::FireSingleTapEvent(LayoutDevicePoint aPoint)
1693 {
1694 int time = 0;
1695 DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, mWidget);
1696 DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, mWidget);
1697 DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, mWidget);
1698 }
1699
1700 bool
1701 TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
1702 {
1703 if (!mGlobal || !mTabChildGlobal) {
1704 return true;
1705 }
1706
1707 mContextMenuHandled =
1708 DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
1709 APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid),
1710 2, 1, 0, false,
1711 nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
1712
1713 SendContentReceivedTouch(aGuid, mContextMenuHandled);
1714
1715 return true;
1716 }
1717
1718 bool
1719 TabChild::RecvHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
1720 {
1721 if (mContextMenuHandled) {
1722 mContextMenuHandled = false;
1723 return true;
1724 }
1725
1726 RecvHandleSingleTap(aPoint, aGuid);
1727 return true;
1728 }
1729
1730 bool
1731 TabChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
1732 const APZStateChange& aChange,
1733 const int& aArg)
1734 {
1735 switch (aChange)
1736 {
1737 case APZStateChange::TransformBegin:
1738 {
1739 nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
1740 nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sf);
1741 if (scrollbarOwner) {
1742 scrollbarOwner->ScrollbarActivityStarted();
1743 }
1744 break;
1745 }
1746 case APZStateChange::TransformEnd:
1747 {
1748 nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
1749 nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sf);
1750 if (scrollbarOwner) {
1751 scrollbarOwner->ScrollbarActivityStopped();
1752 }
1753 break;
1754 }
1755 case APZStateChange::StartTouch:
1756 {
1757 mActiveElementManager->HandleTouchStart(aArg);
1758 break;
1759 }
1760 case APZStateChange::StartPanning:
1761 {
1762 mActiveElementManager->HandlePanStart();
1763 break;
1764 }
1765 case APZStateChange::EndTouch:
1766 {
1767 mActiveElementManager->HandleTouchEnd(aArg);
1768 break;
1769 }
1770 default:
1771 // APZStateChange has a 'sentinel' value, and the compiler complains
1772 // if an enumerator is not handled and there is no 'default' case.
1773 break;
1774 }
1775 return true;
1776 }
1777
1778 bool
1779 TabChild::RecvActivate()
1780 {
1781 nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(WebNavigation());
1782 browser->Activate();
1783 return true;
1784 }
1785
1786 bool TabChild::RecvDeactivate()
1787 {
1788 nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(WebNavigation());
1789 browser->Deactivate();
1790 return true;
1791 }
1792
1793 bool
1794 TabChild::RecvMouseEvent(const nsString& aType,
1795 const float& aX,
1796 const float& aY,
1797 const int32_t& aButton,
1798 const int32_t& aClickCount,
1799 const int32_t& aModifiers,
1800 const bool& aIgnoreRootScrollFrame)
1801 {
1802 DispatchMouseEvent(aType, CSSPoint(aX, aY), aButton, aClickCount, aModifiers,
1803 aIgnoreRootScrollFrame, nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN);
1804 return true;
1805 }
1806
1807 bool
1808 TabChild::RecvRealMouseEvent(const WidgetMouseEvent& event)
1809 {
1810 WidgetMouseEvent localEvent(event);
1811 localEvent.widget = mWidget;
1812 DispatchWidgetEvent(localEvent);
1813 return true;
1814 }
1815
1816 bool
1817 TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& event)
1818 {
1819 WidgetWheelEvent localEvent(event);
1820 localEvent.widget = mWidget;
1821 DispatchWidgetEvent(localEvent);
1822 return true;
1823 }
1824
1825 static Touch*
1826 GetTouchForIdentifier(const WidgetTouchEvent& aEvent, int32_t aId)
1827 {
1828 for (uint32_t i = 0; i < aEvent.touches.Length(); ++i) {
1829 Touch* touch = static_cast<Touch*>(aEvent.touches[i].get());
1830 if (touch->mIdentifier == aId) {
1831 return touch;
1832 }
1833 }
1834 return nullptr;
1835 }
1836
1837 void
1838 TabChild::UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus)
1839 {
1840 static bool sHavePrefs;
1841 static bool sClickHoldContextMenusEnabled;
1842 static nsIntSize sDragThreshold;
1843 static int32_t sContextMenuDelayMs;
1844 if (!sHavePrefs) {
1845 sHavePrefs = true;
1846 Preferences::AddBoolVarCache(&sClickHoldContextMenusEnabled,
1847 "ui.click_hold_context_menus", true);
1848 Preferences::AddIntVarCache(&sDragThreshold.width,
1849 "ui.dragThresholdX", 25);
1850 Preferences::AddIntVarCache(&sDragThreshold.height,
1851 "ui.dragThresholdY", 25);
1852 Preferences::AddIntVarCache(&sContextMenuDelayMs,
1853 "ui.click_hold_context_menus.delay", 500);
1854 }
1855
1856 if (aEvent.touches.Length() == 0) {
1857 return;
1858 }
1859
1860 bool currentlyTrackingTouch = (mActivePointerId >= 0);
1861 if (aEvent.message == NS_TOUCH_START) {
1862 if (currentlyTrackingTouch || aEvent.touches.Length() > 1) {
1863 // We're tracking a possible tap for another point, or we saw a
1864 // touchstart for a later pointer after we canceled tracking of
1865 // the first point. Ignore this one.
1866 return;
1867 }
1868 if (aStatus == nsEventStatus_eConsumeNoDefault ||
1869 nsIPresShell::gPreventMouseEvents ||
1870 aEvent.mFlags.mMultipleActionsPrevented) {
1871 return;
1872 }
1873
1874 Touch* touch = aEvent.touches[0];
1875 mGestureDownPoint = LayoutDevicePoint(touch->mRefPoint.x, touch->mRefPoint.y);
1876 mActivePointerId = touch->mIdentifier;
1877 if (sClickHoldContextMenusEnabled) {
1878 MOZ_ASSERT(!mTapHoldTimer);
1879 mTapHoldTimer = NewRunnableMethod(this,
1880 &TabChild::FireContextMenuEvent);
1881 MessageLoop::current()->PostDelayedTask(FROM_HERE, mTapHoldTimer,
1882 sContextMenuDelayMs);
1883 }
1884 return;
1885 }
1886
1887 // If we're not tracking a touch or this event doesn't include the
1888 // one we care about, bail.
1889 if (!currentlyTrackingTouch) {
1890 return;
1891 }
1892 Touch* trackedTouch = GetTouchForIdentifier(aEvent, mActivePointerId);
1893 if (!trackedTouch) {
1894 return;
1895 }
1896
1897 LayoutDevicePoint currentPoint = LayoutDevicePoint(trackedTouch->mRefPoint.x, trackedTouch->mRefPoint.y);
1898 int64_t time = aEvent.time;
1899 switch (aEvent.message) {
1900 case NS_TOUCH_MOVE:
1901 if (abs(currentPoint.x - mGestureDownPoint.x) > sDragThreshold.width ||
1902 abs(currentPoint.y - mGestureDownPoint.y) > sDragThreshold.height) {
1903 CancelTapTracking();
1904 }
1905 return;
1906
1907 case NS_TOUCH_END:
1908 if (!nsIPresShell::gPreventMouseEvents) {
1909 DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, mWidget);
1910 DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, mWidget);
1911 DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, mWidget);
1912 }
1913 // fall through
1914 case NS_TOUCH_CANCEL:
1915 CancelTapTracking();
1916 return;
1917
1918 default:
1919 NS_WARNING("Unknown touch event type");
1920 }
1921 }
1922
1923 void
1924 TabChild::FireContextMenuEvent()
1925 {
1926 double scale;
1927 GetDefaultScale(&scale);
1928 if (scale < 0) {
1929 scale = 1;
1930 }
1931
1932 MOZ_ASSERT(mTapHoldTimer && mActivePointerId >= 0);
1933 bool defaultPrevented = DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
1934 mGestureDownPoint / CSSToLayoutDeviceScale(scale),
1935 2 /* Right button */,
1936 1 /* Click count */,
1937 0 /* Modifiers */,
1938 false /* Ignore root scroll frame */,
1939 nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
1940
1941 // Fire a click event if someone didn't call preventDefault() on the context
1942 // menu event.
1943 if (defaultPrevented) {
1944 CancelTapTracking();
1945 } else if (mTapHoldTimer) {
1946 mTapHoldTimer->Cancel();
1947 mTapHoldTimer = nullptr;
1948 }
1949 }
1950
1951 void
1952 TabChild::CancelTapTracking()
1953 {
1954 mActivePointerId = -1;
1955 if (mTapHoldTimer) {
1956 mTapHoldTimer->Cancel();
1957 }
1958 mTapHoldTimer = nullptr;
1959 }
1960
1961 bool
1962 TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
1963 const ScrollableLayerGuid& aGuid)
1964 {
1965 WidgetTouchEvent localEvent(aEvent);
1966 localEvent.widget = mWidget;
1967 for (size_t i = 0; i < localEvent.touches.Length(); i++) {
1968 aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale());
1969 }
1970
1971 nsEventStatus status = DispatchWidgetEvent(localEvent);
1972
1973 if (!IsAsyncPanZoomEnabled()) {
1974 UpdateTapState(localEvent, status);
1975 return true;
1976 }
1977
1978 if (aEvent.message == NS_TOUCH_START && localEvent.touches.Length() > 0) {
1979 mActiveElementManager->SetTargetElement(localEvent.touches[0]->Target());
1980 }
1981
1982 nsCOMPtr<nsPIDOMWindow> outerWindow = do_GetInterface(WebNavigation());
1983 nsCOMPtr<nsPIDOMWindow> innerWindow = outerWindow->GetCurrentInnerWindow();
1984
1985 if (!innerWindow || !innerWindow->HasTouchEventListeners()) {
1986 SendContentReceivedTouch(aGuid, false);
1987 return true;
1988 }
1989
1990 bool isTouchPrevented = nsIPresShell::gPreventMouseEvents ||
1991 localEvent.mFlags.mMultipleActionsPrevented;
1992 switch (aEvent.message) {
1993 case NS_TOUCH_START: {
1994 if (isTouchPrevented) {
1995 SendContentReceivedTouch(aGuid, isTouchPrevented);
1996 } else {
1997 mWaitingTouchListeners = true;
1998 }
1999 break;
2000 }
2001
2002 case NS_TOUCH_MOVE:
2003 case NS_TOUCH_END:
2004 case NS_TOUCH_CANCEL: {
2005 if (mWaitingTouchListeners) {
2006 SendContentReceivedTouch(aGuid, isTouchPrevented);
2007 mWaitingTouchListeners = false;
2008 }
2009 break;
2010 }
2011
2012 default:
2013 NS_WARNING("Unknown touch event type");
2014 }
2015
2016 return true;
2017 }
2018
2019 bool
2020 TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
2021 const ScrollableLayerGuid& aGuid)
2022 {
2023 return RecvRealTouchEvent(aEvent, aGuid);
2024 }
2025
2026 void
2027 TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache,
2028 WidgetKeyboardEvent* aEvent)
2029 {
2030 MaybeNativeKeyBinding maybeBindings;
2031 if (!SendRequestNativeKeyBindings(*aEvent, &maybeBindings)) {
2032 return;
2033 }
2034
2035 if (maybeBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
2036 const NativeKeyBinding& bindings = maybeBindings;
2037 aAutoCache->Cache(bindings.singleLineCommands(),
2038 bindings.multiLineCommands(),
2039 bindings.richTextCommands());
2040 } else {
2041 aAutoCache->CacheNoCommands();
2042 }
2043 }
2044
2045 bool
2046 TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
2047 const MaybeNativeKeyBinding& aBindings)
2048 {
2049 PuppetWidget* widget = static_cast<PuppetWidget*>(mWidget.get());
2050 AutoCacheNativeKeyCommands autoCache(widget);
2051
2052 if (event.message == NS_KEY_PRESS) {
2053 if (aBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
2054 const NativeKeyBinding& bindings = aBindings;
2055 autoCache.Cache(bindings.singleLineCommands(),
2056 bindings.multiLineCommands(),
2057 bindings.richTextCommands());
2058 } else {
2059 autoCache.CacheNoCommands();
2060 }
2061 }
2062 // If content code called preventDefault() on a keydown event, then we don't
2063 // want to process any following keypress events.
2064 if (event.message == NS_KEY_PRESS && mIgnoreKeyPressEvent) {
2065 return true;
2066 }
2067
2068 WidgetKeyboardEvent localEvent(event);
2069 localEvent.widget = mWidget;
2070 nsEventStatus status = DispatchWidgetEvent(localEvent);
2071
2072 if (event.message == NS_KEY_DOWN) {
2073 mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
2074 }
2075
2076 if (localEvent.mFlags.mWantReplyFromContentProcess) {
2077 SendReplyKeyEvent(localEvent);
2078 }
2079
2080 return true;
2081 }
2082
2083 bool
2084 TabChild::RecvKeyEvent(const nsString& aType,
2085 const int32_t& aKeyCode,
2086 const int32_t& aCharCode,
2087 const int32_t& aModifiers,
2088 const bool& aPreventDefault)
2089 {
2090 nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
2091 NS_ENSURE_TRUE(utils, true);
2092 bool ignored = false;
2093 utils->SendKeyEvent(aType, aKeyCode, aCharCode,
2094 aModifiers, aPreventDefault, &ignored);
2095 return true;
2096 }
2097
2098 bool
2099 TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event)
2100 {
2101 WidgetCompositionEvent localEvent(event);
2102 localEvent.widget = mWidget;
2103 DispatchWidgetEvent(localEvent);
2104 return true;
2105 }
2106
2107 bool
2108 TabChild::RecvTextEvent(const WidgetTextEvent& event)
2109 {
2110 WidgetTextEvent localEvent(event);
2111 localEvent.widget = mWidget;
2112 DispatchWidgetEvent(localEvent);
2113 return true;
2114 }
2115
2116 bool
2117 TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
2118 {
2119 WidgetSelectionEvent localEvent(event);
2120 localEvent.widget = mWidget;
2121 DispatchWidgetEvent(localEvent);
2122 return true;
2123 }
2124
2125 PDocumentRendererChild*
2126 TabChild::AllocPDocumentRendererChild(const nsRect& documentRect,
2127 const mozilla::gfx::Matrix& transform,
2128 const nsString& bgcolor,
2129 const uint32_t& renderFlags,
2130 const bool& flushLayout,
2131 const nsIntSize& renderSize)
2132 {
2133 return new DocumentRendererChild();
2134 }
2135
2136 bool
2137 TabChild::DeallocPDocumentRendererChild(PDocumentRendererChild* actor)
2138 {
2139 delete actor;
2140 return true;
2141 }
2142
2143 bool
2144 TabChild::RecvPDocumentRendererConstructor(PDocumentRendererChild* actor,
2145 const nsRect& documentRect,
2146 const mozilla::gfx::Matrix& transform,
2147 const nsString& bgcolor,
2148 const uint32_t& renderFlags,
2149 const bool& flushLayout,
2150 const nsIntSize& renderSize)
2151 {
2152 DocumentRendererChild *render = static_cast<DocumentRendererChild *>(actor);
2153
2154 nsCOMPtr<nsIWebBrowser> browser = do_QueryInterface(WebNavigation());
2155 if (!browser)
2156 return true; // silently ignore
2157 nsCOMPtr<nsIDOMWindow> window;
2158 if (NS_FAILED(browser->GetContentDOMWindow(getter_AddRefs(window))) ||
2159 !window)
2160 {
2161 return true; // silently ignore
2162 }
2163
2164 nsCString data;
2165 bool ret = render->RenderDocument(window,
2166 documentRect, transform,
2167 bgcolor,
2168 renderFlags, flushLayout,
2169 renderSize, data);
2170 if (!ret)
2171 return true; // silently ignore
2172
2173 return PDocumentRendererChild::Send__delete__(actor, renderSize, data);
2174 }
2175
2176 PColorPickerChild*
2177 TabChild::AllocPColorPickerChild(const nsString&, const nsString&)
2178 {
2179 NS_RUNTIMEABORT("unused");
2180 return nullptr;
2181 }
2182
2183 bool
2184 TabChild::DeallocPColorPickerChild(PColorPickerChild* aColorPicker)
2185 {
2186 nsColorPickerProxy* picker = static_cast<nsColorPickerProxy*>(aColorPicker);
2187 NS_RELEASE(picker);
2188 return true;
2189 }
2190
2191 PContentPermissionRequestChild*
2192 TabChild::AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
2193 const IPC::Principal& aPrincipal)
2194 {
2195 NS_RUNTIMEABORT("unused");
2196 return nullptr;
2197 }
2198
2199 bool
2200 TabChild::DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor)
2201 {
2202 PCOMContentPermissionRequestChild* child =
2203 static_cast<PCOMContentPermissionRequestChild*>(actor);
2204 #ifdef DEBUG
2205 child->mIPCOpen = false;
2206 #endif /* DEBUG */
2207 child->IPDLRelease();
2208 return true;
2209 }
2210
2211 PFilePickerChild*
2212 TabChild::AllocPFilePickerChild(const nsString&, const int16_t&)
2213 {
2214 NS_RUNTIMEABORT("unused");
2215 return nullptr;
2216 }
2217
2218 bool
2219 TabChild::DeallocPFilePickerChild(PFilePickerChild* actor)
2220 {
2221 nsFilePickerProxy* filePicker = static_cast<nsFilePickerProxy*>(actor);
2222 NS_RELEASE(filePicker);
2223 return true;
2224 }
2225
2226 bool
2227 TabChild::RecvActivateFrameEvent(const nsString& aType, const bool& capture)
2228 {
2229 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
2230 NS_ENSURE_TRUE(window, true);
2231 nsCOMPtr<EventTarget> chromeHandler =
2232 do_QueryInterface(window->GetChromeEventHandler());
2233 NS_ENSURE_TRUE(chromeHandler, true);
2234 nsRefPtr<ContentListener> listener = new ContentListener(this);
2235 chromeHandler->AddEventListener(aType, listener, capture);
2236 return true;
2237 }
2238
2239 POfflineCacheUpdateChild*
2240 TabChild::AllocPOfflineCacheUpdateChild(const URIParams& manifestURI,
2241 const URIParams& documentURI,
2242 const bool& stickDocument)
2243 {
2244 NS_RUNTIMEABORT("unused");
2245 return nullptr;
2246 }
2247
2248 bool
2249 TabChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor)
2250 {
2251 OfflineCacheUpdateChild* offlineCacheUpdate = static_cast<OfflineCacheUpdateChild*>(actor);
2252 NS_RELEASE(offlineCacheUpdate);
2253 return true;
2254 }
2255
2256 bool
2257 TabChild::RecvLoadRemoteScript(const nsString& aURL, const bool& aRunInGlobalScope)
2258 {
2259 if (!mGlobal && !InitTabChildGlobal())
2260 // This can happen if we're half-destroyed. It's not a fatal
2261 // error.
2262 return true;
2263
2264 LoadFrameScriptInternal(aURL, aRunInGlobalScope);
2265 return true;
2266 }
2267
2268 bool
2269 TabChild::RecvAsyncMessage(const nsString& aMessage,
2270 const ClonedMessageData& aData,
2271 const InfallibleTArray<CpowEntry>& aCpows,
2272 const IPC::Principal& aPrincipal)
2273 {
2274 if (mTabChildGlobal) {
2275 nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
2276 StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
2277 nsRefPtr<nsFrameMessageManager> mm =
2278 static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
2279 CpowIdHolder cpows(static_cast<ContentChild*>(Manager())->GetCPOWManager(), aCpows);
2280 mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
2281 aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
2282 }
2283 return true;
2284 }
2285
2286 class UnloadScriptEvent : public nsRunnable
2287 {
2288 public:
2289 UnloadScriptEvent(TabChild* aTabChild, TabChildGlobal* aTabChildGlobal)
2290 : mTabChild(aTabChild), mTabChildGlobal(aTabChildGlobal)
2291 { }
2292
2293 NS_IMETHOD Run()
2294 {
2295 nsCOMPtr<nsIDOMEvent> event;
2296 NS_NewDOMEvent(getter_AddRefs(event), mTabChildGlobal, nullptr, nullptr);
2297 if (event) {
2298 event->InitEvent(NS_LITERAL_STRING("unload"), false, false);
2299 event->SetTrusted(true);
2300
2301 bool dummy;
2302 mTabChildGlobal->DispatchEvent(event, &dummy);
2303 }
2304
2305 return NS_OK;
2306 }
2307
2308 nsRefPtr<TabChild> mTabChild;
2309 TabChildGlobal* mTabChildGlobal;
2310 };
2311
2312 bool
2313 TabChild::RecvDestroy()
2314 {
2315 if (mTabChildGlobal) {
2316 // Let the frame scripts know the child is being closed
2317 nsContentUtils::AddScriptRunner(
2318 new UnloadScriptEvent(this, mTabChildGlobal)
2319 );
2320 }
2321
2322 nsCOMPtr<nsIObserverService> observerService =
2323 mozilla::services::GetObserverService();
2324
2325 observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
2326 observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
2327
2328 const InfallibleTArray<PIndexedDBChild*>& idbActors =
2329 ManagedPIndexedDBChild();
2330 for (uint32_t i = 0; i < idbActors.Length(); ++i) {
2331 static_cast<IndexedDBChild*>(idbActors[i])->Disconnect();
2332 }
2333
2334 // XXX what other code in ~TabChild() should we be running here?
2335 DestroyWindow();
2336
2337 return Send__delete__(this);
2338 }
2339
2340 bool
2341 TabChild::RecvSetUpdateHitRegion(const bool& aEnabled)
2342 {
2343 mUpdateHitRegion = aEnabled;
2344 return true;
2345 }
2346
2347 bool
2348 TabChild::RecvSetIsDocShellActive(const bool& aIsActive)
2349 {
2350 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2351 if (docShell) {
2352 docShell->SetIsActive(aIsActive);
2353 }
2354 return true;
2355 }
2356
2357 PRenderFrameChild*
2358 TabChild::AllocPRenderFrameChild()
2359 {
2360 return new RenderFrameChild();
2361 }
2362
2363 bool
2364 TabChild::DeallocPRenderFrameChild(PRenderFrameChild* aFrame)
2365 {
2366 delete aFrame;
2367 return true;
2368 }
2369
2370 bool
2371 TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
2372 {
2373 if (!mGlobal && !mTabChildGlobal) {
2374 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
2375 NS_ENSURE_TRUE(window, false);
2376 nsCOMPtr<EventTarget> chromeHandler =
2377 do_QueryInterface(window->GetChromeEventHandler());
2378 NS_ENSURE_TRUE(chromeHandler, false);
2379
2380 nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
2381 mTabChildGlobal = scope;
2382
2383 nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, scope);
2384
2385 NS_NAMED_LITERAL_CSTRING(globalId, "outOfProcessTabChildGlobal");
2386 NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports, globalId), false);
2387
2388 scope->Init();
2389
2390 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
2391 NS_ENSURE_TRUE(root, false);
2392 root->SetParentTarget(scope);
2393
2394 chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
2395 }
2396
2397 if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
2398 mTriedBrowserInit = true;
2399 // Initialize the child side of the browser element machinery,
2400 // if appropriate.
2401 if (IsBrowserOrApp()) {
2402 RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
2403 }
2404 }
2405
2406 return true;
2407 }
2408
2409 bool
2410 TabChild::InitRenderingState()
2411 {
2412 static_cast<PuppetWidget*>(mWidget.get())->InitIMEState();
2413
2414 uint64_t id;
2415 bool success;
2416 RenderFrameChild* remoteFrame =
2417 static_cast<RenderFrameChild*>(SendPRenderFrameConstructor());
2418 if (!remoteFrame) {
2419 NS_WARNING("failed to construct RenderFrame");
2420 return false;
2421 }
2422 SendInitRenderFrame(remoteFrame, &mScrolling, &mTextureFactoryIdentifier, &id, &success);
2423 if (!success) {
2424 NS_WARNING("failed to construct RenderFrame");
2425 PRenderFrameChild::Send__delete__(remoteFrame);
2426 return false;
2427 }
2428
2429 PLayerTransactionChild* shadowManager = nullptr;
2430 if (id != 0) {
2431 // Pushing layers transactions directly to a separate
2432 // compositor context.
2433 PCompositorChild* compositorChild = CompositorChild::Get();
2434 if (!compositorChild) {
2435 NS_WARNING("failed to get CompositorChild instance");
2436 return false;
2437 }
2438 nsTArray<LayersBackend> backends;
2439 backends.AppendElement(mTextureFactoryIdentifier.mParentBackend);
2440 bool success;
2441 shadowManager =
2442 compositorChild->SendPLayerTransactionConstructor(backends,
2443 id, &mTextureFactoryIdentifier, &success);
2444 if (!success) {
2445 NS_WARNING("failed to properly allocate layer transaction");
2446 return false;
2447 }
2448 } else {
2449 // Pushing transactions to the parent content.
2450 shadowManager = remoteFrame->SendPLayerTransactionConstructor();
2451 }
2452
2453 if (!shadowManager) {
2454 NS_WARNING("failed to construct LayersChild");
2455 // This results in |remoteFrame| being deleted.
2456 PRenderFrameChild::Send__delete__(remoteFrame);
2457 return false;
2458 }
2459
2460 ShadowLayerForwarder* lf =
2461 mWidget->GetLayerManager(shadowManager, mTextureFactoryIdentifier.mParentBackend)
2462 ->AsShadowForwarder();
2463 NS_ABORT_IF_FALSE(lf && lf->HasShadowManager(),
2464 "PuppetWidget should have shadow manager");
2465 lf->IdentifyTextureHost(mTextureFactoryIdentifier);
2466 ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
2467
2468 mRemoteFrame = remoteFrame;
2469 if (id != 0) {
2470 if (!sTabChildren) {
2471 sTabChildren = new TabChildMap;
2472 }
2473 sTabChildren->Put(id, this);
2474 mLayersId = id;
2475 }
2476
2477 nsCOMPtr<nsIObserverService> observerService =
2478 mozilla::services::GetObserverService();
2479
2480 if (observerService) {
2481 observerService->AddObserver(this,
2482 BROWSER_ZOOM_TO_RECT,
2483 false);
2484 observerService->AddObserver(this,
2485 BEFORE_FIRST_PAINT,
2486 false);
2487 }
2488
2489 // This state can't change during the lifetime of the child.
2490 sCpowsEnabled = BrowserTabsRemote();
2491 if (Preferences::GetBool("dom.ipc.cpows.force-enabled", false))
2492 sCpowsEnabled = true;
2493
2494 return true;
2495 }
2496
2497 void
2498 TabChild::SetBackgroundColor(const nscolor& aColor)
2499 {
2500 if (mLastBackgroundColor != aColor) {
2501 mLastBackgroundColor = aColor;
2502 SendSetBackgroundColor(mLastBackgroundColor);
2503 }
2504 }
2505
2506 void
2507 TabChild::GetDPI(float* aDPI)
2508 {
2509 *aDPI = -1.0;
2510 if (!mRemoteFrame) {
2511 return;
2512 }
2513
2514 SendGetDPI(aDPI);
2515 }
2516
2517 void
2518 TabChild::GetDefaultScale(double* aScale)
2519 {
2520 *aScale = -1.0;
2521 if (!mRemoteFrame) {
2522 return;
2523 }
2524
2525 SendGetDefaultScale(aScale);
2526 }
2527
2528 void
2529 TabChild::NotifyPainted()
2530 {
2531 if (UseDirectCompositor() && !mNotified) {
2532 mRemoteFrame->SendNotifyCompositorTransaction();
2533 mNotified = true;
2534 }
2535 }
2536
2537 bool
2538 TabChild::DispatchMouseEvent(const nsString& aType,
2539 const CSSPoint& aPoint,
2540 const int32_t& aButton,
2541 const int32_t& aClickCount,
2542 const int32_t& aModifiers,
2543 const bool& aIgnoreRootScrollFrame,
2544 const unsigned short& aInputSourceArg)
2545 {
2546 nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
2547 NS_ENSURE_TRUE(utils, true);
2548
2549 bool defaultPrevented = false;
2550 utils->SendMouseEvent(aType, aPoint.x, aPoint.y, aButton, aClickCount, aModifiers,
2551 aIgnoreRootScrollFrame, 0, aInputSourceArg, false, 4, &defaultPrevented);
2552 return defaultPrevented;
2553 }
2554
2555 void
2556 TabChild::MakeVisible()
2557 {
2558 if (mWidget) {
2559 mWidget->Show(true);
2560 }
2561 }
2562
2563 void
2564 TabChild::MakeHidden()
2565 {
2566 if (mWidget) {
2567 mWidget->Show(false);
2568 }
2569 }
2570
2571 void
2572 TabChild::UpdateHitRegion(const nsRegion& aRegion)
2573 {
2574 mRemoteFrame->SendUpdateHitRegion(aRegion);
2575 }
2576
2577 NS_IMETHODIMP
2578 TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
2579 {
2580 if (mTabChildGlobal) {
2581 NS_ADDREF(*aResult = mTabChildGlobal);
2582 return NS_OK;
2583 }
2584 *aResult = nullptr;
2585 return NS_ERROR_FAILURE;
2586 }
2587
2588 void
2589 TabChild::SendRequestFocus(bool aCanFocus)
2590 {
2591 PBrowserChild::SendRequestFocus(aCanFocus);
2592 }
2593
2594 PIndexedDBChild*
2595 TabChild::AllocPIndexedDBChild(
2596 const nsCString& aGroup,
2597 const nsCString& aASCIIOrigin, bool* /* aAllowed */)
2598 {
2599 NS_NOTREACHED("Should never get here!");
2600 return nullptr;
2601 }
2602
2603 bool
2604 TabChild::DeallocPIndexedDBChild(PIndexedDBChild* aActor)
2605 {
2606 delete aActor;
2607 return true;
2608 }
2609
2610 bool
2611 TabChild::DoSendBlockingMessage(JSContext* aCx,
2612 const nsAString& aMessage,
2613 const StructuredCloneData& aData,
2614 JS::Handle<JSObject *> aCpows,
2615 nsIPrincipal* aPrincipal,
2616 InfallibleTArray<nsString>* aJSONRetVal,
2617 bool aIsSync)
2618 {
2619 ContentChild* cc = Manager();
2620 ClonedMessageData data;
2621 if (!BuildClonedMessageDataForChild(cc, aData, data)) {
2622 return false;
2623 }
2624 InfallibleTArray<CpowEntry> cpows;
2625 if (sCpowsEnabled) {
2626 if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
2627 return false;
2628 }
2629 }
2630 if (aIsSync) {
2631 return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
2632 aPrincipal, aJSONRetVal);
2633 }
2634
2635 return CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
2636 aPrincipal, aJSONRetVal);
2637 }
2638
2639 bool
2640 TabChild::DoSendAsyncMessage(JSContext* aCx,
2641 const nsAString& aMessage,
2642 const StructuredCloneData& aData,
2643 JS::Handle<JSObject *> aCpows,
2644 nsIPrincipal* aPrincipal)
2645 {
2646 ContentChild* cc = Manager();
2647 ClonedMessageData data;
2648 if (!BuildClonedMessageDataForChild(cc, aData, data)) {
2649 return false;
2650 }
2651 InfallibleTArray<CpowEntry> cpows;
2652 if (sCpowsEnabled) {
2653 if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
2654 return false;
2655 }
2656 }
2657 return SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
2658 aPrincipal);
2659 }
2660
2661 TabChild*
2662 TabChild::GetFrom(nsIPresShell* aPresShell)
2663 {
2664 nsIDocument* doc = aPresShell->GetDocument();
2665 if (!doc) {
2666 return nullptr;
2667 }
2668 nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell());
2669 return GetFrom(docShell);
2670 }
2671
2672 TabChild*
2673 TabChild::GetFrom(uint64_t aLayersId)
2674 {
2675 if (!sTabChildren) {
2676 return nullptr;
2677 }
2678 return sTabChildren->Get(aLayersId);
2679 }
2680
2681 void
2682 TabChild::DidComposite()
2683 {
2684 MOZ_ASSERT(mWidget);
2685 MOZ_ASSERT(mWidget->GetLayerManager());
2686 MOZ_ASSERT(mWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT);
2687
2688 ClientLayerManager *manager = static_cast<ClientLayerManager*>(mWidget->GetLayerManager());
2689 manager->DidComposite();
2690 }
2691
2692 NS_IMETHODIMP
2693 TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText)
2694 {
2695 nsString str(aTipText);
2696 SendShowTooltip(aXCoords, aYCoords, str);
2697 return NS_OK;
2698 }
2699
2700 NS_IMETHODIMP
2701 TabChild::OnHideTooltip()
2702 {
2703 SendHideTooltip();
2704 return NS_OK;
2705 }
2706
2707 TabChildGlobal::TabChildGlobal(TabChildBase* aTabChild)
2708 : mTabChild(aTabChild)
2709 {
2710 }
2711
2712 void
2713 TabChildGlobal::Init()
2714 {
2715 NS_ASSERTION(!mMessageManager, "Re-initializing?!?");
2716 mMessageManager = new nsFrameMessageManager(mTabChild,
2717 nullptr,
2718 MM_CHILD);
2719 }
2720
2721 NS_IMPL_CYCLE_COLLECTION_INHERITED(TabChildGlobal, DOMEventTargetHelper,
2722 mMessageManager, mTabChild)
2723
2724 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChildGlobal)
2725 NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager)
2726 NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
2727 NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
2728 NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
2729 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
2730 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
2731 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager)
2732 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
2733
2734 NS_IMPL_ADDREF_INHERITED(TabChildGlobal, DOMEventTargetHelper)
2735 NS_IMPL_RELEASE_INHERITED(TabChildGlobal, DOMEventTargetHelper)
2736
2737 /* [notxpcom] boolean markForCC (); */
2738 // This method isn't automatically forwarded safely because it's notxpcom, so
2739 // the IDL binding doesn't know what value to return.
2740 NS_IMETHODIMP_(bool)
2741 TabChildGlobal::MarkForCC()
2742 {
2743 return mMessageManager ? mMessageManager->MarkForCC() : false;
2744 }
2745
2746 NS_IMETHODIMP
2747 TabChildGlobal::GetContent(nsIDOMWindow** aContent)
2748 {
2749 *aContent = nullptr;
2750 if (!mTabChild)
2751 return NS_ERROR_NULL_POINTER;
2752 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mTabChild->WebNavigation());
2753 window.swap(*aContent);
2754 return NS_OK;
2755 }
2756
2757 NS_IMETHODIMP
2758 TabChildGlobal::PrivateNoteIntentionalCrash()
2759 {
2760 mozilla::NoteIntentionalCrash("tab");
2761 return NS_OK;
2762 }
2763
2764 NS_IMETHODIMP
2765 TabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
2766 {
2767 *aDocShell = nullptr;
2768 if (!mTabChild)
2769 return NS_ERROR_NULL_POINTER;
2770 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mTabChild->WebNavigation());
2771 docShell.swap(*aDocShell);
2772 return NS_OK;
2773 }
2774
2775 NS_IMETHODIMP
2776 TabChildGlobal::Btoa(const nsAString& aBinaryData,
2777 nsAString& aAsciiBase64String)
2778 {
2779 return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
2780 }
2781
2782 NS_IMETHODIMP
2783 TabChildGlobal::Atob(const nsAString& aAsciiString,
2784 nsAString& aBinaryData)
2785 {
2786 return nsContentUtils::Atob(aAsciiString, aBinaryData);
2787 }
2788
2789 JSContext*
2790 TabChildGlobal::GetJSContextForEventHandlers()
2791 {
2792 return nsContentUtils::GetSafeJSContext();
2793 }
2794
2795 nsIPrincipal*
2796 TabChildGlobal::GetPrincipal()
2797 {
2798 if (!mTabChild)
2799 return nullptr;
2800 return mTabChild->GetPrincipal();
2801 }
2802
2803 JSObject*
2804 TabChildGlobal::GetGlobalJSObject()
2805 {
2806 NS_ENSURE_TRUE(mTabChild, nullptr);
2807 nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mTabChild->GetGlobal();
2808 NS_ENSURE_TRUE(ref, nullptr);
2809 return ref->GetJSObject();
2810 }
2811

mercurial