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