1 /* 2 * Copyright (C) 2008 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 "PageGroup.h" 28 29 #include "Chrome.h" 30 #include "ChromeClient.h" 31 #include "Document.h" 32 #include "Frame.h" 33 #include "Page.h" 34 #include "Settings.h" 35 36 #if ENABLE(DOM_STORAGE) 37 #include "StorageNamespace.h" 38 #endif 39 40 #if PLATFORM(CHROMIUM) 41 #include "ChromiumBridge.h" 42 #endif 43 44 namespace WebCore { 45 46 static unsigned getUniqueIdentifier() 47 { 48 static unsigned currentIdentifier = 0; 49 return ++currentIdentifier; 50 } 51 52 // -------- 53 54 static bool shouldTrackVisitedLinks = false; 55 56 PageGroup::PageGroup(const String& name) 57 : m_name(name) 58 , m_visitedLinksPopulated(false) 59 , m_identifier(getUniqueIdentifier()) 60 { 61 } 62 63 PageGroup::PageGroup(Page* page) 64 : m_visitedLinksPopulated(false) 65 , m_identifier(getUniqueIdentifier()) 66 { 67 ASSERT(page); 68 addPage(page); 69 } 70 71 PageGroup::~PageGroup() 72 { 73 removeAllUserContent(); 74 } 75 76 typedef HashMap<String, PageGroup*> PageGroupMap; 77 static PageGroupMap* pageGroups = 0; 78 79 PageGroup* PageGroup::pageGroup(const String& groupName) 80 { 81 ASSERT(!groupName.isEmpty()); 82 83 if (!pageGroups) 84 pageGroups = new PageGroupMap; 85 86 pair<PageGroupMap::iterator, bool> result = pageGroups->add(groupName, 0); 87 88 if (result.second) { 89 ASSERT(!result.first->second); 90 result.first->second = new PageGroup(groupName); 91 } 92 93 ASSERT(result.first->second); 94 return result.first->second; 95 } 96 97 void PageGroup::closeLocalStorage() 98 { 99 #if ENABLE(DOM_STORAGE) 100 if (!pageGroups) 101 return; 102 103 PageGroupMap::iterator end = pageGroups->end(); 104 105 for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { 106 if (it->second->hasLocalStorage()) 107 it->second->localStorage()->close(); 108 } 109 #endif 110 } 111 112 void PageGroup::addPage(Page* page) 113 { 114 ASSERT(page); 115 ASSERT(!m_pages.contains(page)); 116 m_pages.add(page); 117 } 118 119 void PageGroup::removePage(Page* page) 120 { 121 ASSERT(page); 122 ASSERT(m_pages.contains(page)); 123 m_pages.remove(page); 124 } 125 126 bool PageGroup::isLinkVisited(LinkHash visitedLinkHash) 127 { 128 #if PLATFORM(CHROMIUM) 129 // Use Chromium's built-in visited link database. 130 return ChromiumBridge::isLinkVisited(visitedLinkHash); 131 #else 132 if (!m_visitedLinksPopulated) { 133 m_visitedLinksPopulated = true; 134 ASSERT(!m_pages.isEmpty()); 135 (*m_pages.begin())->chrome()->client()->populateVisitedLinks(); 136 } 137 return m_visitedLinkHashes.contains(visitedLinkHash); 138 #endif 139 } 140 141 inline void PageGroup::addVisitedLink(LinkHash hash) 142 { 143 ASSERT(shouldTrackVisitedLinks); 144 #if !PLATFORM(CHROMIUM) 145 if (!m_visitedLinkHashes.add(hash).second) 146 return; 147 #endif 148 Page::visitedStateChanged(this, hash); 149 } 150 151 void PageGroup::addVisitedLink(const KURL& url) 152 { 153 if (!shouldTrackVisitedLinks) 154 return; 155 ASSERT(!url.isEmpty()); 156 addVisitedLink(visitedLinkHash(url.string().characters(), url.string().length())); 157 } 158 159 void PageGroup::addVisitedLink(const UChar* characters, size_t length) 160 { 161 if (!shouldTrackVisitedLinks) 162 return; 163 addVisitedLink(visitedLinkHash(characters, length)); 164 } 165 166 void PageGroup::removeVisitedLinks() 167 { 168 m_visitedLinksPopulated = false; 169 if (m_visitedLinkHashes.isEmpty()) 170 return; 171 m_visitedLinkHashes.clear(); 172 Page::allVisitedStateChanged(this); 173 } 174 175 void PageGroup::removeAllVisitedLinks() 176 { 177 Page::removeAllVisitedLinks(); 178 } 179 180 void PageGroup::setShouldTrackVisitedLinks(bool shouldTrack) 181 { 182 if (shouldTrackVisitedLinks == shouldTrack) 183 return; 184 shouldTrackVisitedLinks = shouldTrack; 185 if (!shouldTrackVisitedLinks) 186 removeAllVisitedLinks(); 187 } 188 189 #if ENABLE(DOM_STORAGE) 190 StorageNamespace* PageGroup::localStorage() 191 { 192 if (!m_localStorage) { 193 // Need a page in this page group to query the settings for the local storage database path. 194 Page* page = *m_pages.begin(); 195 const String& path = page->settings()->localStorageDatabasePath(); 196 unsigned quota = page->settings()->localStorageQuota(); 197 m_localStorage = StorageNamespace::localStorageNamespace(path, quota); 198 } 199 200 return m_localStorage.get(); 201 } 202 #endif 203 204 void PageGroup::addUserScriptToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, PassOwnPtr<Vector<String> > whitelist, 205 PassOwnPtr<Vector<String> > blacklist, UserScriptInjectionTime injectionTime) 206 { 207 ASSERT_ARG(world, world); 208 209 OwnPtr<UserScript> userScript(new UserScript(source, url, whitelist, blacklist, injectionTime)); 210 if (!m_userScripts) 211 m_userScripts.set(new UserScriptMap); 212 UserScriptVector*& scriptsInWorld = m_userScripts->add(world, 0).first->second; 213 if (!scriptsInWorld) 214 scriptsInWorld = new UserScriptVector; 215 scriptsInWorld->append(userScript.release()); 216 } 217 218 void PageGroup::addUserStyleSheetToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, PassOwnPtr<Vector<String> > whitelist, 219 PassOwnPtr<Vector<String> > blacklist) 220 { 221 ASSERT_ARG(world, world); 222 223 OwnPtr<UserStyleSheet> userStyleSheet(new UserStyleSheet(source, url, whitelist, blacklist)); 224 if (!m_userStyleSheets) 225 m_userStyleSheets.set(new UserStyleSheetMap); 226 UserStyleSheetVector*& styleSheetsInWorld = m_userStyleSheets->add(world, 0).first->second; 227 if (!styleSheetsInWorld) 228 styleSheetsInWorld = new UserStyleSheetVector; 229 styleSheetsInWorld->append(userStyleSheet.release()); 230 231 // Clear our cached sheets and have them just reparse. 232 HashSet<Page*>::const_iterator end = m_pages.end(); 233 for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) { 234 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 235 frame->document()->clearPageGroupUserSheets(); 236 } 237 } 238 239 void PageGroup::removeUserScriptFromWorld(DOMWrapperWorld* world, const KURL& url) 240 { 241 ASSERT_ARG(world, world); 242 243 if (!m_userScripts) 244 return; 245 246 UserScriptMap::iterator it = m_userScripts->find(world); 247 if (it == m_userScripts->end()) 248 return; 249 250 UserScriptVector* scripts = it->second; 251 for (int i = scripts->size() - 1; i >= 0; --i) { 252 if (scripts->at(i)->url() == url) 253 scripts->remove(i); 254 } 255 256 if (!scripts->isEmpty()) 257 return; 258 259 delete it->second; 260 m_userScripts->remove(it); 261 } 262 263 void PageGroup::removeUserStyleSheetFromWorld(DOMWrapperWorld* world, const KURL& url) 264 { 265 ASSERT_ARG(world, world); 266 267 if (!m_userStyleSheets) 268 return; 269 270 UserStyleSheetMap::iterator it = m_userStyleSheets->find(world); 271 bool sheetsChanged = false; 272 if (it == m_userStyleSheets->end()) 273 return; 274 275 UserStyleSheetVector* stylesheets = it->second; 276 for (int i = stylesheets->size() - 1; i >= 0; --i) { 277 if (stylesheets->at(i)->url() == url) { 278 stylesheets->remove(i); 279 sheetsChanged = true; 280 } 281 } 282 283 if (!sheetsChanged) 284 return; 285 286 if (!stylesheets->isEmpty()) { 287 delete it->second; 288 m_userStyleSheets->remove(it); 289 } 290 291 // Clear our cached sheets and have them just reparse. 292 HashSet<Page*>::const_iterator end = m_pages.end(); 293 for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) { 294 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 295 frame->document()->clearPageGroupUserSheets(); 296 } 297 } 298 299 void PageGroup::removeUserScriptsFromWorld(DOMWrapperWorld* world) 300 { 301 ASSERT_ARG(world, world); 302 303 if (!m_userScripts) 304 return; 305 306 UserScriptMap::iterator it = m_userScripts->find(world); 307 if (it == m_userScripts->end()) 308 return; 309 310 delete it->second; 311 m_userScripts->remove(it); 312 } 313 314 void PageGroup::removeUserStyleSheetsFromWorld(DOMWrapperWorld* world) 315 { 316 ASSERT_ARG(world, world); 317 318 if (!m_userStyleSheets) 319 return; 320 321 UserStyleSheetMap::iterator it = m_userStyleSheets->find(world); 322 if (it == m_userStyleSheets->end()) 323 return; 324 325 delete it->second; 326 m_userStyleSheets->remove(it); 327 328 // Clear our cached sheets and have them just reparse. 329 HashSet<Page*>::const_iterator end = m_pages.end(); 330 for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) { 331 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 332 frame->document()->clearPageGroupUserSheets(); 333 } 334 } 335 336 void PageGroup::removeAllUserContent() 337 { 338 if (m_userScripts) { 339 deleteAllValues(*m_userScripts); 340 m_userScripts.clear(); 341 } 342 343 344 if (m_userStyleSheets) { 345 deleteAllValues(*m_userStyleSheets); 346 m_userStyleSheets.clear(); 347 } 348 } 349 350 } // namespace WebCore 351