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 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 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 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 88 STDMETHODIMP_(ULONG) WCEnumFormatEtc::AddRef(void) 89 { 90 return InterlockedIncrement(&m_ref); 91 } 92 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 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 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 132 STDMETHODIMP WCEnumFormatEtc::Reset(void) 133 { 134 m_current = 0; 135 return S_OK; 136 } 137 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 157 HRESULT WCDataObject::createInstance(WCDataObject** result) 158 { 159 if (!result) 160 return E_POINTER; 161 *result = new WCDataObject(); 162 return S_OK; 163 } 164 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 176 WCDataObject::WCDataObject() 177 : m_ref(1) 178 { 179 } 180 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 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 204 STDMETHODIMP_(ULONG) WCDataObject::AddRef( void) 205 { 206 return InterlockedIncrement(&m_ref); 207 } 208 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 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 235 STDMETHODIMP WCDataObject::GetDataHere(FORMATETC*, STGMEDIUM*) 236 { 237 return E_NOTIMPL; 238 } 239 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 261 STDMETHODIMP WCDataObject::GetCanonicalFormatEtc(FORMATETC*, FORMATETC*) 262 { 263 return DATA_S_SAMEFORMATETC; 264 } 265 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 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 } 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 359 STDMETHODIMP WCDataObject::DAdvise(FORMATETC*, DWORD, IAdviseSink*,DWORD*) 360 { 361 return OLE_E_ADVISENOTSUPPORTED; 362 } 363 364 STDMETHODIMP WCDataObject::DUnadvise(DWORD) 365 { 366 return E_NOTIMPL; 367 } 368 369 HRESULT STDMETHODCALLTYPE WCDataObject::EnumDAdvise(IEnumSTATDATA**) 370 { 371 return OLE_E_ADVISENOTSUPPORTED; 372 } 373 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