Bug 1942006 - Upstream a variety of Servo-specific code from Servo's downstream fork...
[gecko.git] / widget / nsDragServiceProxy.cpp
blobef0ecb6502e5cc1f96b0e2773d7eeb6af2107749
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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/. */
7 #include "nsDragServiceProxy.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/BrowserChild.h"
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/net/CookieJarSettings.h"
12 #include "mozilla/UniquePtr.h"
13 #include "mozilla/Unused.h"
14 #include "nsContentUtils.h"
16 using mozilla::CSSIntRegion;
17 using mozilla::LayoutDeviceIntRect;
18 using mozilla::Maybe;
19 using mozilla::Nothing;
20 using mozilla::Some;
21 using mozilla::dom::BrowserChild;
22 using mozilla::gfx::DataSourceSurface;
23 using mozilla::gfx::SourceSurface;
24 using mozilla::gfx::SurfaceFormat;
25 using mozilla::ipc::Shmem;
27 nsDragServiceProxy::~nsDragServiceProxy() = default;
29 nsDragSessionProxy::~nsDragSessionProxy() = default;
31 already_AddRefed<nsIDragSession> nsDragServiceProxy::CreateDragSession() {
32 RefPtr<nsIDragSession> session = new nsDragSessionProxy();
33 return session.forget();
36 nsresult nsDragSessionProxy::InvokeDragSession(
37 nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal,
38 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings,
39 nsIArray* aTransferableArray, uint32_t aActionType,
40 nsContentPolicyType aContentPolicyType) {
41 BrowserChild* sourceBrowser = aWidget->GetOwningBrowserChild();
42 NS_ENSURE_TRUE(sourceBrowser, NS_ERROR_INVALID_ARG);
43 [[maybe_unused]] RefPtr<nsIDragSession> sourceSession =
44 sourceBrowser->GetDragSession();
45 MOZ_ASSERT(!sourceSession);
46 MOZ_ALWAYS_SUCCEEDS(
47 sourceBrowser->GetWeakReference(getter_AddRefs(mSourceBrowser)));
48 sourceBrowser->SetDragSession(this);
49 nsresult rv = nsBaseDragSession::InvokeDragSession(
50 aWidget, aDOMNode, aPrincipal, aCsp, aCookieJarSettings,
51 aTransferableArray, aActionType, aContentPolicyType);
52 return rv;
55 nsresult nsDragSessionProxy::InvokeDragSessionImpl(
56 nsIWidget* aWidget, nsIArray* aArrayTransferables,
57 const Maybe<CSSIntRegion>& aRegion, uint32_t aActionType) {
58 NS_ENSURE_STATE(mSourceDocument->GetDocShell());
59 BrowserChild* child = BrowserChild::GetFrom(mSourceDocument->GetDocShell());
60 NS_ENSURE_STATE(child);
61 nsTArray<mozilla::dom::IPCTransferableData> transferables;
62 nsContentUtils::TransferablesToIPCTransferableDatas(
63 aArrayTransferables, transferables, false, nullptr);
65 nsCOMPtr<nsIPrincipal> principal;
66 if (mSourceNode) {
67 principal = mSourceNode->NodePrincipal();
70 nsCOMPtr<nsIContentSecurityPolicy> csp;
71 if (mSourceDocument) {
72 csp = mSourceDocument->GetCsp();
73 // XXX why do we need this here? Shouldn't they be set properly in
74 // nsBaseDragService already?
75 mSourceWindowContext = mSourceDocument->GetWindowContext();
76 mSourceTopWindowContext = mSourceWindowContext
77 ? mSourceWindowContext->TopWindowContext()
78 : nullptr;
81 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
82 cookieJarSettings = mSourceDocument->CookieJarSettings();
83 mozilla::net::CookieJarSettingsArgs csArgs;
84 mozilla::net::CookieJarSettings::Cast(cookieJarSettings)->Serialize(csArgs);
86 LayoutDeviceIntRect dragRect;
87 if (mHasImage || mSelection) {
88 nsPresContext* pc;
89 RefPtr<SourceSurface> surface;
90 DrawDrag(mSourceNode, aRegion, mScreenPosition, &dragRect, &surface, &pc);
92 if (surface) {
93 RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
94 if (dataSurface) {
95 size_t length;
96 int32_t stride;
97 auto surfaceData =
98 nsContentUtils::GetSurfaceData(*dataSurface, &length, &stride);
99 if (surfaceData.isNothing()) {
100 NS_WARNING("Failed to create shared memory for drag session.");
101 return NS_ERROR_FAILURE;
104 mozilla::Unused << child->SendInvokeDragSession(
105 std::move(transferables), aActionType, std::move(surfaceData),
106 stride, dataSurface->GetFormat(), dragRect, principal, csp, csArgs,
107 mSourceWindowContext, mSourceTopWindowContext);
108 return NS_OK;
113 mozilla::Unused << child->SendInvokeDragSession(
114 std::move(transferables), aActionType, Nothing(), 0,
115 static_cast<SurfaceFormat>(0), dragRect, principal, csp, csArgs,
116 mSourceWindowContext, mSourceTopWindowContext);
117 return NS_OK;
120 nsIDragSession* nsDragServiceProxy::StartDragSession(
121 nsISupports* aWidgetProvider) {
122 nsIWidget* widget = GetWidgetFromWidgetProvider(aWidgetProvider);
123 NS_ENSURE_TRUE(widget, nullptr);
124 BrowserChild* targetBrowser = widget->GetOwningBrowserChild();
125 NS_ENSURE_TRUE(targetBrowser, nullptr);
126 RefPtr<nsIDragSession> session = targetBrowser->GetDragSession();
127 if (session) {
128 // session already exists on the browser
129 return session;
132 session = CreateDragSession();
133 MOZ_ASSERT(session);
134 static_cast<nsDragSessionProxy*>(session.get())->SetDragTarget(targetBrowser);
135 targetBrowser->SetDragSession(session);
136 return session;
139 NS_IMETHODIMP
140 nsDragServiceProxy::GetCurrentSession(nsISupports* aWidgetProvider,
141 nsIDragSession** aSession) {
142 if (!aSession) {
143 return NS_ERROR_INVALID_ARG;
145 *aSession = nullptr;
147 nsIWidget* widget = GetWidgetFromWidgetProvider(aWidgetProvider);
148 NS_ENSURE_TRUE(widget, NS_ERROR_INVALID_ARG);
149 BrowserChild* browser = widget->GetOwningBrowserChild();
150 NS_ENSURE_TRUE(browser, NS_ERROR_INVALID_ARG);
151 RefPtr<nsIDragSession> session = browser->GetDragSession();
153 if (!mSuppressLevel && session) {
154 session.forget(aSession);
157 return NS_OK;
160 void nsDragSessionProxy::SetDragTarget(BrowserChild* aTarget) {
161 if (!aTarget) {
162 if (mTargetBrowser) {
163 nsCOMPtr<BrowserChild> targetBC = do_QueryReferent(mTargetBrowser);
164 MOZ_ASSERT(targetBC);
165 if (targetBC) {
166 targetBC->SetDragSession(nullptr);
168 mTargetBrowser = nullptr;
170 return;
172 [[maybe_unused]] RefPtr<nsIDragSession> session = aTarget->GetDragSession();
173 MOZ_ASSERT(!session);
174 MOZ_ALWAYS_SUCCEEDS(
175 aTarget->GetWeakReference(getter_AddRefs(mTargetBrowser)));
178 nsresult nsDragSessionProxy::EndDragSessionImpl(bool aDoneDrag,
179 uint32_t aKeyModifiers) {
180 // End the drag session before removing it from its BrowserChild(s). This
181 // leaves the drag session in place while EndDragSessionImpl sends dragend.
182 nsresult rv = nsBaseDragSession::EndDragSessionImpl(aDoneDrag, aKeyModifiers);
184 if (mSourceBrowser) {
185 nsCOMPtr<BrowserChild> sourceBC = do_QueryReferent(mSourceBrowser);
186 MOZ_ASSERT(sourceBC);
187 [[maybe_unused]] RefPtr<nsIDragSession> session =
188 sourceBC->GetDragSession();
189 MOZ_ASSERT(session == this);
190 sourceBC->SetDragSession(nullptr);
191 mSourceBrowser = nullptr;
194 SetDragTarget(nullptr);
195 return rv;