Add WTF::move()
[WebKit-https.git] / Tools / DumpRenderTree / win / DRTDataObject.cpp
1 /*
2  * Copyright (C) 2007, 2014 Apple Inc.  All rights reserved.
3  * Copyright (C) 2012 Baidu Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "DRTDataObject.h"
29
30 FORMATETC* cfHDropFormat()
31 {
32     static FORMATETC urlFormat = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
33     return &urlFormat;
34 }
35
36 FORMATETC* cfFileNameWFormat()
37 {
38     static UINT cf = RegisterClipboardFormat(L"FileNameW");
39     static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
40     return &urlFormat;
41 }
42
43 FORMATETC* cfUrlWFormat()
44 {
45     static UINT cf = RegisterClipboardFormat(L"UniformResourceLocatorW");
46     static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
47     return &urlFormat;
48 }
49
50 class WCEnumFormatEtc : public IEnumFORMATETC {
51 public:
52     explicit WCEnumFormatEtc(const Vector<FORMATETC>& formats);
53     explicit WCEnumFormatEtc(const Vector<std::unique_ptr<FORMATETC>>& formats);
54
55     // IUnknown members
56     STDMETHOD(QueryInterface)(REFIID, void**);
57     STDMETHOD_(ULONG, AddRef)();
58     STDMETHOD_(ULONG, Release)();
59
60     // IEnumFORMATETC members
61     STDMETHOD(Next)(ULONG, LPFORMATETC, ULONG*);
62     STDMETHOD(Skip)(ULONG);
63     STDMETHOD(Reset)();
64     STDMETHOD(Clone)(IEnumFORMATETC**);
65
66 private:
67     long m_ref;
68     Vector<FORMATETC> m_formats;
69     size_t m_current;
70 };
71
72 WCEnumFormatEtc::WCEnumFormatEtc(const Vector<FORMATETC>& formats)
73     : m_ref(1)
74     , m_current(0)
75     , m_formats(formats)
76 {
77 }
78
79 WCEnumFormatEtc::WCEnumFormatEtc(const Vector<std::unique_ptr<FORMATETC>>& formats)
80     : m_ref(1)
81     , m_current(0)
82 {
83     for (auto& format : formats)
84         m_formats.append(*format);
85 }
86
87 STDMETHODIMP WCEnumFormatEtc::QueryInterface(REFIID riid, void** ppvObject)
88 {
89     *ppvObject = 0;
90     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEnumFORMATETC)) {
91         *ppvObject = this;
92         AddRef();
93         return S_OK;
94     }
95
96     return E_NOINTERFACE;
97 }
98
99 STDMETHODIMP_(ULONG) WCEnumFormatEtc::AddRef()
100 {
101     return InterlockedIncrement(&m_ref);
102 }
103
104 STDMETHODIMP_(ULONG) WCEnumFormatEtc::Release()
105 {
106     long refCount = InterlockedDecrement(&m_ref);
107     if (!refCount)
108         delete this;
109     return refCount;
110 }
111
112 STDMETHODIMP WCEnumFormatEtc::Next(ULONG celt, LPFORMATETC lpFormatEtc, ULONG* pceltFetched)
113 {
114     if (pceltFetched)
115         *pceltFetched = 0;
116
117     ULONG cReturn = celt;
118
119     if (celt <= 0 || !lpFormatEtc || m_current >= m_formats.size())
120         return S_FALSE;
121
122     if (!pceltFetched && celt != 1) // pceltFetched can be 0 only for 1 item request
123         return S_FALSE;
124
125     while (m_current < m_formats.size() && cReturn > 0) {
126         *lpFormatEtc++ = m_formats[m_current++];
127         --cReturn;
128     }
129     if (pceltFetched)
130         *pceltFetched = celt - cReturn;
131
132     return !cReturn ? S_OK : S_FALSE;
133 }
134
135 STDMETHODIMP WCEnumFormatEtc::Skip(ULONG celt)
136 {
137     if ((m_current + celt) >= m_formats.size())
138         return S_FALSE;
139     m_current += celt;
140     return S_OK;
141 }
142
143 STDMETHODIMP WCEnumFormatEtc::Reset()
144 {
145     m_current = 0;
146     return S_OK;
147 }
148
149 STDMETHODIMP WCEnumFormatEtc::Clone(IEnumFORMATETC** ppCloneEnumFormatEtc)
150 {
151     if (!ppCloneEnumFormatEtc)
152         return E_POINTER;
153
154     WCEnumFormatEtc* newEnum = new WCEnumFormatEtc(m_formats);
155     if (!newEnum)
156         return E_OUTOFMEMORY;
157
158     newEnum->AddRef();
159     newEnum->m_current = m_current;
160     *ppCloneEnumFormatEtc = newEnum;
161     return S_OK;
162 }
163
164 //////////////////////////////////////////////////////////////////////////
165 HRESULT DRTDataObject::createInstance(DRTDataObject** result)
166 {
167     if (!result)
168         return E_POINTER;
169     *result = new DRTDataObject();
170     return S_OK;
171 }
172
173 DRTDataObject::DRTDataObject()
174     : m_ref(1)
175 {
176 }
177
178 STDMETHODIMP DRTDataObject::QueryInterface(REFIID riid, void** ppvObject)
179 {
180     *ppvObject = 0;
181     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDataObject))
182         *ppvObject = this;
183
184     if (*ppvObject) {
185         AddRef();
186         return S_OK;
187     }
188     return E_NOINTERFACE;
189 }
190
191 STDMETHODIMP_(ULONG) DRTDataObject::AddRef()
192 {
193     return InterlockedIncrement(&m_ref);
194 }
195
196 STDMETHODIMP_(ULONG) DRTDataObject::Release()
197 {
198     long refCount = InterlockedDecrement(&m_ref);
199     if (!refCount)
200         delete this;
201     return refCount;
202 }
203
204 STDMETHODIMP DRTDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
205
206     if (!pformatetcIn || !pmedium)
207         return E_POINTER;
208     pmedium->hGlobal = 0;
209
210     for (size_t i = 0; i < m_formats.size(); ++i) {
211         if (pformatetcIn->lindex == m_formats[i]->lindex && pformatetcIn->dwAspect == m_formats[i]->dwAspect && pformatetcIn->cfFormat == m_formats[i]->cfFormat) {
212             CopyMedium(pmedium, m_medium[i].get(), m_formats[i].get());
213             return S_OK;
214         }
215     }
216     return DV_E_FORMATETC;
217 }
218
219 STDMETHODIMP DRTDataObject::GetDataHere(FORMATETC*, STGMEDIUM*)
220
221     return E_NOTIMPL;
222 }
223
224 STDMETHODIMP DRTDataObject::QueryGetData(FORMATETC* pformatetc)
225
226     if (!pformatetc)
227         return E_POINTER;
228
229     if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
230         return (DV_E_DVASPECT);
231
232     for (auto& format : m_formats) {
233         if (pformatetc->tymed & format->tymed) {
234             if (pformatetc->cfFormat == format->cfFormat)
235                 return S_OK;
236         }
237     }
238     return DV_E_TYMED;
239 }
240
241 STDMETHODIMP DRTDataObject::GetCanonicalFormatEtc(FORMATETC*, FORMATETC*)
242
243     return DATA_S_SAMEFORMATETC;
244 }
245
246 STDMETHODIMP DRTDataObject::SetData(FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
247
248     if (!pformatetc || !pmedium)
249         return E_POINTER;
250
251     auto formatetc = std::make_unique<FORMATETC>();
252     std::unique_ptr<STGMEDIUM, StgMediumDeleter> pStgMed(new STGMEDIUM);
253
254     ZeroMemory(formatetc.get(), sizeof(FORMATETC));
255     ZeroMemory(pStgMed.get(), sizeof(STGMEDIUM));
256
257     *formatetc = *pformatetc;
258     m_formats.append(WTF::move(formatetc));
259
260     if (fRelease)
261         *pStgMed = *pmedium;
262     else
263         CopyMedium(pStgMed.get(), pmedium, pformatetc);
264     m_medium.append(WTF::move(pStgMed));
265
266     return S_OK;
267 }
268
269 void DRTDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
270 {
271     switch (pMedSrc->tymed) {
272 #if !OS(WINCE)
273     case TYMED_HGLOBAL:
274         pMedDest->hGlobal = static_cast<HGLOBAL>(OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0));
275         break;
276     case TYMED_GDI:
277         pMedDest->hBitmap = static_cast<HBITMAP>(OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, 0));
278         break;
279     case TYMED_MFPICT:
280         pMedDest->hMetaFilePict = static_cast<HMETAFILEPICT>(OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0));
281         break;
282     case TYMED_ENHMF:
283         pMedDest->hEnhMetaFile = static_cast<HENHMETAFILE>(OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0));
284         break;
285     case TYMED_FILE:
286         pMedSrc->lpszFileName = static_cast<LPOLESTR>(OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0));
287         break;
288 #endif
289     case TYMED_ISTREAM:
290         pMedDest->pstm = pMedSrc->pstm;
291         pMedSrc->pstm->AddRef();
292         break;
293     case TYMED_ISTORAGE:
294         pMedDest->pstg = pMedSrc->pstg;
295         pMedSrc->pstg->AddRef();
296         break;
297     default:
298         break;
299     }
300     pMedDest->tymed = pMedSrc->tymed;
301     pMedDest->pUnkForRelease = 0;
302     if (pMedSrc->pUnkForRelease) {
303         pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
304         pMedSrc->pUnkForRelease->AddRef();
305     }
306 }
307 STDMETHODIMP DRTDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
308
309     if (!ppenumFormatEtc)
310         return E_POINTER;
311
312     *ppenumFormatEtc = 0;
313     switch (dwDirection) {
314     case DATADIR_GET:
315         *ppenumFormatEtc = new WCEnumFormatEtc(m_formats);
316         if (!(*ppenumFormatEtc))
317             return E_OUTOFMEMORY;
318         break;
319
320     case DATADIR_SET:
321     default:
322         return E_NOTIMPL;
323         break;
324     }
325
326     return S_OK;
327 }
328
329 STDMETHODIMP DRTDataObject::DAdvise(FORMATETC*, DWORD, IAdviseSink*, DWORD*)
330
331     return OLE_E_ADVISENOTSUPPORTED;
332 }
333
334 STDMETHODIMP DRTDataObject::DUnadvise(DWORD)
335 {
336     return E_NOTIMPL;
337 }
338
339 HRESULT STDMETHODCALLTYPE DRTDataObject::EnumDAdvise(IEnumSTATDATA**)
340 {
341     return OLE_E_ADVISENOTSUPPORTED;
342 }
343
344 void DRTDataObject::clearData(CLIPFORMAT format)
345 {
346     size_t position = 0;
347     while (position < m_formats.size()) {
348         if (m_formats[position]->cfFormat == format) {
349             m_formats[position] = m_formats.takeLast();
350             m_medium[position] = m_medium.takeLast();
351             continue;
352         }
353         position++;
354     }
355 }