• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 COMPUTER, 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 COMPUTER, 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 "PlatformString.h"
32 
33 namespace WebCore {
34 
35 class WCEnumFormatEtc : public IEnumFORMATETC
36 {
37 public:
38     WCEnumFormatEtc(const Vector<FORMATETC>& formats);
39     WCEnumFormatEtc(const Vector<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 
59 
WCEnumFormatEtc(const Vector<FORMATETC> & formats)60 WCEnumFormatEtc::WCEnumFormatEtc(const Vector<FORMATETC>& formats)
61 : m_ref(1)
62 , m_current(0)
63 {
64     for(size_t i = 0; i < formats.size(); ++i)
65         m_formats.append(formats[i]);
66 }
67 
WCEnumFormatEtc(const Vector<FORMATETC * > & formats)68 WCEnumFormatEtc::WCEnumFormatEtc(const Vector<FORMATETC*>& formats)
69 : m_ref(1)
70 , m_current(0)
71 {
72     for(size_t i = 0; i < formats.size(); ++i)
73         m_formats.append(*formats[i]);
74 }
75 
QueryInterface(REFIID riid,void ** ppvObject)76 STDMETHODIMP  WCEnumFormatEtc::QueryInterface(REFIID riid, void** ppvObject)
77 {
78     *ppvObject = 0;
79     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEnumFORMATETC)) {
80         *ppvObject = this;
81         AddRef();
82         return S_OK;
83     }
84 
85     return E_NOINTERFACE;
86 }
87 
STDMETHODIMP_(ULONG)88 STDMETHODIMP_(ULONG) WCEnumFormatEtc::AddRef(void)
89 {
90     return InterlockedIncrement(&m_ref);
91 }
92 
STDMETHODIMP_(ULONG)93 STDMETHODIMP_(ULONG) WCEnumFormatEtc::Release(void)
94 {
95     long c = InterlockedDecrement(&m_ref);
96     if (c == 0)
97         delete this;
98     return c;
99 }
100 
Next(ULONG celt,LPFORMATETC lpFormatEtc,ULONG * pceltFetched)101 STDMETHODIMP WCEnumFormatEtc::Next(ULONG celt, LPFORMATETC lpFormatEtc, ULONG* pceltFetched)
102 {
103     if(pceltFetched != 0)
104         *pceltFetched=0;
105 
106     ULONG cReturn = celt;
107 
108     if(celt <= 0 || lpFormatEtc == 0 || m_current >= m_formats.size())
109         return S_FALSE;
110 
111     if(pceltFetched == 0 && celt != 1) // pceltFetched can be 0 only for 1 item request
112         return S_FALSE;
113 
114     while (m_current < m_formats.size() && cReturn > 0) {
115         *lpFormatEtc++ = m_formats[m_current++];
116         --cReturn;
117     }
118     if (pceltFetched != 0)
119         *pceltFetched = celt - cReturn;
120 
121     return (cReturn == 0) ? S_OK : S_FALSE;
122 }
123 
Skip(ULONG celt)124 STDMETHODIMP WCEnumFormatEtc::Skip(ULONG celt)
125 {
126     if((m_current + int(celt)) >= m_formats.size())
127         return S_FALSE;
128     m_current += celt;
129     return S_OK;
130 }
131 
Reset(void)132 STDMETHODIMP WCEnumFormatEtc::Reset(void)
133 {
134     m_current = 0;
135     return S_OK;
136 }
137 
Clone(IEnumFORMATETC ** ppCloneEnumFormatEtc)138 STDMETHODIMP WCEnumFormatEtc::Clone(IEnumFORMATETC** ppCloneEnumFormatEtc)
139 {
140     if(!ppCloneEnumFormatEtc)
141         return E_POINTER;
142 
143     WCEnumFormatEtc *newEnum = new WCEnumFormatEtc(m_formats);
144     if(!newEnum)
145         return E_OUTOFMEMORY;
146 
147     newEnum->AddRef();
148     newEnum->m_current = m_current;
149     *ppCloneEnumFormatEtc = newEnum;
150     return S_OK;
151 }
152 
153 
154 
155 //////////////////////////////////////////////////////////////////////////
156 
createInstance(WCDataObject ** result)157 HRESULT WCDataObject::createInstance(WCDataObject** result)
158 {
159     if (!result)
160         return E_POINTER;
161     *result = new WCDataObject();
162     return S_OK;
163 }
164 
createInstance(WCDataObject ** result,const DragDataMap & dataMap)165 HRESULT WCDataObject::createInstance(WCDataObject** result, const DragDataMap& dataMap)
166 {
167     if (!result)
168         return E_POINTER;
169     *result = new WCDataObject;
170 
171     for (DragDataMap::const_iterator it = dataMap.begin(); it != dataMap.end(); ++it)
172         setClipboardData(*result, it->first, it->second);
173     return S_OK;
174 }
175 
WCDataObject()176 WCDataObject::WCDataObject()
177 : m_ref(1)
178 {
179 }
180 
~WCDataObject()181 WCDataObject::~WCDataObject()
182 {
183     for(size_t i = 0; i < m_medium.size(); ++i) {
184         ReleaseStgMedium(m_medium[i]);
185         delete m_medium[i];
186     }
187     WTF::deleteAllValues(m_formats);
188 }
189 
QueryInterface(REFIID riid,void ** ppvObject)190 STDMETHODIMP WCDataObject::QueryInterface(REFIID riid,void** ppvObject)
191 {
192     *ppvObject = 0;
193     if (IsEqualIID(riid, IID_IUnknown) ||
194         IsEqualIID(riid, IID_IDataObject)) {
195         *ppvObject=this;
196     }
197     if (*ppvObject) {
198         AddRef();
199         return S_OK;
200     }
201     return E_NOINTERFACE;
202 }
203 
STDMETHODIMP_(ULONG)204 STDMETHODIMP_(ULONG) WCDataObject::AddRef( void)
205 {
206     return InterlockedIncrement(&m_ref);
207 }
208 
STDMETHODIMP_(ULONG)209 STDMETHODIMP_(ULONG) WCDataObject::Release( void)
210 {
211     long c = InterlockedDecrement(&m_ref);
212     if (c == 0)
213         delete this;
214     return c;
215 }
216 
GetData(FORMATETC * pformatetcIn,STGMEDIUM * pmedium)217 STDMETHODIMP WCDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
218 {
219     if(!pformatetcIn || !pmedium)
220         return E_POINTER;
221     pmedium->hGlobal = 0;
222 
223     for(size_t i=0; i < m_formats.size(); ++i) {
224         if(/*pformatetcIn->tymed & m_formats[i]->tymed &&*/     // tymed can be 0 (TYMED_NULL) - but it can have a medium that contains an pUnkForRelease
225             pformatetcIn->lindex == m_formats[i]->lindex &&
226             pformatetcIn->dwAspect == m_formats[i]->dwAspect &&
227             pformatetcIn->cfFormat == m_formats[i]->cfFormat) {
228             CopyMedium(pmedium, m_medium[i], m_formats[i]);
229             return S_OK;
230         }
231     }
232     return DV_E_FORMATETC;
233 }
234 
GetDataHere(FORMATETC *,STGMEDIUM *)235 STDMETHODIMP WCDataObject::GetDataHere(FORMATETC*, STGMEDIUM*)
236 {
237     return E_NOTIMPL;
238 }
239 
QueryGetData(FORMATETC * pformatetc)240 STDMETHODIMP WCDataObject::QueryGetData(FORMATETC* pformatetc)
241 {
242     if(!pformatetc)
243         return E_POINTER;
244 
245     if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
246         return (DV_E_DVASPECT);
247     HRESULT  hr = DV_E_TYMED;
248     for(size_t i = 0; i < m_formats.size(); ++i) {
249         if(pformatetc->tymed & m_formats[i]->tymed) {
250             if(pformatetc->cfFormat == m_formats[i]->cfFormat)
251                 return S_OK;
252             else
253                 hr = DV_E_CLIPFORMAT;
254         }
255         else
256             hr = DV_E_TYMED;
257     }
258     return hr;
259 }
260 
GetCanonicalFormatEtc(FORMATETC *,FORMATETC *)261 STDMETHODIMP WCDataObject::GetCanonicalFormatEtc(FORMATETC*, FORMATETC*)
262 {
263     return DATA_S_SAMEFORMATETC;
264 }
265 
SetData(FORMATETC * pformatetc,STGMEDIUM * pmedium,BOOL fRelease)266 STDMETHODIMP WCDataObject::SetData(FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
267 {
268     if(!pformatetc || !pmedium)
269         return E_POINTER;
270 
271     FORMATETC* fetc=new FORMATETC;
272     if (!fetc)
273         return E_OUTOFMEMORY;
274 
275     STGMEDIUM* pStgMed = new STGMEDIUM;
276 
277     if(!pStgMed) {
278         delete fetc;
279         return E_OUTOFMEMORY;
280     }
281 
282     ZeroMemory(fetc,sizeof(FORMATETC));
283     ZeroMemory(pStgMed,sizeof(STGMEDIUM));
284 
285     *fetc = *pformatetc;
286     m_formats.append(fetc);
287 
288     if(fRelease)
289         *pStgMed = *pmedium;
290     else
291         CopyMedium(pStgMed, pmedium, pformatetc);
292     m_medium.append(pStgMed);
293 
294     return S_OK;
295 }
296 
CopyMedium(STGMEDIUM * pMedDest,STGMEDIUM * pMedSrc,FORMATETC * pFmtSrc)297 void WCDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
298 {
299     switch(pMedSrc->tymed)
300     {
301 #if !OS(WINCE)
302     case TYMED_HGLOBAL:
303         pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, 0);
304         break;
305     case TYMED_GDI:
306         pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, 0);
307         break;
308     case TYMED_MFPICT:
309         pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, 0);
310         break;
311     case TYMED_ENHMF:
312         pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, 0);
313         break;
314     case TYMED_FILE:
315         pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, 0);
316         break;
317 #endif
318     case TYMED_ISTREAM:
319         pMedDest->pstm = pMedSrc->pstm;
320         pMedSrc->pstm->AddRef();
321         break;
322     case TYMED_ISTORAGE:
323         pMedDest->pstg = pMedSrc->pstg;
324         pMedSrc->pstg->AddRef();
325         break;
326     default:
327         break;
328     }
329     pMedDest->tymed = pMedSrc->tymed;
330     pMedDest->pUnkForRelease = 0;
331     if(pMedSrc->pUnkForRelease != 0) {
332         pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
333         pMedSrc->pUnkForRelease->AddRef();
334     }
335 }
EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC ** ppenumFormatEtc)336 STDMETHODIMP WCDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
337 {
338     if(!ppenumFormatEtc)
339         return E_POINTER;
340 
341     *ppenumFormatEtc=0;
342     switch (dwDirection)
343     {
344     case DATADIR_GET:
345         *ppenumFormatEtc= new WCEnumFormatEtc(m_formats);
346         if(!(*ppenumFormatEtc))
347             return E_OUTOFMEMORY;
348         break;
349 
350     case DATADIR_SET:
351     default:
352         return E_NOTIMPL;
353         break;
354     }
355 
356     return S_OK;
357 }
358 
DAdvise(FORMATETC *,DWORD,IAdviseSink *,DWORD *)359 STDMETHODIMP WCDataObject::DAdvise(FORMATETC*, DWORD, IAdviseSink*,DWORD*)
360 {
361     return OLE_E_ADVISENOTSUPPORTED;
362 }
363 
DUnadvise(DWORD)364 STDMETHODIMP WCDataObject::DUnadvise(DWORD)
365 {
366     return E_NOTIMPL;
367 }
368 
EnumDAdvise(IEnumSTATDATA **)369 HRESULT STDMETHODCALLTYPE WCDataObject::EnumDAdvise(IEnumSTATDATA**)
370 {
371     return OLE_E_ADVISENOTSUPPORTED;
372 }
373 
clearData(CLIPFORMAT format)374 void WCDataObject::clearData(CLIPFORMAT format)
375 {
376     size_t ptr = 0;
377     while (ptr < m_formats.size()) {
378         if (m_formats[ptr]->cfFormat == format) {
379             FORMATETC* current = m_formats[ptr];
380             m_formats[ptr] = m_formats[m_formats.size() - 1];
381             m_formats[m_formats.size() - 1] = 0;
382             m_formats.removeLast();
383             delete current;
384             STGMEDIUM* medium = m_medium[ptr];
385             m_medium[ptr] = m_medium[m_medium.size() - 1];
386             m_medium[m_medium.size() - 1] = 0;
387             m_medium.removeLast();
388             ReleaseStgMedium(medium);
389             delete medium;
390             continue;
391         }
392         ptr++;
393     }
394 }
395 
396 }
397