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/COMPtr.h>
33 #include <WebCore/PlatformString.h>
34 #include <WebCore/StringHash.h>
35 #include <wtf/HashMap.h>
36 #include <wtf/HashTraits.h>
37 #include <wtf/Vector.h>
38 #pragma warning(pop)
39 #include <tchar.h>
40 #include <utility>
41
42 using namespace WebCore;
43
44 typedef std::pair<COMPtr<IUnknown>, COMPtr<IWebNotificationObserver> > ObjectObserverPair;
45 typedef Vector<ObjectObserverPair> ObjectObserverList;
46 typedef ObjectObserverList::iterator ObserverListIterator;
47 typedef HashMap<String, ObjectObserverList> MappedObservers;
48
49 struct WebNotificationCenterPrivate {
50 MappedObservers m_mappedObservers;
51 };
52
53 // WebNotificationCenter ----------------------------------------------------------------
54
55 IWebNotificationCenter* WebNotificationCenter::m_defaultCenter = 0;
56
WebNotificationCenter()57 WebNotificationCenter::WebNotificationCenter()
58 : m_refCount(0)
59 , d(new WebNotificationCenterPrivate)
60 {
61 gClassCount++;
62 gClassNameCount.add("WebNotificationCenter");
63 }
64
~WebNotificationCenter()65 WebNotificationCenter::~WebNotificationCenter()
66 {
67 gClassCount--;
68 gClassNameCount.remove("WebNotificationCenter");
69 }
70
createInstance()71 WebNotificationCenter* WebNotificationCenter::createInstance()
72 {
73 WebNotificationCenter* instance = new WebNotificationCenter();
74 instance->AddRef();
75 return instance;
76 }
77
78 // IUnknown -------------------------------------------------------------------
79
QueryInterface(REFIID riid,void ** ppvObject)80 HRESULT STDMETHODCALLTYPE WebNotificationCenter::QueryInterface(REFIID riid, void** ppvObject)
81 {
82 *ppvObject = 0;
83 if (IsEqualGUID(riid, IID_IUnknown))
84 *ppvObject = static_cast<IWebNotificationCenter*>(this);
85 else if (IsEqualGUID(riid, IID_IWebNotificationCenter))
86 *ppvObject = static_cast<IWebNotificationCenter*>(this);
87 else
88 return E_NOINTERFACE;
89
90 AddRef();
91 return S_OK;
92 }
93
AddRef(void)94 ULONG STDMETHODCALLTYPE WebNotificationCenter::AddRef(void)
95 {
96 return ++m_refCount;
97 }
98
Release(void)99 ULONG STDMETHODCALLTYPE WebNotificationCenter::Release(void)
100 {
101 ULONG newRef = --m_refCount;
102 if (!newRef)
103 delete(this);
104
105 return newRef;
106 }
107
defaultCenterInternal()108 IWebNotificationCenter* WebNotificationCenter::defaultCenterInternal()
109 {
110 if (!m_defaultCenter)
111 m_defaultCenter = WebNotificationCenter::createInstance();
112 return m_defaultCenter;
113 }
114
postNotificationInternal(IWebNotification * notification,BSTR notificationName,IUnknown * anObject)115 void WebNotificationCenter::postNotificationInternal(IWebNotification* notification, BSTR notificationName, IUnknown* anObject)
116 {
117 String name(notificationName, SysStringLen(notificationName));
118 MappedObservers::iterator it = d->m_mappedObservers.find(name);
119 if (it == d->m_mappedObservers.end())
120 return;
121
122 // Intentionally make a copy of the list to avoid the possibility of errors
123 // from a mutation of the list in the onNotify callback.
124 ObjectObserverList list = it->second;
125
126 ObserverListIterator end = list.end();
127 for (ObserverListIterator it2 = list.begin(); it2 != end; ++it2) {
128 IUnknown* observedObject = it2->first.get();
129 IWebNotificationObserver* observer = it2->second.get();
130 if (!observedObject || !anObject || observedObject == anObject)
131 observer->onNotify(notification);
132 }
133 }
134
135 // IWebNotificationCenter -----------------------------------------------------
136
defaultCenter(IWebNotificationCenter ** center)137 HRESULT STDMETHODCALLTYPE WebNotificationCenter::defaultCenter(
138 /* [retval][out] */ IWebNotificationCenter** center)
139 {
140 *center = defaultCenterInternal();
141 (*center)->AddRef();
142 return S_OK;
143 }
144
addObserver(IWebNotificationObserver * observer,BSTR notificationName,IUnknown * anObject)145 HRESULT STDMETHODCALLTYPE WebNotificationCenter::addObserver(
146 /* [in] */ IWebNotificationObserver* observer,
147 /* [in] */ BSTR notificationName,
148 /* [in] */ IUnknown* anObject)
149 {
150 String name(notificationName, SysStringLen(notificationName));
151 MappedObservers::iterator it = d->m_mappedObservers.find(name);
152 if (it != d->m_mappedObservers.end())
153 it->second.append(ObjectObserverPair(anObject, observer));
154 else {
155 ObjectObserverList list;
156 list.append(ObjectObserverPair(anObject, observer));
157 d->m_mappedObservers.add(name, list);
158 }
159
160 return S_OK;
161 }
162
postNotification(IWebNotification * notification)163 HRESULT STDMETHODCALLTYPE WebNotificationCenter::postNotification(
164 /* [in] */ IWebNotification* notification)
165 {
166 BSTR name;
167 HRESULT hr = notification->name(&name);
168 if (FAILED(hr))
169 return hr;
170
171 COMPtr<IUnknown> obj;
172 hr = notification->getObject(&obj);
173 if (FAILED(hr))
174 return hr;
175
176 postNotificationInternal(notification, name, obj.get());
177 SysFreeString(name);
178
179 return hr;
180 }
181
postNotificationName(BSTR notificationName,IUnknown * anObject,IPropertyBag * userInfo)182 HRESULT STDMETHODCALLTYPE WebNotificationCenter::postNotificationName(
183 /* [in] */ BSTR notificationName,
184 /* [in] */ IUnknown* anObject,
185 /* [optional][in] */ IPropertyBag* userInfo)
186 {
187 COMPtr<WebNotification> notification(AdoptCOM, WebNotification::createInstance(notificationName, anObject, userInfo));
188 postNotificationInternal(notification.get(), notificationName, anObject);
189 return S_OK;
190 }
191
removeObserver(IWebNotificationObserver * anObserver,BSTR notificationName,IUnknown * anObject)192 HRESULT STDMETHODCALLTYPE WebNotificationCenter::removeObserver(
193 /* [in] */ IWebNotificationObserver* anObserver,
194 /* [in] */ BSTR notificationName,
195 /* [optional][in] */ IUnknown* anObject)
196 {
197 String name(notificationName, SysStringLen(notificationName));
198 MappedObservers::iterator it = d->m_mappedObservers.find(name);
199 if (it == d->m_mappedObservers.end())
200 return E_FAIL;
201
202 ObjectObserverList& observerList = it->second;
203 ObserverListIterator end = observerList.end();
204
205 int i = 0;
206 for (ObserverListIterator it2 = observerList.begin(); it2 != end; ++it2, ++i) {
207 IUnknown* observedObject = it2->first.get();
208 IWebNotificationObserver* observer = it2->second.get();
209 if (observer == anObserver && (!anObject || anObject == observedObject)) {
210 observerList.remove(i);
211 break;
212 }
213 }
214
215 if (observerList.isEmpty())
216 d->m_mappedObservers.remove(name);
217
218 return S_OK;
219 }
220