Home | History | Annotate | Download | only in win
      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