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 33namespace WebCore { 34 35class WCEnumFormatEtc : public IEnumFORMATETC 36{ 37public: 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 52private: 53 long m_ref; 54 Vector<FORMATETC> m_formats; 55 size_t m_current; 56}; 57 58WCEnumFormatEtc::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 66WCEnumFormatEtc::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 74STDMETHODIMP 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 86STDMETHODIMP_(ULONG) WCEnumFormatEtc::AddRef(void) 87{ 88 return InterlockedIncrement(&m_ref); 89} 90 91STDMETHODIMP_(ULONG) WCEnumFormatEtc::Release(void) 92{ 93 long c = InterlockedDecrement(&m_ref); 94 if (c == 0) 95 delete this; 96 return c; 97} 98 99STDMETHODIMP 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 122STDMETHODIMP 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 130STDMETHODIMP WCEnumFormatEtc::Reset(void) 131{ 132 m_current = 0; 133 return S_OK; 134} 135 136STDMETHODIMP 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 155HRESULT WCDataObject::createInstance(WCDataObject** result) 156{ 157 if (!result) 158 return E_POINTER; 159 *result = new WCDataObject(); 160 return S_OK; 161} 162 163HRESULT 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 174WCDataObject::WCDataObject() 175: m_ref(1) 176{ 177} 178 179STDMETHODIMP 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 193STDMETHODIMP_(ULONG) WCDataObject::AddRef( void) 194{ 195 return InterlockedIncrement(&m_ref); 196} 197 198STDMETHODIMP_(ULONG) WCDataObject::Release( void) 199{ 200 long c = InterlockedDecrement(&m_ref); 201 if (c == 0) 202 delete this; 203 return c; 204} 205 206STDMETHODIMP 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 224STDMETHODIMP WCDataObject::GetDataHere(FORMATETC*, STGMEDIUM*) 225{ 226 return E_NOTIMPL; 227} 228 229STDMETHODIMP 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 250STDMETHODIMP WCDataObject::GetCanonicalFormatEtc(FORMATETC*, FORMATETC*) 251{ 252 return DATA_S_SAMEFORMATETC; 253} 254 255STDMETHODIMP 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 278void WCDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc) 279{ 280 switch(pMedSrc->tymed) 281 { 282#if !OS(WINCE) 283 case TYMED_HGLOBAL: 284 pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, 0); 285 break; 286 case TYMED_GDI: 287 pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, 0); 288 break; 289 case TYMED_MFPICT: 290 pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, 0); 291 break; 292 case TYMED_ENHMF: 293 pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, 0); 294 break; 295 case TYMED_FILE: 296 pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, 0); 297 break; 298#endif 299 case TYMED_ISTREAM: 300 pMedDest->pstm = pMedSrc->pstm; 301 pMedSrc->pstm->AddRef(); 302 break; 303 case TYMED_ISTORAGE: 304 pMedDest->pstg = pMedSrc->pstg; 305 pMedSrc->pstg->AddRef(); 306 break; 307 default: 308 break; 309 } 310 pMedDest->tymed = pMedSrc->tymed; 311 pMedDest->pUnkForRelease = 0; 312 if(pMedSrc->pUnkForRelease != 0) { 313 pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease; 314 pMedSrc->pUnkForRelease->AddRef(); 315 } 316} 317STDMETHODIMP WCDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc) 318{ 319 if(!ppenumFormatEtc) 320 return E_POINTER; 321 322 *ppenumFormatEtc=0; 323 switch (dwDirection) 324 { 325 case DATADIR_GET: 326 *ppenumFormatEtc= new WCEnumFormatEtc(m_formats); 327 if(!(*ppenumFormatEtc)) 328 return E_OUTOFMEMORY; 329 break; 330 331 case DATADIR_SET: 332 default: 333 return E_NOTIMPL; 334 break; 335 } 336 337 return S_OK; 338} 339 340STDMETHODIMP WCDataObject::DAdvise(FORMATETC*, DWORD, IAdviseSink*,DWORD*) 341{ 342 return OLE_E_ADVISENOTSUPPORTED; 343} 344 345STDMETHODIMP WCDataObject::DUnadvise(DWORD) 346{ 347 return E_NOTIMPL; 348} 349 350HRESULT STDMETHODCALLTYPE WCDataObject::EnumDAdvise(IEnumSTATDATA**) 351{ 352 return OLE_E_ADVISENOTSUPPORTED; 353} 354 355void WCDataObject::clearData(CLIPFORMAT format) 356{ 357 size_t ptr = 0; 358 while (ptr < m_formats.size()) { 359 if (m_formats[ptr]->cfFormat == format) { 360 m_formats[ptr] = m_formats.takeLast(); 361 m_medium[ptr] = m_medium.takeLast(); 362 continue; 363 } 364 ptr++; 365 } 366} 367 368} 369