Bug 1883853 [wpt PR 44937] - [wdspec] fix test_set_permission_origin_unknown, a=testonly
[gecko.git] / widget / android / nsDragService.cpp
blob8f12ab65e32563dc97368589d1d7f789a2ad5f92
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsDragService.h"
8 #include "AndroidGraphics.h"
9 #include "AndroidWidgetUtils.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/java/GeckoDragAndDropWrappers.h"
12 #include "mozilla/PresShell.h"
13 #include "mozilla/ScopeExit.h"
14 #include "nsArrayUtils.h"
15 #include "nsClipboard.h"
16 #include "nsComponentManagerUtils.h"
17 #include "nsIArray.h"
18 #include "nsITransferable.h"
19 #include "nsPrimitiveHelpers.h"
20 #include "nsViewManager.h"
21 #include "nsWindow.h"
23 NS_IMPL_ISUPPORTS_INHERITED0(nsDragService, nsBaseDragService)
25 using namespace mozilla;
26 using namespace mozilla::widget;
28 StaticRefPtr<nsDragService> sDragServiceInstance;
30 /* static */
31 already_AddRefed<nsDragService> nsDragService::GetInstance() {
32 if (!sDragServiceInstance) {
33 sDragServiceInstance = new nsDragService();
34 ClearOnShutdown(&sDragServiceInstance);
37 RefPtr<nsDragService> service = sDragServiceInstance.get();
38 return service.forget();
41 static nsWindow* GetWindow(dom::Document* aDocument) {
42 if (!aDocument) {
43 return nullptr;
46 PresShell* presShell = aDocument->GetPresShell();
47 if (!presShell) {
48 return nullptr;
51 RefPtr<nsViewManager> vm = presShell->GetViewManager();
52 if (!vm) {
53 return nullptr;
56 nsCOMPtr<nsIWidget> widget = vm->GetRootWidget();
57 if (!widget) {
58 return nullptr;
61 RefPtr<nsWindow> window = nsWindow::From(widget);
62 return window.get();
65 nsresult nsDragService::InvokeDragSessionImpl(
66 nsIArray* aTransferableArray, const Maybe<CSSIntRegion>& aRegion,
67 uint32_t aActionType) {
68 if (jni::GetAPIVersion() < 24) {
69 return NS_ERROR_NOT_AVAILABLE;
72 uint32_t count = 0;
73 aTransferableArray->GetLength(&count);
74 if (count != 1) {
75 return NS_ERROR_FAILURE;
78 nsCOMPtr<nsITransferable> transferable =
79 do_QueryElementAt(aTransferableArray, 0);
81 nsAutoString html;
82 nsAutoString text;
83 nsresult rv = nsClipboard::GetTextFromTransferable(transferable, text, html);
84 if (NS_FAILED(rv)) {
85 return rv;
87 java::GeckoDragAndDrop::SetDragData(text, html);
89 if (nsWindow* window = GetWindow(mSourceDocument)) {
90 mTransferable = transferable;
92 nsBaseDragService::StartDragSession();
93 nsBaseDragService::OpenDragPopup();
95 auto bitmap = CreateDragImage(mSourceNode, aRegion);
96 window->StartDragAndDrop(bitmap);
98 return NS_OK;
101 return NS_ERROR_FAILURE;
104 NS_IMETHODIMP
105 nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItem) {
106 if (!aTransferable) {
107 return NS_ERROR_INVALID_ARG;
110 nsTArray<nsCString> flavors;
111 nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
112 if (NS_FAILED(rv)) {
113 return NS_ERROR_FAILURE;
116 for (const auto& flavor : flavors) {
117 nsCOMPtr<nsISupports> data;
118 rv = mTransferable->GetTransferData(flavor.get(), getter_AddRefs(data));
119 if (NS_FAILED(rv)) {
120 continue;
122 rv = aTransferable->SetTransferData(flavor.get(), data);
123 if (NS_SUCCEEDED(rv)) {
124 return rv;
128 return NS_ERROR_FAILURE;
131 NS_IMETHODIMP
132 nsDragService::GetNumDropItems(uint32_t* aNumItems) {
133 if (mTransferable) {
134 *aNumItems = 1;
135 return NS_OK;
137 *aNumItems = 0;
138 return NS_OK;
141 NS_IMETHODIMP
142 nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
143 *_retval = false;
145 nsDependentCString dataFlavor(aDataFlavor);
146 auto logging = MakeScopeExit([&] {
147 MOZ_DRAGSERVICE_LOG("IsDataFlavorSupported: %s is%s found", aDataFlavor,
148 *_retval ? "" : " not");
151 nsTArray<nsCString> flavors;
152 nsresult rv = mTransferable->FlavorsTransferableCanImport(flavors);
153 if (NS_FAILED(rv)) {
154 return NS_OK;
157 for (const auto& flavor : flavors) {
158 if (dataFlavor.Equals(flavor)) {
159 *_retval = true;
160 return NS_OK;
164 return NS_OK;
167 NS_IMETHODIMP
168 nsDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
169 java::GeckoDragAndDrop::EndDragSession();
171 nsresult rv = nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
172 mTransferable = nullptr;
173 return rv;
176 NS_IMETHODIMP
177 nsDragService::UpdateDragImage(nsINode* aImage, int32_t aImageX,
178 int32_t aImageY) {
179 nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY);
180 auto bitmap = CreateDragImage(mSourceNode, Nothing());
182 if (nsWindow* window = GetWindow(mSourceDocument)) {
183 window->UpdateDragImage(bitmap);
186 return NS_OK;
189 bool nsDragService::MustUpdateDataTransfer(EventMessage aMessage) {
190 // Android's drag and drop API sets drop item in drop event.
191 // So we have to invalidate data transfer cache on drop event.
192 return aMessage == eDrop;
195 java::sdk::Bitmap::LocalRef nsDragService::CreateDragImage(
196 nsINode* aNode, const Maybe<CSSIntRegion>& aRegion) {
197 LayoutDeviceIntRect dragRect;
198 RefPtr<SourceSurface> surface;
199 nsPresContext* pc;
200 DrawDrag(aNode, aRegion, mScreenPosition, &dragRect, &surface, &pc);
201 if (!surface) {
202 return nullptr;
205 RefPtr<DataSourceSurface> destDataSurface =
206 AndroidWidgetUtils::GetDataSourceSurfaceForAndroidBitmap(
207 surface, &dragRect, dragRect.width * 4);
208 if (!destDataSurface) {
209 return nullptr;
212 DataSourceSurface::ScopedMap destMap(destDataSurface,
213 DataSourceSurface::READ);
215 java::sdk::Bitmap::LocalRef bitmap;
216 auto pixels = mozilla::jni::ByteBuffer::New(
217 reinterpret_cast<int8_t*>(destMap.GetData()),
218 destMap.GetStride() * destDataSurface->GetSize().height);
219 bitmap = java::sdk::Bitmap::CreateBitmap(
220 dragRect.width, dragRect.height, java::sdk::Bitmap::Config::ARGB_8888());
221 bitmap->CopyPixelsFromBuffer(pixels);
222 return bitmap;
225 void nsDragService::SetData(nsITransferable* aTransferable) {
226 mTransferable = aTransferable;
227 // Reset DataTransfer
228 mDataTransfer = nullptr;
231 // static
232 void nsDragService::SetDropData(
233 mozilla::java::GeckoDragAndDrop::DropData::Param aDropData) {
234 MOZ_ASSERT(NS_IsMainThread());
236 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
237 if (!dragService) {
238 return;
241 if (!aDropData) {
242 dragService->SetData(nullptr);
243 return;
246 nsCString mime(aDropData->MimeType()->ToCString());
248 if (mime.EqualsLiteral("application/x-moz-draganddrop")) {
249 // The drop data isn't changed.
250 return;
253 if (!mime.EqualsLiteral("text/plain") && !mime.EqualsLiteral("text/html")) {
254 // Not supported data.
255 dragService->SetData(nullptr);
256 return;
259 nsString buffer(aDropData->Text()->ToString());
260 nsCOMPtr<nsISupports> wrapper;
261 nsPrimitiveHelpers::CreatePrimitiveForData(
262 mime, buffer.get(), buffer.Length() * 2, getter_AddRefs(wrapper));
263 if (!wrapper) {
264 dragService->SetData(nullptr);
265 return;
267 nsCOMPtr<nsITransferable> transferable =
268 do_CreateInstance("@mozilla.org/widget/transferable;1");
269 transferable->Init(nullptr);
270 transferable->SetTransferData(mime.get(), wrapper);
271 dragService->SetData(transferable);