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