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 "DOMWrapperWorld.h" 32#include "Document.h" 33#include "DocumentStyleSheetCollection.h" 34#include "Frame.h" 35#include "GroupSettings.h" 36#include "Page.h" 37#include "PageCache.h" 38#include "SecurityOrigin.h" 39#include "Settings.h" 40#include "StorageNamespace.h" 41 42#if ENABLE(VIDEO_TRACK) 43#if (PLATFORM(MAC) && !PLATFORM(IOS)) || HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) 44#include "CaptionUserPreferencesMediaAF.h" 45#else 46#include "CaptionUserPreferences.h" 47#endif 48#endif 49 50namespace WebCore { 51 52static unsigned getUniqueIdentifier() 53{ 54 static unsigned currentIdentifier = 0; 55 return ++currentIdentifier; 56} 57 58// -------- 59 60static bool shouldTrackVisitedLinks = false; 61 62PageGroup::PageGroup(const String& name) 63 : m_name(name) 64 , m_visitedLinksPopulated(false) 65 , m_identifier(getUniqueIdentifier()) 66 , m_groupSettings(GroupSettings::create()) 67{ 68} 69 70PageGroup::PageGroup(Page* page) 71 : m_visitedLinksPopulated(false) 72 , m_identifier(getUniqueIdentifier()) 73 , m_groupSettings(GroupSettings::create()) 74{ 75 ASSERT(page); 76 addPage(page); 77} 78 79PageGroup::~PageGroup() 80{ 81 removeAllUserContent(); 82} 83 84PassOwnPtr<PageGroup> PageGroup::create(Page* page) 85{ 86 return adoptPtr(new PageGroup(page)); 87} 88 89typedef HashMap<String, PageGroup*> PageGroupMap; 90static PageGroupMap* pageGroups = 0; 91 92PageGroup* PageGroup::pageGroup(const String& groupName) 93{ 94 ASSERT(!groupName.isEmpty()); 95 96 if (!pageGroups) 97 pageGroups = new PageGroupMap; 98 99 PageGroupMap::AddResult result = pageGroups->add(groupName, 0); 100 101 if (result.isNewEntry) { 102 ASSERT(!result.iterator->value); 103 result.iterator->value = new PageGroup(groupName); 104 } 105 106 ASSERT(result.iterator->value); 107 return result.iterator->value; 108} 109 110void PageGroup::closeLocalStorage() 111{ 112 if (!pageGroups) 113 return; 114 115 PageGroupMap::iterator end = pageGroups->end(); 116 117 for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { 118 if (it->value->hasLocalStorage()) 119 it->value->localStorage()->close(); 120 } 121} 122 123void PageGroup::clearLocalStorageForAllOrigins() 124{ 125 if (!pageGroups) 126 return; 127 128 PageGroupMap::iterator end = pageGroups->end(); 129 for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { 130 if (it->value->hasLocalStorage()) 131 it->value->localStorage()->clearAllOriginsForDeletion(); 132 } 133} 134 135void PageGroup::clearLocalStorageForOrigin(SecurityOrigin* origin) 136{ 137 if (!pageGroups) 138 return; 139 140 PageGroupMap::iterator end = pageGroups->end(); 141 for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { 142 if (it->value->hasLocalStorage()) 143 it->value->localStorage()->clearOriginForDeletion(origin); 144 } 145} 146 147void PageGroup::closeIdleLocalStorageDatabases() 148{ 149 if (!pageGroups) 150 return; 151 152 PageGroupMap::iterator end = pageGroups->end(); 153 for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { 154 if (it->value->hasLocalStorage()) 155 it->value->localStorage()->closeIdleLocalStorageDatabases(); 156 } 157} 158 159void PageGroup::syncLocalStorage() 160{ 161 if (!pageGroups) 162 return; 163 164 PageGroupMap::iterator end = pageGroups->end(); 165 for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { 166 if (it->value->hasLocalStorage()) 167 it->value->localStorage()->sync(); 168 } 169} 170 171unsigned PageGroup::numberOfPageGroups() 172{ 173 if (!pageGroups) 174 return 0; 175 176 return pageGroups->size(); 177} 178 179void PageGroup::addPage(Page* page) 180{ 181 ASSERT(page); 182 ASSERT(!m_pages.contains(page)); 183 m_pages.add(page); 184} 185 186void PageGroup::removePage(Page* page) 187{ 188 ASSERT(page); 189 ASSERT(m_pages.contains(page)); 190 m_pages.remove(page); 191} 192 193bool PageGroup::isLinkVisited(LinkHash visitedLinkHash) 194{ 195 if (!m_visitedLinksPopulated) { 196 m_visitedLinksPopulated = true; 197 ASSERT(!m_pages.isEmpty()); 198 (*m_pages.begin())->chrome().client()->populateVisitedLinks(); 199 } 200 return m_visitedLinkHashes.contains(visitedLinkHash); 201} 202 203void PageGroup::addVisitedLinkHash(LinkHash hash) 204{ 205 if (shouldTrackVisitedLinks) 206 addVisitedLink(hash); 207} 208 209inline void PageGroup::addVisitedLink(LinkHash hash) 210{ 211 ASSERT(shouldTrackVisitedLinks); 212 if (!m_visitedLinkHashes.add(hash).isNewEntry) 213 return; 214 Page::visitedStateChanged(this, hash); 215 pageCache()->markPagesForVistedLinkStyleRecalc(); 216} 217 218void PageGroup::addVisitedLink(const KURL& url) 219{ 220 if (!shouldTrackVisitedLinks) 221 return; 222 ASSERT(!url.isEmpty()); 223 addVisitedLink(visitedLinkHash(url.string())); 224} 225 226void PageGroup::addVisitedLink(const UChar* characters, size_t length) 227{ 228 if (!shouldTrackVisitedLinks) 229 return; 230 addVisitedLink(visitedLinkHash(characters, length)); 231} 232 233void PageGroup::removeVisitedLinks() 234{ 235 m_visitedLinksPopulated = false; 236 if (m_visitedLinkHashes.isEmpty()) 237 return; 238 m_visitedLinkHashes.clear(); 239 Page::allVisitedStateChanged(this); 240 pageCache()->markPagesForVistedLinkStyleRecalc(); 241} 242 243void PageGroup::removeAllVisitedLinks() 244{ 245 Page::removeAllVisitedLinks(); 246 pageCache()->markPagesForVistedLinkStyleRecalc(); 247} 248 249void PageGroup::setShouldTrackVisitedLinks(bool shouldTrack) 250{ 251 if (shouldTrackVisitedLinks == shouldTrack) 252 return; 253 shouldTrackVisitedLinks = shouldTrack; 254 if (!shouldTrackVisitedLinks) 255 removeAllVisitedLinks(); 256} 257 258StorageNamespace* PageGroup::localStorage() 259{ 260 if (!m_localStorage) 261 m_localStorage = StorageNamespace::localStorageNamespace(this); 262 263 return m_localStorage.get(); 264} 265 266StorageNamespace* PageGroup::transientLocalStorage(SecurityOrigin* topOrigin) 267{ 268 HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageNamespace> >::AddResult result = m_transientLocalStorageMap.add(topOrigin, 0); 269 270 if (result.isNewEntry) 271 result.iterator->value = StorageNamespace::transientLocalStorageNamespace(this, topOrigin); 272 273 return result.iterator->value.get(); 274} 275 276void PageGroup::addUserScriptToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, 277 const Vector<String>& whitelist, const Vector<String>& blacklist, 278 UserScriptInjectionTime injectionTime, UserContentInjectedFrames injectedFrames) 279{ 280 ASSERT_ARG(world, world); 281 282 OwnPtr<UserScript> userScript = adoptPtr(new UserScript(source, url, whitelist, blacklist, injectionTime, injectedFrames)); 283 if (!m_userScripts) 284 m_userScripts = adoptPtr(new UserScriptMap); 285 OwnPtr<UserScriptVector>& scriptsInWorld = m_userScripts->add(world, nullptr).iterator->value; 286 if (!scriptsInWorld) 287 scriptsInWorld = adoptPtr(new UserScriptVector); 288 scriptsInWorld->append(userScript.release()); 289} 290 291void PageGroup::addUserStyleSheetToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, 292 const Vector<String>& whitelist, const Vector<String>& blacklist, 293 UserContentInjectedFrames injectedFrames, 294 UserStyleLevel level, 295 UserStyleInjectionTime injectionTime) 296{ 297 ASSERT_ARG(world, world); 298 299 OwnPtr<UserStyleSheet> userStyleSheet = adoptPtr(new UserStyleSheet(source, url, whitelist, blacklist, injectedFrames, level)); 300 if (!m_userStyleSheets) 301 m_userStyleSheets = adoptPtr(new UserStyleSheetMap); 302 OwnPtr<UserStyleSheetVector>& styleSheetsInWorld = m_userStyleSheets->add(world, nullptr).iterator->value; 303 if (!styleSheetsInWorld) 304 styleSheetsInWorld = adoptPtr(new UserStyleSheetVector); 305 styleSheetsInWorld->append(userStyleSheet.release()); 306 307 if (injectionTime == InjectInExistingDocuments) 308 invalidateInjectedStyleSheetCacheInAllFrames(); 309} 310 311void PageGroup::removeUserScriptFromWorld(DOMWrapperWorld* world, const KURL& url) 312{ 313 ASSERT_ARG(world, world); 314 315 if (!m_userScripts) 316 return; 317 318 UserScriptMap::iterator it = m_userScripts->find(world); 319 if (it == m_userScripts->end()) 320 return; 321 322 UserScriptVector* scripts = it->value.get(); 323 for (int i = scripts->size() - 1; i >= 0; --i) { 324 if (scripts->at(i)->url() == url) 325 scripts->remove(i); 326 } 327 328 if (scripts->isEmpty()) 329 m_userScripts->remove(it); 330} 331 332void PageGroup::removeUserStyleSheetFromWorld(DOMWrapperWorld* world, const KURL& url) 333{ 334 ASSERT_ARG(world, world); 335 336 if (!m_userStyleSheets) 337 return; 338 339 UserStyleSheetMap::iterator it = m_userStyleSheets->find(world); 340 bool sheetsChanged = false; 341 if (it == m_userStyleSheets->end()) 342 return; 343 344 UserStyleSheetVector* stylesheets = it->value.get(); 345 for (int i = stylesheets->size() - 1; i >= 0; --i) { 346 if (stylesheets->at(i)->url() == url) { 347 stylesheets->remove(i); 348 sheetsChanged = true; 349 } 350 } 351 352 if (!sheetsChanged) 353 return; 354 355 if (stylesheets->isEmpty()) 356 m_userStyleSheets->remove(it); 357 358 invalidateInjectedStyleSheetCacheInAllFrames(); 359} 360 361void PageGroup::removeUserScriptsFromWorld(DOMWrapperWorld* world) 362{ 363 ASSERT_ARG(world, world); 364 365 if (!m_userScripts) 366 return; 367 368 UserScriptMap::iterator it = m_userScripts->find(world); 369 if (it == m_userScripts->end()) 370 return; 371 372 m_userScripts->remove(it); 373} 374 375void PageGroup::removeUserStyleSheetsFromWorld(DOMWrapperWorld* world) 376{ 377 ASSERT_ARG(world, world); 378 379 if (!m_userStyleSheets) 380 return; 381 382 UserStyleSheetMap::iterator it = m_userStyleSheets->find(world); 383 if (it == m_userStyleSheets->end()) 384 return; 385 386 m_userStyleSheets->remove(it); 387 388 invalidateInjectedStyleSheetCacheInAllFrames(); 389} 390 391void PageGroup::removeAllUserContent() 392{ 393 m_userScripts.clear(); 394 395 if (m_userStyleSheets) { 396 m_userStyleSheets.clear(); 397 invalidateInjectedStyleSheetCacheInAllFrames(); 398 } 399} 400 401void PageGroup::invalidateInjectedStyleSheetCacheInAllFrames() 402{ 403 // Clear our cached sheets and have them just reparse. 404 HashSet<Page*>::const_iterator end = m_pages.end(); 405 for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) { 406 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) { 407 frame->document()->styleSheetCollection()->invalidateInjectedStyleSheetCache(); 408 frame->document()->styleResolverChanged(DeferRecalcStyle); 409 } 410 } 411} 412 413#if ENABLE(VIDEO_TRACK) 414void PageGroup::captionPreferencesChanged() 415{ 416 for (HashSet<Page*>::iterator i = m_pages.begin(); i != m_pages.end(); ++i) 417 (*i)->captionPreferencesChanged(); 418 pageCache()->markPagesForCaptionPreferencesChanged(); 419} 420 421CaptionUserPreferences* PageGroup::captionPreferences() 422{ 423 if (!m_captionPreferences) 424#if (PLATFORM(MAC) && !PLATFORM(IOS)) || HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) 425 m_captionPreferences = CaptionUserPreferencesMediaAF::create(this); 426#else 427 m_captionPreferences = CaptionUserPreferences::create(this); 428#endif 429 430 return m_captionPreferences.get(); 431} 432 433#endif 434 435} // namespace WebCore 436