gecko/dom/ipc/TabParent.cpp
Kartikaya Gupta 55c123d4d6 Bug 885023 - Convert mFrameMetrics.mZoom to a CSSToScreenScale. r=BenWa,k17e
The mFrameMetrics.mZoom was previously a "resolution-independent" zoom,
which meant it had to always be multiplied by the CalculateIntrinsicScale()
value to be useful. This patch converts it to a "resolution-dependent" zoom,
and includes the intrinsic scale multiplier already. This means it needs
to be updated if either the viewport or composition bounds (which determine
the intrinsic scale) change, but there are only a few places where this
happens and it makes the rest of the code cleaner.
2013-08-26 09:50:30 -04:00

1586 lines
45 KiB
C++

/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "TabParent.h"
#include "Blob.h"
#include "IDBFactory.h"
#include "IndexedDBParent.h"
#include "mozIApplication.h"
#include "mozilla/BrowserElementParent.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/Hal.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layout/RenderFrameParent.h"
#include "mozilla/Preferences.h"
#include "mozilla/unused.h"
#include "nsCOMPtr.h"
#include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
#include "nsDebug.h"
#include "nsEventDispatcher.h"
#include "nsEventStateManager.h"
#include "nsFocusManager.h"
#include "nsFrameLoader.h"
#include "nsIContent.h"
#include "nsIDocShell.h"
#include "nsIDOMApplicationRegistry.h"
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include "nsIDOMHTMLFrameElement.h"
#include "nsIDOMWindow.h"
#include "nsIDialogCreator.h"
#include "nsIPromptFactory.h"
#include "nsIURI.h"
#include "nsIMozBrowserFrame.h"
#include "nsIScriptSecurityManager.h"
#include "nsIWebBrowserChrome.h"
#include "nsIXULBrowserWindow.h"
#include "nsIXULWindow.h"
#include "nsViewManager.h"
#include "nsIWidget.h"
#include "nsIWindowWatcher.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsPrintfCString.h"
#include "nsSerializationHelper.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "private/pprio.h"
#include "StructuredCloneUtils.h"
#include "JavaScriptParent.h"
#include "TabChild.h"
#include <algorithm>
using namespace mozilla::dom;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::layout;
using namespace mozilla::services;
using namespace mozilla::widget;
using namespace mozilla::dom::indexedDB;
using namespace mozilla::jsipc;
// The flags passed by the webProgress notifications are 16 bits shifted
// from the ones registered by webProgressListeners.
#define NOTIFY_FLAG_SHIFT 16
class OpenFileAndSendFDRunnable : public nsRunnable
{
const nsString mPath;
nsRefPtr<TabParent> mTabParent;
nsCOMPtr<nsIEventTarget> mEventTarget;
PRFileDesc* mFD;
public:
OpenFileAndSendFDRunnable(const nsAString& aPath, TabParent* aTabParent)
: mPath(aPath), mTabParent(aTabParent), mFD(nullptr)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aPath.IsEmpty());
MOZ_ASSERT(aTabParent);
}
void Dispatch()
{
MOZ_ASSERT(NS_IsMainThread());
mEventTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
NS_ENSURE_TRUE_VOID(mEventTarget);
nsresult rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS_VOID(rv);
}
private:
~OpenFileAndSendFDRunnable()
{
MOZ_ASSERT(!mFD);
}
// This shouldn't be called directly except by the event loop. Use Dispatch
// to start the sequence.
NS_IMETHOD Run()
{
if (NS_IsMainThread()) {
SendResponse();
} else if (mFD) {
CloseFile();
} else {
OpenFile();
}
return NS_OK;
}
void SendResponse()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mTabParent);
MOZ_ASSERT(mEventTarget);
MOZ_ASSERT(mFD);
nsRefPtr<TabParent> tabParent;
mTabParent.swap(tabParent);
FileDescriptor::PlatformHandleType handle =
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFD));
mozilla::unused << tabParent->SendCacheFileDescriptor(mPath, handle);
nsCOMPtr<nsIEventTarget> eventTarget;
mEventTarget.swap(eventTarget);
if (NS_FAILED(eventTarget->Dispatch(this, NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch to stream transport service!");
// It's probably safer to take the main thread IO hit here rather
// than leak a file descriptor.
CloseFile();
}
}
void OpenFile()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!mFD);
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewLocalFile(mPath, false, getter_AddRefs(file));
NS_ENSURE_SUCCESS_VOID(rv);
PRFileDesc* fd;
rv = file->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
NS_ENSURE_SUCCESS_VOID(rv);
mFD = fd;
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch to main thread!");
CloseFile();
}
}
void CloseFile()
{
// It's possible for this to happen on the main thread if the dispatch
// to the stream service fails after we've already opened the file so
// we can't assert the thread we're running on.
MOZ_ASSERT(mFD);
PR_Close(mFD);
mFD = nullptr;
}
};
namespace mozilla {
namespace dom {
TabParent* sEventCapturer;
TabParent *TabParent::mIMETabParent = nullptr;
NS_IMPL_ISUPPORTS3(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI)
TabParent::TabParent(ContentParent* aManager, const TabContext& aContext)
: TabContext(aContext)
, mFrameElement(NULL)
, mIMESelectionAnchor(0)
, mIMESelectionFocus(0)
, mIMEComposing(false)
, mIMECompositionEnding(false)
, mIMECompositionStart(0)
, mIMESeqno(0)
, mEventCaptureDepth(0)
, mRect(0, 0, 0, 0)
, mDimensions(0, 0)
, mOrientation(0)
, mDPI(0)
, mDefaultScale(0)
, mShown(false)
, mUpdatedDimensions(false)
, mManager(aManager)
, mMarkedDestroying(false)
, mIsDestroyed(false)
, mAppPackageFileDescriptorSent(false)
{
}
TabParent::~TabParent()
{
}
void
TabParent::SetOwnerElement(Element* aElement)
{
mFrameElement = aElement;
TryCacheDPIAndScale();
}
void
TabParent::GetAppType(nsAString& aOut)
{
aOut.Truncate();
nsCOMPtr<Element> elem = do_QueryInterface(mFrameElement);
if (!elem) {
return;
}
elem->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapptype, aOut);
}
bool
TabParent::IsVisible()
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
return false;
}
bool visible = false;
frameLoader->GetVisible(&visible);
return visible;
}
void
TabParent::Destroy()
{
if (mIsDestroyed) {
return;
}
// If this fails, it's most likely due to a content-process crash,
// and auto-cleanup will kick in. Otherwise, the child side will
// destroy itself and send back __delete__().
unused << SendDestroy();
const InfallibleTArray<PIndexedDBParent*>& idbParents =
ManagedPIndexedDBParent();
for (uint32_t i = 0; i < idbParents.Length(); ++i) {
static_cast<IndexedDBParent*>(idbParents[i])->Disconnect();
}
if (RenderFrameParent* frame = GetRenderFrame()) {
frame->Destroy();
}
mIsDestroyed = true;
Manager()->NotifyTabDestroying(this);
mMarkedDestroying = true;
}
bool
TabParent::Recv__delete__()
{
Manager()->NotifyTabDestroyed(this, mMarkedDestroying);
return true;
}
void
TabParent::ActorDestroy(ActorDestroyReason why)
{
if (sEventCapturer == this) {
sEventCapturer = nullptr;
}
if (mIMETabParent == this) {
mIMETabParent = nullptr;
}
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (frameLoader) {
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr);
frameLoader->DestroyChild();
if (why == AbnormalShutdown && os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
"oop-frameloader-crashed", nullptr);
}
}
if (os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsITabParent*, this), "ipc:browser-destroyed", nullptr);
}
}
bool
TabParent::RecvMoveFocus(const bool& aForward)
{
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
if (fm) {
nsCOMPtr<nsIDOMElement> dummy;
uint32_t type = aForward ? uint32_t(nsIFocusManager::MOVEFOCUS_FORWARD)
: uint32_t(nsIFocusManager::MOVEFOCUS_BACKWARD);
nsCOMPtr<nsIDOMElement> frame = do_QueryInterface(mFrameElement);
fm->MoveFocus(nullptr, frame, type, nsIFocusManager::FLAG_BYKEY,
getter_AddRefs(dummy));
}
return true;
}
bool
TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
{
nsCOMPtr<nsIDOMEvent> event = do_QueryInterface(aEvent.mEvent);
NS_ENSURE_TRUE(event, true);
nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
NS_ENSURE_TRUE(target, true);
event->SetOwner(target);
bool dummy;
target->DispatchEvent(event, &dummy);
return true;
}
bool
TabParent::AnswerCreateWindow(PBrowserParent** retval)
{
if (!mBrowserDOMWindow) {
return false;
}
// Only non-app, non-browser processes may call CreateWindow.
if (IsBrowserOrApp()) {
return false;
}
// Get a new rendering area from the browserDOMWin. We don't want
// to be starting any loads here, so get it with a null URI.
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
mBrowserDOMWindow->OpenURIInFrame(nullptr, nullptr,
nsIBrowserDOMWindow::OPEN_NEWTAB,
nsIBrowserDOMWindow::OPEN_NEW,
getter_AddRefs(frameLoaderOwner));
if (!frameLoaderOwner) {
return false;
}
nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
if (!frameLoader) {
return false;
}
*retval = frameLoader->GetRemoteBrowser();
return true;
}
void
TabParent::LoadURL(nsIURI* aURI)
{
MOZ_ASSERT(aURI);
if (mIsDestroyed) {
return;
}
nsCString spec;
aURI->GetSpec(spec);
if (!mShown) {
NS_WARNING(nsPrintfCString("TabParent::LoadURL(%s) called before "
"Show(). Ignoring LoadURL.\n",
spec.get()).get());
return;
}
unused << SendLoadURL(spec);
// If this app is a packaged app then we can speed startup by sending over
// the file descriptor for the "application.zip" file that it will
// invariably request. Only do this once.
if (!mAppPackageFileDescriptorSent) {
mAppPackageFileDescriptorSent = true;
nsCOMPtr<mozIApplication> app = GetOwnOrContainingApp();
if (app) {
nsString manifestURL;
nsresult rv = app->GetManifestURL(manifestURL);
NS_ENSURE_SUCCESS_VOID(rv);
if (StringBeginsWith(manifestURL, NS_LITERAL_STRING("app:"))) {
nsString basePath;
rv = app->GetBasePath(basePath);
NS_ENSURE_SUCCESS_VOID(rv);
nsString appId;
rv = app->GetId(appId);
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<nsIFile> packageFile;
rv = NS_NewLocalFile(basePath, false,
getter_AddRefs(packageFile));
NS_ENSURE_SUCCESS_VOID(rv);
rv = packageFile->Append(appId);
NS_ENSURE_SUCCESS_VOID(rv);
rv = packageFile->Append(NS_LITERAL_STRING("application.zip"));
NS_ENSURE_SUCCESS_VOID(rv);
nsString path;
rv = packageFile->GetPath(path);
NS_ENSURE_SUCCESS_VOID(rv);
nsRefPtr<OpenFileAndSendFDRunnable> openFileRunnable =
new OpenFileAndSendFDRunnable(path, this);
openFileRunnable->Dispatch();
}
}
}
}
void
TabParent::Show(const nsIntSize& size)
{
// sigh
mShown = true;
mDimensions = size;
if (!mIsDestroyed) {
unused << SendShow(size);
}
}
void
TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
{
if (mIsDestroyed) {
return;
}
hal::ScreenConfiguration config;
hal::GetCurrentScreenConfiguration(&config);
ScreenOrientation orientation = config.orientation();
if (!mUpdatedDimensions || mOrientation != orientation ||
mDimensions != size || !mRect.IsEqualEdges(rect)) {
mUpdatedDimensions = true;
mRect = rect;
mDimensions = size;
mOrientation = orientation;
unused << SendUpdateDimensions(mRect, mDimensions, mOrientation);
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->NotifyDimensionsChanged(ScreenIntSize::FromUnknownSize(
gfx::IntSize(mDimensions.width, mDimensions.height)));
}
}
}
void
TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
{
if (!mIsDestroyed) {
unused << SendUpdateFrame(aFrameMetrics);
}
}
void TabParent::HandleDoubleTap(const CSSIntPoint& aPoint)
{
if (!mIsDestroyed) {
unused << SendHandleDoubleTap(aPoint);
}
}
void TabParent::HandleSingleTap(const CSSIntPoint& aPoint)
{
if (!mIsDestroyed) {
unused << SendHandleSingleTap(aPoint);
}
}
void TabParent::HandleLongTap(const CSSIntPoint& aPoint)
{
if (!mIsDestroyed) {
unused << SendHandleLongTap(aPoint);
}
}
void
TabParent::Activate()
{
if (!mIsDestroyed) {
unused << SendActivate();
}
}
void
TabParent::Deactivate()
{
if (!mIsDestroyed) {
unused << SendDeactivate();
}
}
NS_IMETHODIMP
TabParent::Init(nsIDOMWindow *window)
{
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetState(uint32_t *aState)
{
NS_ENSURE_ARG(aState);
NS_WARNING("SecurityState not valid here");
*aState = 0;
return NS_OK;
}
NS_IMETHODIMP
TabParent::SetDocShell(nsIDocShell *aDocShell)
{
NS_ENSURE_ARG(aDocShell);
NS_WARNING("No mDocShell member in TabParent so there is no docShell to set");
return NS_OK;
}
PDocumentRendererParent*
TabParent::AllocPDocumentRendererParent(const nsRect& documentRect,
const gfxMatrix& transform,
const nsString& bgcolor,
const uint32_t& renderFlags,
const bool& flushLayout,
const nsIntSize& renderSize)
{
return new DocumentRendererParent();
}
bool
TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor)
{
delete actor;
return true;
}
PContentPermissionRequestParent*
TabParent::AllocPContentPermissionRequestParent(const nsCString& type, const nsCString& access, const IPC::Principal& principal)
{
return new ContentPermissionRequestParent(type, access, mFrameElement, principal);
}
bool
TabParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor)
{
delete actor;
return true;
}
void
TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
int32_t aButton, int32_t aClickCount,
int32_t aModifiers, bool aIgnoreRootScrollFrame)
{
if (!mIsDestroyed) {
unused << PBrowserParent::SendMouseEvent(nsString(aType), aX, aY,
aButton, aClickCount,
aModifiers, aIgnoreRootScrollFrame);
}
}
void
TabParent::SendKeyEvent(const nsAString& aType,
int32_t aKeyCode,
int32_t aCharCode,
int32_t aModifiers,
bool aPreventDefault)
{
if (!mIsDestroyed) {
unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode,
aModifiers, aPreventDefault);
}
}
bool
TabParent::MapEventCoordinatesForChildProcess(nsEvent* aEvent)
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
return false;
}
LayoutDeviceIntPoint offset = nsEventStateManager::GetChildProcessOffset(frameLoader, *aEvent);
MapEventCoordinatesForChildProcess(offset, aEvent);
return true;
}
void
TabParent::MapEventCoordinatesForChildProcess(
const LayoutDeviceIntPoint& aOffset, nsEvent* aEvent)
{
if (aEvent->eventStructType != NS_TOUCH_EVENT) {
aEvent->refPoint = aOffset;
} else {
aEvent->refPoint = LayoutDeviceIntPoint();
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
// Then offset all the touch points by that distance, to put them
// in the space where top-left is 0,0.
const nsTArray< nsRefPtr<Touch> >& touches = touchEvent->touches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
Touch* touch = touches[i];
if (touch) {
touch->mRefPoint += LayoutDeviceIntPoint::ToUntyped(aOffset);
}
}
}
}
bool TabParent::SendRealMouseEvent(nsMouseEvent& event)
{
if (mIsDestroyed) {
return false;
}
nsMouseEvent e(event);
MaybeForwardEventToRenderFrame(event, &e);
if (!MapEventCoordinatesForChildProcess(&e)) {
return false;
}
return PBrowserParent::SendRealMouseEvent(e);
}
bool TabParent::SendMouseWheelEvent(WheelEvent& event)
{
if (mIsDestroyed) {
return false;
}
WheelEvent e(event);
MaybeForwardEventToRenderFrame(event, &e);
if (!MapEventCoordinatesForChildProcess(&e)) {
return false;
}
return PBrowserParent::SendMouseWheelEvent(event);
}
bool TabParent::SendRealKeyEvent(nsKeyEvent& event)
{
if (mIsDestroyed) {
return false;
}
nsKeyEvent e(event);
MaybeForwardEventToRenderFrame(event, &e);
if (!MapEventCoordinatesForChildProcess(&e)) {
return false;
}
return PBrowserParent::SendRealKeyEvent(e);
}
bool TabParent::SendRealTouchEvent(nsTouchEvent& event)
{
if (mIsDestroyed) {
return false;
}
if (event.message == NS_TOUCH_START) {
// Adjust the widget coordinates to be relative to our frame.
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
// No frame anymore?
sEventCapturer = nullptr;
return false;
}
mChildProcessOffsetAtTouchStart =
nsEventStateManager::GetChildProcessOffset(frameLoader,
event);
MOZ_ASSERT((!sEventCapturer && mEventCaptureDepth == 0) ||
(sEventCapturer == this && mEventCaptureDepth > 0));
// We want to capture all remaining touch events in this series
// for fast-path dispatch.
sEventCapturer = this;
++mEventCaptureDepth;
}
nsTouchEvent e(event);
// PresShell::HandleEventInternal adds touches on touch end/cancel.
// This confuses remote content into thinking that the added touches
// are part of the touchend/cancel, when actually they're not.
if (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL) {
for (int i = e.touches.Length() - 1; i >= 0; i--) {
if (!e.touches[i]->mChanged) {
e.touches.RemoveElementAt(i);
}
}
}
MaybeForwardEventToRenderFrame(event, &e);
MapEventCoordinatesForChildProcess(mChildProcessOffsetAtTouchStart, &e);
return (e.message == NS_TOUCH_MOVE) ?
PBrowserParent::SendRealTouchMoveEvent(e) :
PBrowserParent::SendRealTouchEvent(e);
}
/*static*/ TabParent*
TabParent::GetEventCapturer()
{
return sEventCapturer;
}
bool
TabParent::TryCapture(const nsGUIEvent& aEvent)
{
MOZ_ASSERT(sEventCapturer == this && mEventCaptureDepth > 0);
if (aEvent.eventStructType != NS_TOUCH_EVENT) {
// Only capture of touch events is implemented, for now.
return false;
}
nsTouchEvent event(static_cast<const nsTouchEvent&>(aEvent));
bool isTouchPointUp = (event.message == NS_TOUCH_END ||
event.message == NS_TOUCH_CANCEL);
if (event.message == NS_TOUCH_START || isTouchPointUp) {
// Let the DOM see touch start/end events so that its touch-point
// state stays consistent.
if (isTouchPointUp && 0 == --mEventCaptureDepth) {
// All event series are un-captured, don't try to catch any
// more.
sEventCapturer = nullptr;
}
return false;
}
SendRealTouchEvent(event);
return true;
}
bool
TabParent::RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(static_cast<ContentParent*>(Manager())->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aJSONRetVal);
}
bool
TabParent::RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
{
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(static_cast<ContentParent*>(Manager())->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, false, &cloneData, &cpows, nullptr);
}
bool
TabParent::RecvSetCursor(const uint32_t& aCursor)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SetCursor((nsCursor) aCursor);
}
return true;
}
bool
TabParent::RecvSetBackgroundColor(const nscolor& aColor)
{
if (RenderFrameParent* frame = GetRenderFrame()) {
frame->SetBackgroundColor(aColor);
}
return true;
}
bool
TabParent::RecvSetStatus(const uint32_t& aType, const nsString& aStatus)
{
nsCOMPtr<nsIContent> frame = do_QueryInterface(mFrameElement);
if (frame) {
nsCOMPtr<nsISupports> container = frame->OwnerDoc()->GetContainer();
if (!container)
return true;
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
if (!docShell)
return true;
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
docShell->GetTreeOwner(getter_AddRefs(treeOwner));
if (!treeOwner)
return true;
nsCOMPtr<nsIXULWindow> window = do_GetInterface(treeOwner);
if (window) {
nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow;
window->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
if (xulBrowserWindow) {
switch (aType)
{
case nsIWebBrowserChrome::STATUS_SCRIPT:
xulBrowserWindow->SetJSStatus(aStatus);
break;
case nsIWebBrowserChrome::STATUS_LINK:
xulBrowserWindow->SetOverLink(aStatus, nullptr);
break;
}
}
}
}
return true;
}
bool
TabParent::RecvNotifyIMEFocus(const bool& aFocus,
nsIMEUpdatePreference* aPreference,
uint32_t* aSeqno)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
aPreference->mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING;
aPreference->mWantHints = false;
return true;
}
*aSeqno = mIMESeqno;
mIMETabParent = aFocus ? this : nullptr;
mIMESelectionAnchor = 0;
mIMESelectionFocus = 0;
widget->NotifyIME(aFocus ? NOTIFY_IME_OF_FOCUS : NOTIFY_IME_OF_BLUR);
if (aFocus) {
*aPreference = widget->GetIMEUpdatePreference();
} else {
mIMECacheText.Truncate(0);
}
return true;
}
bool
TabParent::RecvNotifyIMETextChange(const uint32_t& aStart,
const uint32_t& aEnd,
const uint32_t& aNewEnd)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return true;
widget->NotifyIMEOfTextChange(aStart, aEnd, aNewEnd);
return true;
}
bool
TabParent::RecvNotifyIMESelection(const uint32_t& aSeqno,
const uint32_t& aAnchor,
const uint32_t& aFocus)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return true;
if (aSeqno == mIMESeqno) {
mIMESelectionAnchor = aAnchor;
mIMESelectionFocus = aFocus;
widget->NotifyIME(NOTIFY_IME_OF_SELECTION_CHANGE);
}
return true;
}
bool
TabParent::RecvNotifyIMETextHint(const nsString& aText)
{
// Replace our cache with new text
mIMECacheText = aText;
return true;
}
/**
* Try to answer query event using cached text.
*
* For NS_QUERY_SELECTED_TEXT, fail if the cache doesn't contain the whole
* selected range. (This shouldn't happen because PuppetWidget should have
* already sent the whole selection.)
*
* For NS_QUERY_TEXT_CONTENT, fail only if the cache doesn't overlap with
* the queried range. Note the difference from above. We use
* this behavior because a normal NS_QUERY_TEXT_CONTENT event is allowed to
* have out-of-bounds offsets, so that widget can request content without
* knowing the exact length of text. It's up to widget to handle cases when
* the returned offset/length are different from the queried offset/length.
*/
bool
TabParent::HandleQueryContentEvent(nsQueryContentEvent& aEvent)
{
aEvent.mSucceeded = false;
aEvent.mWasAsync = false;
aEvent.mReply.mFocusedWidget = nsCOMPtr<nsIWidget>(GetWidget()).get();
switch (aEvent.message)
{
case NS_QUERY_SELECTED_TEXT:
{
aEvent.mReply.mOffset = std::min(mIMESelectionAnchor, mIMESelectionFocus);
if (mIMESelectionAnchor == mIMESelectionFocus) {
aEvent.mReply.mString.Truncate(0);
} else {
if (mIMESelectionAnchor > mIMECacheText.Length() ||
mIMESelectionFocus > mIMECacheText.Length()) {
break;
}
uint32_t selLen = mIMESelectionAnchor > mIMESelectionFocus ?
mIMESelectionAnchor - mIMESelectionFocus :
mIMESelectionFocus - mIMESelectionAnchor;
aEvent.mReply.mString = Substring(mIMECacheText,
aEvent.mReply.mOffset,
selLen);
}
aEvent.mReply.mReversed = mIMESelectionFocus < mIMESelectionAnchor;
aEvent.mReply.mHasSelection = true;
aEvent.mSucceeded = true;
}
break;
case NS_QUERY_TEXT_CONTENT:
{
uint32_t inputOffset = aEvent.mInput.mOffset,
inputEnd = inputOffset + aEvent.mInput.mLength;
if (inputEnd > mIMECacheText.Length()) {
inputEnd = mIMECacheText.Length();
}
if (inputEnd < inputOffset) {
break;
}
aEvent.mReply.mOffset = inputOffset;
aEvent.mReply.mString = Substring(mIMECacheText,
inputOffset,
inputEnd - inputOffset);
aEvent.mSucceeded = true;
}
break;
}
return true;
}
bool
TabParent::SendCompositionEvent(nsCompositionEvent& event)
{
if (mIsDestroyed) {
return false;
}
mIMEComposing = event.message != NS_COMPOSITION_END;
mIMECompositionStart = std::min(mIMESelectionAnchor, mIMESelectionFocus);
if (mIMECompositionEnding)
return true;
event.seqno = ++mIMESeqno;
return PBrowserParent::SendCompositionEvent(event);
}
/**
* During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION,
* widget usually sends a NS_TEXT_TEXT event to finalize or clear the
* composition, respectively
*
* Because the event will not reach content in time, we intercept it
* here and pass the text as the EndIMEComposition return value
*/
bool
TabParent::SendTextEvent(nsTextEvent& event)
{
if (mIsDestroyed) {
return false;
}
if (mIMECompositionEnding) {
mIMECompositionText = event.theText;
return true;
}
// We must be able to simulate the selection because
// we might not receive selection updates in time
if (!mIMEComposing) {
mIMECompositionStart = std::min(mIMESelectionAnchor, mIMESelectionFocus);
}
mIMESelectionAnchor = mIMESelectionFocus =
mIMECompositionStart + event.theText.Length();
event.seqno = ++mIMESeqno;
return PBrowserParent::SendTextEvent(event);
}
bool
TabParent::SendSelectionEvent(nsSelectionEvent& event)
{
if (mIsDestroyed) {
return false;
}
mIMESelectionAnchor = event.mOffset + (event.mReversed ? event.mLength : 0);
mIMESelectionFocus = event.mOffset + (!event.mReversed ? event.mLength : 0);
event.seqno = ++mIMESeqno;
return PBrowserParent::SendSelectionEvent(event);
}
/*static*/ TabParent*
TabParent::GetFrom(nsFrameLoader* aFrameLoader)
{
if (!aFrameLoader) {
return nullptr;
}
PBrowserParent* remoteBrowser = aFrameLoader->GetRemoteBrowser();
return static_cast<TabParent*>(remoteBrowser);
}
/*static*/ TabParent*
TabParent::GetFrom(nsIContent* aContent)
{
nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent);
if (!loaderOwner) {
return nullptr;
}
nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
return GetFrom(frameLoader);
}
RenderFrameParent*
TabParent::GetRenderFrame()
{
if (ManagedPRenderFrameParent().IsEmpty()) {
return nullptr;
}
return static_cast<RenderFrameParent*>(ManagedPRenderFrameParent()[0]);
}
bool
TabParent::RecvEndIMEComposition(const bool& aCancel,
nsString* aComposition)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return true;
mIMECompositionEnding = true;
widget->NotifyIME(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
REQUEST_TO_COMMIT_COMPOSITION);
mIMECompositionEnding = false;
*aComposition = mIMECompositionText;
mIMECompositionText.Truncate(0);
return true;
}
bool
TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
int32_t* aIMEOpen,
intptr_t* aNativeIMEContext)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
*aIMEEnabled = IMEState::DISABLED;
*aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
*aNativeIMEContext = 0;
return true;
}
InputContext context = widget->GetInputContext();
*aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled);
*aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen);
*aNativeIMEContext = reinterpret_cast<intptr_t>(context.mNativeIMEContext);
return true;
}
bool
TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
const int32_t& aIMEOpen,
const nsString& aType,
const nsString& aInputmode,
const nsString& aActionHint,
const int32_t& aCause,
const int32_t& aFocusChange)
{
// mIMETabParent (which is actually static) tracks which if any TabParent has IMEFocus
// When the input mode is set to anything but IMEState::DISABLED,
// mIMETabParent should be set to this
mIMETabParent =
aIMEEnabled != static_cast<int32_t>(IMEState::DISABLED) ? this : nullptr;
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget || !AllowContentIME())
return true;
InputContext context;
context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled);
context.mIMEState.mOpen = static_cast<IMEState::Open>(aIMEOpen);
context.mHTMLInputType.Assign(aType);
context.mHTMLInputInputmode.Assign(aInputmode);
context.mActionHint.Assign(aActionHint);
InputContextAction action(
static_cast<InputContextAction::Cause>(aCause),
static_cast<InputContextAction::FocusChange>(aFocusChange));
widget->SetInputContext(context, action);
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
if (!observerService)
return true;
nsAutoString state;
state.AppendInt(aIMEEnabled);
observerService->NotifyObservers(nullptr, "ime-enabled-state-changed", state.get());
return true;
}
bool
TabParent::RecvGetDPI(float* aValue)
{
TryCacheDPIAndScale();
NS_ABORT_IF_FALSE(mDPI > 0,
"Must not ask for DPI before OwnerElement is received!");
*aValue = mDPI;
return true;
}
bool
TabParent::RecvGetDefaultScale(double* aValue)
{
TryCacheDPIAndScale();
NS_ABORT_IF_FALSE(mDefaultScale > 0,
"Must not ask for scale before OwnerElement is received!");
*aValue = mDefaultScale;
return true;
}
bool
TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
if (content) {
nsIPresShell* shell = content->OwnerDoc()->GetShell();
if (shell) {
nsViewManager* vm = shell->GetViewManager();
nsCOMPtr<nsIWidget> widget;
vm->GetRootWidget(getter_AddRefs(widget));
if (widget) {
*aValue = reinterpret_cast<WindowsHandle>(
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
return true;
}
}
}
return false;
}
bool
TabParent::ReceiveMessage(const nsString& aMessage,
bool aSync,
const StructuredCloneData* aCloneData,
CpowHolder* aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (frameLoader && frameLoader->GetFrameMessageManager()) {
nsRefPtr<nsFrameMessageManager> manager =
frameLoader->GetFrameMessageManager();
manager->ReceiveMessage(mFrameElement,
aMessage,
aSync,
aCloneData,
aCpows,
aJSONRetVal);
}
return true;
}
PIndexedDBParent*
TabParent::AllocPIndexedDBParent(const nsCString& aASCIIOrigin, bool* /* aAllowed */)
{
return new IndexedDBParent(this);
}
bool
TabParent::DeallocPIndexedDBParent(PIndexedDBParent* aActor)
{
delete aActor;
return true;
}
bool
TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
const nsCString& aASCIIOrigin,
bool* aAllowed)
{
nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
NS_ENSURE_TRUE(mgr, false);
if (!IndexedDatabaseManager::IsMainProcess()) {
NS_RUNTIMEABORT("Not supported yet!");
}
nsresult rv;
// XXXbent Need to make sure we have a whitelist for chrome databases!
// Verify that the child is requesting to access a database it's allowed to
// see. (aASCIIOrigin here specifies a TabContext + a website origin, and
// we're checking that the TabContext may access it.)
//
// We have to check IsBrowserOrApp() because TabContextMayAccessOrigin will
// fail if we're not a browser-or-app, since aASCIIOrigin will be a plain URI,
// but TabContextMayAccessOrigin will construct an extended origin using
// app-id 0. Note that as written below, we allow a non browser-or-app child
// to read any database. That's a security hole, but we don't ship a
// configuration which creates non browser-or-app children, so it's not a big
// deal.
if (!aASCIIOrigin.EqualsLiteral("chrome") && IsBrowserOrApp() &&
!IndexedDatabaseManager::TabContextMayAccessOrigin(*this, aASCIIOrigin)) {
NS_WARNING("App attempted to open databases that it does not have "
"permission to access!");
return false;
}
nsCOMPtr<nsINode> node = do_QueryInterface(GetOwnerElement());
NS_ENSURE_TRUE(node, false);
nsIDocument* doc = node->GetOwnerDocument();
NS_ENSURE_TRUE(doc, false);
nsCOMPtr<nsPIDOMWindow> window = doc->GetInnerWindow();
NS_ENSURE_TRUE(window, false);
// Let's do a current inner check to see if the inner is active or is in
// bf cache, and bail out if it's not active.
nsCOMPtr<nsPIDOMWindow> outer = doc->GetWindow();
if (!outer || outer->GetCurrentInnerWindow() != window) {
*aAllowed = false;
return true;
}
ContentParent* contentParent = Manager();
NS_ASSERTION(contentParent, "Null manager?!");
nsRefPtr<IDBFactory> factory;
rv = IDBFactory::Create(window, aASCIIOrigin, contentParent,
getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, false);
if (!factory) {
*aAllowed = false;
return true;
}
IndexedDBParent* actor = static_cast<IndexedDBParent*>(aActor);
actor->mFactory = factory;
actor->mASCIIOrigin = aASCIIOrigin;
*aAllowed = true;
return true;
}
// nsIAuthPromptProvider
// This method is largely copied from nsDocShell::GetAuthPrompt
NS_IMETHODIMP
TabParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
void** aResult)
{
// we're either allowing auth, or it's a proxy request
nsresult rv;
nsCOMPtr<nsIPromptFactory> wwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMWindow> window;
nsCOMPtr<nsIContent> frame = do_QueryInterface(mFrameElement);
if (frame)
window = do_QueryInterface(frame->OwnerDoc()->GetWindow());
// Get an auth prompter for our window so that the parenting
// of the dialogs works as it should when using tabs.
return wwatch->GetPrompt(window, iid,
reinterpret_cast<void**>(aResult));
}
PContentDialogParent*
TabParent::AllocPContentDialogParent(const uint32_t& aType,
const nsCString& aName,
const nsCString& aFeatures,
const InfallibleTArray<int>& aIntParams,
const InfallibleTArray<nsString>& aStringParams)
{
ContentDialogParent* parent = new ContentDialogParent();
nsCOMPtr<nsIDialogParamBlock> params =
do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
TabChild::ArraysToParams(aIntParams, aStringParams, params);
mDelayedDialogs.AppendElement(new DelayedDialogData(parent, aType, aName,
aFeatures, params));
nsRefPtr<nsIRunnable> ev =
NS_NewRunnableMethod(this, &TabParent::HandleDelayedDialogs);
NS_DispatchToCurrentThread(ev);
return parent;
}
void
TabParent::HandleDelayedDialogs()
{
nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
nsCOMPtr<nsIDOMWindow> window;
if (mFrameElement) {
window = do_QueryInterface(mFrameElement->OwnerDoc()->GetWindow());
}
nsCOMPtr<nsIDialogCreator> dialogCreator = do_QueryInterface(mBrowserDOMWindow);
while (!ShouldDelayDialogs() && mDelayedDialogs.Length()) {
uint32_t index = mDelayedDialogs.Length() - 1;
DelayedDialogData* data = mDelayedDialogs[index];
mDelayedDialogs.RemoveElementAt(index);
nsCOMPtr<nsIDialogParamBlock> params;
params.swap(data->mParams);
PContentDialogParent* dialog = data->mDialog;
if (dialogCreator) {
nsCOMPtr<nsIDOMElement> frame = do_QueryInterface(mFrameElement);
dialogCreator->OpenDialog(data->mType,
data->mName, data->mFeatures,
params, frame);
} else if (ww) {
nsAutoCString url;
if (data->mType) {
if (data->mType == nsIDialogCreator::SELECT_DIALOG) {
url.Assign("chrome://global/content/selectDialog.xul");
} else if (data->mType == nsIDialogCreator::GENERIC_DIALOG) {
url.Assign("chrome://global/content/commonDialog.xul");
}
nsCOMPtr<nsISupports> arguments(do_QueryInterface(params));
nsCOMPtr<nsIDOMWindow> dialog;
ww->OpenWindow(window, url.get(), data->mName.get(),
data->mFeatures.get(), arguments, getter_AddRefs(dialog));
} else {
NS_WARNING("unknown dialog types aren't automatically supported in E10s yet!");
}
}
delete data;
if (dialog) {
InfallibleTArray<int32_t> intParams;
InfallibleTArray<nsString> stringParams;
TabChild::ParamsToArrays(params, intParams, stringParams);
unused << PContentDialogParent::Send__delete__(dialog,
intParams, stringParams);
}
}
if (ShouldDelayDialogs() && mDelayedDialogs.Length()) {
nsContentUtils::DispatchTrustedEvent(mFrameElement->OwnerDoc(), mFrameElement,
NS_LITERAL_STRING("MozDelayedModalDialog"),
true, true);
}
}
PRenderFrameParent*
TabParent::AllocPRenderFrameParent(ScrollingBehavior* aScrolling,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId)
{
MOZ_ASSERT(ManagedPRenderFrameParent().IsEmpty());
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
NS_WARNING("Can't allocate graphics resources, aborting subprocess");
return nullptr;
}
*aScrolling = UseAsyncPanZoom() ? ASYNC_PAN_ZOOM : DEFAULT_SCROLLING;
return new RenderFrameParent(frameLoader,
*aScrolling,
aTextureFactoryIdentifier, aLayersId);
}
bool
TabParent::DeallocPRenderFrameParent(PRenderFrameParent* aFrame)
{
delete aFrame;
return true;
}
mozilla::docshell::POfflineCacheUpdateParent*
TabParent::AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
const URIParams& aDocumentURI,
const bool& stickDocument)
{
nsRefPtr<mozilla::docshell::OfflineCacheUpdateParent> update =
new mozilla::docshell::OfflineCacheUpdateParent(OwnOrContainingAppId(),
IsBrowserElement());
nsresult rv = update->Schedule(aManifestURI, aDocumentURI, stickDocument);
if (NS_FAILED(rv))
return nullptr;
POfflineCacheUpdateParent* result = update.get();
update.forget();
return result;
}
bool
TabParent::DeallocPOfflineCacheUpdateParent(mozilla::docshell::POfflineCacheUpdateParent* actor)
{
mozilla::docshell::OfflineCacheUpdateParent* update =
static_cast<mozilla::docshell::OfflineCacheUpdateParent*>(actor);
update->Release();
return true;
}
bool
TabParent::ShouldDelayDialogs()
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
NS_ENSURE_TRUE(frameLoader, true);
bool delay = false;
frameLoader->GetDelayRemoteDialogs(&delay);
return delay;
}
bool
TabParent::AllowContentIME()
{
nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, false);
nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
if (focusedContent && focusedContent->IsEditable())
return false;
return true;
}
already_AddRefed<nsFrameLoader>
TabParent::GetFrameLoader() const
{
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(mFrameElement);
return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nullptr;
}
void
TabParent::TryCacheDPIAndScale()
{
if (mDPI > 0) {
return;
}
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget && mFrameElement) {
// Even if we don't have a widget (e.g. because we're display:none), there's
// probably a widget somewhere in the hierarchy our frame element lives in.
widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
}
if (widget) {
mDPI = widget->GetDPI();
mDefaultScale = widget->GetDefaultScale();
}
}
already_AddRefed<nsIWidget>
TabParent::GetWidget() const
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
if (!content)
return nullptr;
nsIFrame *frame = content->GetPrimaryFrame();
if (!frame)
return nullptr;
nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget();
return widget.forget();
}
bool
TabParent::UseAsyncPanZoom()
{
bool usingOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
bool asyncPanZoomEnabled =
Preferences::GetBool("layers.async-pan-zoom.enabled", false);
return (usingOffMainThreadCompositing && asyncPanZoomEnabled &&
GetScrollingBehavior() == ASYNC_PAN_ZOOM);
}
void
TabParent::MaybeForwardEventToRenderFrame(const nsInputEvent& aEvent,
nsInputEvent* aOutEvent)
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->NotifyInputEvent(aEvent, aOutEvent);
}
}
bool
TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
const nsString& aURL,
const nsString& aName,
const nsString& aFeatures,
bool* aOutWindowOpened)
{
*aOutWindowOpened =
BrowserElementParent::OpenWindowOOP(static_cast<TabParent*>(aOpener),
this, aURL, aName, aFeatures);
return true;
}
bool
TabParent::RecvPRenderFrameConstructor(PRenderFrameParent* actor,
ScrollingBehavior* scrolling,
TextureFactoryIdentifier* factoryIdentifier,
uint64_t* layersId)
{
RenderFrameParent* rfp = GetRenderFrame();
if (mDimensions != nsIntSize() && rfp) {
rfp->NotifyDimensionsChanged(ScreenIntSize::FromUnknownSize(
gfx::IntSize(mDimensions.width, mDimensions.height)));
}
return true;
}
bool
TabParent::RecvZoomToRect(const CSSRect& aRect)
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->ZoomToRect(aRect);
}
return true;
}
bool
TabParent::RecvUpdateZoomConstraints(const bool& aAllowZoom,
const CSSToScreenScale& aMinZoom,
const CSSToScreenScale& aMaxZoom)
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
}
return true;
}
bool
TabParent::RecvUpdateScrollOffset(const uint32_t& aPresShellId,
const ViewID& aViewId,
const CSSIntPoint& aScrollOffset)
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->UpdateScrollOffset(aPresShellId, aViewId, aScrollOffset);
}
return true;
}
bool
TabParent::RecvContentReceivedTouch(const bool& aPreventDefault)
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->ContentReceivedTouch(aPreventDefault);
}
return true;
}
} // namespace tabs
} // namespace mozilla