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"
18 #include "nsITransferable.h"
19 #include "nsPrimitiveHelpers.h"
20 #include "nsViewManager.h"
23 NS_IMPL_ISUPPORTS_INHERITED0(nsDragService
, nsBaseDragService
)
25 using namespace mozilla
;
26 using namespace mozilla::widget
;
28 StaticRefPtr
<nsDragService
> sDragServiceInstance
;
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
) {
46 PresShell
* presShell
= aDocument
->GetPresShell();
51 RefPtr
<nsViewManager
> vm
= presShell
->GetViewManager();
56 nsCOMPtr
<nsIWidget
> widget
= vm
->GetRootWidget();
61 RefPtr
<nsWindow
> window
= nsWindow::From(widget
);
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
;
73 aTransferableArray
->GetLength(&count
);
75 return NS_ERROR_FAILURE
;
78 nsCOMPtr
<nsITransferable
> transferable
=
79 do_QueryElementAt(aTransferableArray
, 0);
83 nsresult rv
= nsClipboard::GetTextFromTransferable(transferable
, text
, html
);
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
);
101 return NS_ERROR_FAILURE
;
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
);
113 return NS_ERROR_FAILURE
;
116 for (const auto& flavor
: flavors
) {
117 nsCOMPtr
<nsISupports
> data
;
118 rv
= mTransferable
->GetTransferData(flavor
.get(), getter_AddRefs(data
));
122 rv
= aTransferable
->SetTransferData(flavor
.get(), data
);
123 if (NS_SUCCEEDED(rv
)) {
128 return NS_ERROR_FAILURE
;
132 nsDragService::GetNumDropItems(uint32_t* aNumItems
) {
142 nsDragService::IsDataFlavorSupported(const char* aDataFlavor
, bool* _retval
) {
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
);
157 for (const auto& flavor
: flavors
) {
158 if (dataFlavor
.Equals(flavor
)) {
168 nsDragService::EndDragSession(bool aDoneDrag
, uint32_t aKeyModifiers
) {
169 java::GeckoDragAndDrop::EndDragSession();
171 nsresult rv
= nsBaseDragService::EndDragSession(aDoneDrag
, aKeyModifiers
);
172 mTransferable
= nullptr;
177 nsDragService::UpdateDragImage(nsINode
* aImage
, int32_t aImageX
,
179 nsBaseDragService::UpdateDragImage(aImage
, aImageX
, aImageY
);
180 auto bitmap
= CreateDragImage(mSourceNode
, Nothing());
182 if (nsWindow
* window
= GetWindow(mSourceDocument
)) {
183 window
->UpdateDragImage(bitmap
);
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
;
200 DrawDrag(aNode
, aRegion
, mScreenPosition
, &dragRect
, &surface
, &pc
);
205 RefPtr
<DataSourceSurface
> destDataSurface
=
206 AndroidWidgetUtils::GetDataSourceSurfaceForAndroidBitmap(
207 surface
, &dragRect
, dragRect
.width
* 4);
208 if (!destDataSurface
) {
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
);
225 void nsDragService::SetData(nsITransferable
* aTransferable
) {
226 mTransferable
= aTransferable
;
227 // Reset DataTransfer
228 mDataTransfer
= nullptr;
232 void nsDragService::SetDropData(
233 mozilla::java::GeckoDragAndDrop::DropData::Param aDropData
) {
234 MOZ_ASSERT(NS_IsMainThread());
236 RefPtr
<nsDragService
> dragService
= nsDragService::GetInstance();
242 dragService
->SetData(nullptr);
246 nsCString
mime(aDropData
->MimeType()->ToCString());
248 if (mime
.EqualsLiteral("application/x-moz-draganddrop")) {
249 // The drop data isn't changed.
253 if (!mime
.EqualsLiteral("text/plain") && !mime
.EqualsLiteral("text/html")) {
254 // Not supported data.
255 dragService
->SetData(nullptr);
259 nsString
buffer(aDropData
->Text()->ToString());
260 nsCOMPtr
<nsISupports
> wrapper
;
261 nsPrimitiveHelpers::CreatePrimitiveForData(
262 mime
, buffer
.get(), buffer
.Length() * 2, getter_AddRefs(wrapper
));
264 dragService
->SetData(nullptr);
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
);