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