|         |      1 /* | 
|         |      2  * Copyright (C) 2006, 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 "WebKitDLL.h" | 
|         |     28 #include "WebNotificationCenter.h" | 
|         |     29  | 
|         |     30 #include "WebNotification.h" | 
|         |     31 #pragma warning( push, 0 ) | 
|         |     32 #include <WebCore/StringImpl.h> | 
|         |     33 #include <wtf/HashMap.h> | 
|         |     34 #include <wtf/HashTraits.h> | 
|         |     35 #pragma warning(pop) | 
|         |     36 #include <tchar.h> | 
|         |     37  | 
|         |     38 using namespace WebCore; | 
|         |     39  | 
|         |     40 // ---------------------------------------------------------------------------- | 
|         |     41  | 
|         |     42 struct ObserverHash; | 
|         |     43  | 
|         |     44 class ObserverKey | 
|         |     45 { | 
|         |     46     friend ObserverHash; | 
|         |     47 public: | 
|         |     48     ObserverKey(BSTR n = 0, IUnknown* o = 0); | 
|         |     49     ObserverKey(const ObserverKey& key); | 
|         |     50     ~ObserverKey(); | 
|         |     51  | 
|         |     52     bool operator==(const ObserverKey &) const; | 
|         |     53     ObserverKey& operator=(const ObserverKey &); | 
|         |     54  | 
|         |     55 private: | 
|         |     56     BSTR m_notificationName; | 
|         |     57     IUnknown* m_anObject; | 
|         |     58 }; | 
|         |     59  | 
|         |     60 ObserverKey::ObserverKey(BSTR n, IUnknown* o) | 
|         |     61 : m_notificationName(0) | 
|         |     62 , m_anObject(o) | 
|         |     63 { | 
|         |     64     if (n == (BSTR)-1) | 
|         |     65         m_notificationName = n; | 
|         |     66     else if (n) | 
|         |     67         m_notificationName = SysAllocString(n); | 
|         |     68     if (o) | 
|         |     69        o->AddRef(); | 
|         |     70 } | 
|         |     71  | 
|         |     72 ObserverKey::ObserverKey(const ObserverKey& other) | 
|         |     73 : m_notificationName(0) | 
|         |     74 , m_anObject(0) | 
|         |     75 { | 
|         |     76     *this = other; | 
|         |     77 } | 
|         |     78  | 
|         |     79 ObserverKey::~ObserverKey() | 
|         |     80 { | 
|         |     81     if (m_notificationName && m_notificationName != (BSTR)-1) | 
|         |     82         SysFreeString(m_notificationName); | 
|         |     83     if (m_anObject) | 
|         |     84         m_anObject->Release(); | 
|         |     85 } | 
|         |     86  | 
|         |     87 bool ObserverKey::operator==(const ObserverKey &other) const | 
|         |     88 { | 
|         |     89     if (m_anObject && other.m_anObject && m_anObject != other.m_anObject) | 
|         |     90         return false; // only fail to match anObject if both are non-null (treat null as a wildcard) | 
|         |     91  | 
|         |     92     if (m_notificationName == other.m_notificationName) | 
|         |     93         return true; | 
|         |     94  | 
|         |     95     if (!m_notificationName || m_notificationName == (BSTR)-1 || !other.m_notificationName || other.m_notificationName == (BSTR)-1) | 
|         |     96         return false; | 
|         |     97  | 
|         |     98     return !_tcscmp(m_notificationName, other.m_notificationName); | 
|         |     99 } | 
|         |    100  | 
|         |    101 ObserverKey& ObserverKey::operator=(const ObserverKey& other) | 
|         |    102 { | 
|         |    103     if (m_notificationName && m_notificationName != (BSTR)-1) | 
|         |    104         SysFreeString(m_notificationName); | 
|         |    105     m_notificationName = other.m_notificationName; | 
|         |    106     if (m_notificationName && m_notificationName != (BSTR)-1) | 
|         |    107         m_notificationName = SysAllocString(m_notificationName); | 
|         |    108     if (m_anObject != other.m_anObject) { | 
|         |    109         if (m_anObject) | 
|         |    110             m_anObject->Release(); | 
|         |    111         m_anObject = other.m_anObject; | 
|         |    112         if (m_anObject) | 
|         |    113             m_anObject->AddRef(); | 
|         |    114     } | 
|         |    115     return *this; | 
|         |    116 } | 
|         |    117  | 
|         |    118 struct ObserverKeyTraits : WTF::GenericHashTraits<ObserverKey> { | 
|         |    119     static const bool emptyValueIsZero = true; | 
|         |    120     static const bool needsDestruction = true; | 
|         |    121     static ObserverKey deletedValue() { return ObserverKey((BSTR)-1, 0); } | 
|         |    122 }; | 
|         |    123  | 
|         |    124 struct ObserverHash { | 
|         |    125     static unsigned hash(const ObserverKey&); | 
|         |    126     static bool equal(const ObserverKey& a, const ObserverKey& b) { return a == b; } | 
|         |    127 }; | 
|         |    128  | 
|         |    129 unsigned ObserverHash::hash(const ObserverKey& key) | 
|         |    130 { | 
|         |    131     unsigned h = 0; | 
|         |    132  | 
|         |    133     if (key.m_notificationName) { | 
|         |    134         if (key.m_notificationName == (BSTR)-1) | 
|         |    135             h = (unsigned)-1; | 
|         |    136         else | 
|         |    137             h = StringImpl::computeHash(key.m_notificationName, SysStringLen(key.m_notificationName)); | 
|         |    138     } | 
|         |    139  | 
|         |    140     // DO NOT take m_anObject into account for the hash.  We need to match based on m_notificationName only. | 
|         |    141     // We ensure a match in operator== if both of the values are non-null.  This matches semantics of | 
|         |    142     // NSNotificationCenter. | 
|         |    143  | 
|         |    144     return h; | 
|         |    145 } | 
|         |    146  | 
|         |    147 typedef HashMap<ObserverKey, Vector<IWebNotificationObserver*>, ObserverHash, ObserverKeyTraits> MappedObservers; | 
|         |    148  | 
|         |    149 struct WebNotificationCenterPrivate | 
|         |    150 { | 
|         |    151     MappedObservers m_mappedObservers; | 
|         |    152 }; | 
|         |    153  | 
|         |    154 // WebNotificationCenter ---------------------------------------------------------------- | 
|         |    155  | 
|         |    156 IWebNotificationCenter* WebNotificationCenter::m_defaultCenter = 0; | 
|         |    157  | 
|         |    158 WebNotificationCenter::WebNotificationCenter() | 
|         |    159 : m_refCount(0) | 
|         |    160 , d(new WebNotificationCenterPrivate) | 
|         |    161 { | 
|         |    162     gClassCount++; | 
|         |    163 } | 
|         |    164  | 
|         |    165 WebNotificationCenter::~WebNotificationCenter() | 
|         |    166 { | 
|         |    167     delete d; | 
|         |    168     gClassCount--; | 
|         |    169 } | 
|         |    170  | 
|         |    171 WebNotificationCenter* WebNotificationCenter::createInstance() | 
|         |    172 { | 
|         |    173     WebNotificationCenter* instance = new WebNotificationCenter(); | 
|         |    174     instance->AddRef(); | 
|         |    175     return instance; | 
|         |    176 } | 
|         |    177  | 
|         |    178 // IUnknown ------------------------------------------------------------------- | 
|         |    179  | 
|         |    180 HRESULT STDMETHODCALLTYPE WebNotificationCenter::QueryInterface(REFIID riid, void** ppvObject) | 
|         |    181 { | 
|         |    182     *ppvObject = 0; | 
|         |    183     if (IsEqualGUID(riid, IID_IUnknown)) | 
|         |    184         *ppvObject = static_cast<IWebNotificationCenter*>(this); | 
|         |    185     else if (IsEqualGUID(riid, IID_IWebNotificationCenter)) | 
|         |    186         *ppvObject = static_cast<IWebNotificationCenter*>(this); | 
|         |    187     else | 
|         |    188         return E_NOINTERFACE; | 
|         |    189  | 
|         |    190     AddRef(); | 
|         |    191     return S_OK; | 
|         |    192 } | 
|         |    193  | 
|         |    194 ULONG STDMETHODCALLTYPE WebNotificationCenter::AddRef(void) | 
|         |    195 { | 
|         |    196     return ++m_refCount; | 
|         |    197 } | 
|         |    198  | 
|         |    199 ULONG STDMETHODCALLTYPE WebNotificationCenter::Release(void) | 
|         |    200 { | 
|         |    201     ULONG newRef = --m_refCount; | 
|         |    202     if (!newRef) | 
|         |    203         delete(this); | 
|         |    204  | 
|         |    205     return newRef; | 
|         |    206 } | 
|         |    207  | 
|         |    208 IWebNotificationCenter* WebNotificationCenter::defaultCenterInternal() | 
|         |    209 { | 
|         |    210     if (!m_defaultCenter) | 
|         |    211         m_defaultCenter = WebNotificationCenter::createInstance(); | 
|         |    212     return m_defaultCenter; | 
|         |    213 } | 
|         |    214  | 
|         |    215 void WebNotificationCenter::postNotificationInternal(IWebNotification* notification, BSTR notificationName, IUnknown* anObject) | 
|         |    216 { | 
|         |    217     ObserverKey key(notificationName, anObject); | 
|         |    218     MappedObservers::iterator it = d->m_mappedObservers.find(key); | 
|         |    219     if (it != d->m_mappedObservers.end()) { | 
|         |    220         Vector<IWebNotificationObserver*> list = it->second; | 
|         |    221  | 
|         |    222         Vector<IWebNotificationObserver*>::iterator end = list.end(); | 
|         |    223         for (Vector<IWebNotificationObserver*>::iterator it2 = list.begin(); it2 != end; ++it2) { | 
|         |    224             (*it2)->onNotify(notification); | 
|         |    225         } | 
|         |    226     } | 
|         |    227 } | 
|         |    228  | 
|         |    229 // IWebNotificationCenter ----------------------------------------------------- | 
|         |    230  | 
|         |    231 HRESULT STDMETHODCALLTYPE WebNotificationCenter::defaultCenter(  | 
|         |    232     /* [retval][out] */ IWebNotificationCenter** center) | 
|         |    233 { | 
|         |    234     *center = defaultCenterInternal(); | 
|         |    235     (*center)->AddRef(); | 
|         |    236     return S_OK; | 
|         |    237 } | 
|         |    238  | 
|         |    239 HRESULT STDMETHODCALLTYPE WebNotificationCenter::addObserver(  | 
|         |    240     /* [in] */ IWebNotificationObserver* observer, | 
|         |    241     /* [in] */ BSTR notificationName, | 
|         |    242     /* [in] */ IUnknown* anObject) | 
|         |    243 { | 
|         |    244     ObserverKey key(notificationName, anObject); | 
|         |    245     MappedObservers::iterator it = d->m_mappedObservers.find(key); | 
|         |    246     observer->AddRef(); | 
|         |    247     if (it != d->m_mappedObservers.end()) | 
|         |    248         it->second.append(observer); | 
|         |    249     else { | 
|         |    250         Vector<IWebNotificationObserver*> list; | 
|         |    251         list.append(observer); | 
|         |    252         d->m_mappedObservers.add(key, list); | 
|         |    253     } | 
|         |    254  | 
|         |    255     return S_OK; | 
|         |    256 } | 
|         |    257  | 
|         |    258 HRESULT STDMETHODCALLTYPE WebNotificationCenter::postNotification(  | 
|         |    259     /* [in] */ IWebNotification* notification) | 
|         |    260 { | 
|         |    261     BSTR name; | 
|         |    262     HRESULT hr = notification->name(&name); | 
|         |    263     if (SUCCEEDED(hr)) { | 
|         |    264         IUnknown* obj; | 
|         |    265         hr = notification->getObject(&obj); | 
|         |    266         if (SUCCEEDED(hr)) { | 
|         |    267             postNotificationInternal(notification, name, obj); | 
|         |    268             if (obj) | 
|         |    269                 obj->Release(); | 
|         |    270         } | 
|         |    271         SysFreeString(name); | 
|         |    272     } | 
|         |    273  | 
|         |    274     return hr; | 
|         |    275 } | 
|         |    276  | 
|         |    277 HRESULT STDMETHODCALLTYPE WebNotificationCenter::postNotificationName(  | 
|         |    278     /* [in] */ BSTR notificationName, | 
|         |    279     /* [in] */ IUnknown* anObject, | 
|         |    280     /* [optional][in] */ IPropertyBag* userInfo) | 
|         |    281 { | 
|         |    282     WebNotification* notification = WebNotification::createInstance(notificationName, anObject, userInfo); | 
|         |    283     postNotificationInternal(notification, notificationName, anObject); | 
|         |    284     notification->Release(); | 
|         |    285     return S_OK; | 
|         |    286 } | 
|         |    287  | 
|         |    288 HRESULT STDMETHODCALLTYPE WebNotificationCenter::removeObserver(  | 
|         |    289     /* [in] */ IWebNotificationObserver* anObserver, | 
|         |    290     /* [in] */ BSTR notificationName, | 
|         |    291     /* [optional][in] */ IUnknown* anObject) | 
|         |    292 { | 
|         |    293     ObserverKey key(notificationName, anObject); | 
|         |    294     MappedObservers::iterator it = d->m_mappedObservers.find(key); | 
|         |    295     if (it == d->m_mappedObservers.end()) | 
|         |    296         return E_FAIL; | 
|         |    297  | 
|         |    298     Vector<IWebNotificationObserver*>& observerList = it->second; | 
|         |    299     Vector<IWebNotificationObserver*>::iterator end = observerList.end(); | 
|         |    300     int i=0; | 
|         |    301     for (Vector<IWebNotificationObserver*>::iterator it2 = observerList.begin(); it2 != end; ++it2, i++) { | 
|         |    302         if (*it2 == anObserver) { | 
|         |    303             (*it2)->Release(); | 
|         |    304             observerList.remove(i); | 
|         |    305             break; | 
|         |    306         } | 
|         |    307     } | 
|         |    308  | 
|         |    309     if (observerList.isEmpty()) | 
|         |    310         d->m_mappedObservers.remove(key); | 
|         |    311  | 
|         |    312     return S_OK; | 
|         |    313 } |