2011-05-09 Shishir Agrawal <shishir@chromium.org>
[WebKit-https.git] / Source / WebCore / page / Page.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "Page.h"
22
23 #include "BackForwardController.h"
24 #include "BackForwardList.h"
25 #include "Base64.h"
26 #include "CSSStyleSelector.h"
27 #include "Chrome.h"
28 #include "ChromeClient.h"
29 #include "ContextMenuClient.h"
30 #include "ContextMenuController.h"
31 #include "DOMWindow.h"
32 #include "DeviceMotionController.h"
33 #include "DeviceOrientationController.h"
34 #include "DocumentMarkerController.h"
35 #include "DragController.h"
36 #include "EditorClient.h"
37 #include "Event.h"
38 #include "EventNames.h"
39 #include "ExceptionCode.h"
40 #include "FileSystem.h"
41 #include "FocusController.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "FrameSelection.h"
46 #include "FrameTree.h"
47 #include "FrameView.h"
48 #include "HTMLElement.h"
49 #include "HistoryItem.h"
50 #include "InspectorController.h"
51 #include "InspectorInstrumentation.h"
52 #include "Logging.h"
53 #include "MediaCanStartListener.h"
54 #include "MediaStreamClient.h"
55 #include "MediaStreamController.h"
56 #include "Navigator.h"
57 #include "NetworkStateNotifier.h"
58 #include "PageGroup.h"
59 #include "PluginData.h"
60 #include "PluginHalter.h"
61 #include "PluginView.h"
62 #include "PluginViewBase.h"
63 #include "ProgressTracker.h"
64 #include "RenderTheme.h"
65 #include "RenderWidget.h"
66 #include "RuntimeEnabledFeatures.h"
67 #include "Settings.h"
68 #include "SharedBuffer.h"
69 #include "SpeechInput.h"
70 #include "SpeechInputClient.h"
71 #include "TextResourceDecoder.h"
72 #include "Widget.h"
73 #include <wtf/HashMap.h>
74 #include <wtf/RefCountedLeakCounter.h>
75 #include <wtf/StdLibExtras.h>
76 #include <wtf/text/StringHash.h>
77
78 #if ENABLE(ACCELERATED_2D_CANVAS)
79 #include "SharedGraphicsContext3D.h"
80 #endif
81
82 #if ENABLE(DOM_STORAGE)
83 #include "StorageArea.h"
84 #include "StorageNamespace.h"
85 #endif
86
87 #if ENABLE(CLIENT_BASED_GEOLOCATION)
88 #include "GeolocationController.h"
89 #endif
90
91 namespace WebCore {
92
93 static HashSet<Page*>* allPages;
94
95 #ifndef NDEBUG
96 static WTF::RefCountedLeakCounter pageCounter("Page");
97 #endif
98
99 static void networkStateChanged()
100 {
101     Vector<RefPtr<Frame> > frames;
102     
103     // Get all the frames of all the pages in all the page groups
104     HashSet<Page*>::iterator end = allPages->end();
105     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
106         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
107             frames.append(frame);
108         InspectorInstrumentation::networkStateChanged(*it);
109     }
110
111     AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
112     for (unsigned i = 0; i < frames.size(); i++)
113         frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
114 }
115
116 Page::Page(const PageClients& pageClients)
117     : m_chrome(adoptPtr(new Chrome(this, pageClients.chromeClient)))
118     , m_dragCaretController(adoptPtr(new DragCaretController))
119 #if ENABLE(DRAG_SUPPORT)
120     , m_dragController(adoptPtr(new DragController(this, pageClients.dragClient)))
121 #endif
122     , m_focusController(adoptPtr(new FocusController(this)))
123 #if ENABLE(CONTEXT_MENUS)
124     , m_contextMenuController(adoptPtr(new ContextMenuController(this, pageClients.contextMenuClient)))
125 #endif
126 #if ENABLE(INSPECTOR)
127     , m_inspectorController(adoptPtr(new InspectorController(this, pageClients.inspectorClient)))
128 #endif
129 #if ENABLE(CLIENT_BASED_GEOLOCATION)
130     , m_geolocationController(adoptPtr(new GeolocationController(this, pageClients.geolocationClient)))
131 #endif
132 #if ENABLE(DEVICE_ORIENTATION)
133     , m_deviceMotionController(RuntimeEnabledFeatures::deviceMotionEnabled() ? adoptPtr(new DeviceMotionController(pageClients.deviceMotionClient)) : nullptr)
134     , m_deviceOrientationController(RuntimeEnabledFeatures::deviceOrientationEnabled() ? adoptPtr(new DeviceOrientationController(this, pageClients.deviceOrientationClient)) : nullptr)
135 #endif
136 #if ENABLE(MEDIA_STREAM)
137     , m_mediaStreamController(RuntimeEnabledFeatures::mediaStreamEnabled() ? adoptPtr(new MediaStreamController(pageClients.mediaStreamClient)) : PassOwnPtr<MediaStreamController>())
138 #endif
139 #if ENABLE(INPUT_SPEECH)
140     , m_speechInputClient(pageClients.speechInputClient)
141 #endif
142     , m_settings(adoptPtr(new Settings(this)))
143     , m_progress(adoptPtr(new ProgressTracker))
144     , m_backForwardController(adoptPtr(new BackForwardController(this, pageClients.backForwardClient)))
145     , m_theme(RenderTheme::themeForPage(this))
146     , m_editorClient(pageClients.editorClient)
147     , m_frameCount(0)
148     , m_openedByDOM(false)
149     , m_tabKeyCyclesThroughElements(true)
150     , m_defersLoading(false)
151     , m_inLowQualityInterpolationMode(false)
152     , m_cookieEnabled(true)
153     , m_areMemoryCacheClientCallsEnabled(true)
154     , m_mediaVolume(1)
155     , m_javaScriptURLsAreAllowed(true)
156     , m_didLoadUserStyleSheet(false)
157     , m_userStyleSheetModificationTime(0)
158     , m_group(0)
159     , m_debugger(0)
160     , m_customHTMLTokenizerTimeDelay(-1)
161     , m_customHTMLTokenizerChunkSize(-1)
162     , m_canStartMedia(true)
163     , m_viewMode(ViewModeWindowed)
164     , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
165     , m_isEditable(false)
166 #if ENABLE(PAGE_VISIBILITY_API)
167     , m_visibilityState(PageVisibilityStateVisible)
168 #endif
169 {
170     if (!allPages) {
171         allPages = new HashSet<Page*>;
172         
173         networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
174     }
175
176     ASSERT(!allPages->contains(this));
177     allPages->add(this);
178
179     if (pageClients.pluginHalterClient) {
180         m_pluginHalter = adoptPtr(new PluginHalter(pageClients.pluginHalterClient));
181         m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
182     }
183
184 #ifndef NDEBUG
185     pageCounter.increment();
186 #endif
187 }
188
189 Page::~Page()
190 {
191     m_mainFrame->setView(0);
192     setGroupName(String());
193     allPages->remove(this);
194     
195     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
196         frame->pageDestroyed();
197
198     if (m_scrollableAreaSet) {
199         ScrollableAreaSet::const_iterator end = m_scrollableAreaSet->end(); 
200         for (ScrollableAreaSet::const_iterator it = m_scrollableAreaSet->begin(); it != end; ++it)
201             (*it)->disconnectFromPage();
202     }
203
204     m_editorClient->pageDestroyed();
205
206     InspectorInstrumentation::inspectedPageDestroyed(this);
207
208     backForward()->close();
209
210 #ifndef NDEBUG
211     pageCounter.decrement();
212
213     // Cancel keepAlive timers, to ensure we release all Frames before exiting.
214     // It's safe to do this because we prohibit closing a Page while JavaScript
215     // is executing.
216     Frame::cancelAllKeepAlive();
217 #endif
218 }
219
220 struct ViewModeInfo {
221     const char* name;
222     Page::ViewMode type;
223 };
224 static const int viewModeMapSize = 5;
225 static ViewModeInfo viewModeMap[viewModeMapSize] = {
226     {"windowed", Page::ViewModeWindowed},
227     {"floating", Page::ViewModeFloating},
228     {"fullscreen", Page::ViewModeFullscreen},
229     {"maximized", Page::ViewModeMaximized},
230     {"minimized", Page::ViewModeMinimized}
231 };
232
233 Page::ViewMode Page::stringToViewMode(const String& text)
234 {
235     for (int i = 0; i < viewModeMapSize; ++i) {
236         if (text == viewModeMap[i].name)
237             return viewModeMap[i].type;
238     }
239     return Page::ViewModeInvalid;
240 }
241
242 void Page::setViewMode(ViewMode viewMode)
243 {
244     if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
245         return;
246
247     m_viewMode = viewMode;
248
249     if (!m_mainFrame)
250         return;
251
252     if (m_mainFrame->view())
253         m_mainFrame->view()->forceLayout();
254
255     if (m_mainFrame->document())
256         m_mainFrame->document()->styleSelectorChanged(RecalcStyleImmediately);
257 }
258
259 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
260 {
261     ASSERT(!m_mainFrame); // Should only be called during initialization
262     m_mainFrame = mainFrame;
263 }
264
265 bool Page::openedByDOM() const
266 {
267     return m_openedByDOM;
268 }
269
270 void Page::setOpenedByDOM()
271 {
272     m_openedByDOM = true;
273 }
274
275 BackForwardList* Page::backForwardList() const
276 {
277     return m_backForwardController->client();
278 }
279
280 bool Page::goBack()
281 {
282     HistoryItem* item = backForward()->backItem();
283     
284     if (item) {
285         goToItem(item, FrameLoadTypeBack);
286         return true;
287     }
288     return false;
289 }
290
291 bool Page::goForward()
292 {
293     HistoryItem* item = backForward()->forwardItem();
294     
295     if (item) {
296         goToItem(item, FrameLoadTypeForward);
297         return true;
298     }
299     return false;
300 }
301
302 bool Page::canGoBackOrForward(int distance) const
303 {
304     if (distance == 0)
305         return true;
306     if (distance > 0 && distance <= backForward()->forwardCount())
307         return true;
308     if (distance < 0 && -distance <= backForward()->backCount())
309         return true;
310     return false;
311 }
312
313 void Page::goBackOrForward(int distance)
314 {
315     if (distance == 0)
316         return;
317
318     HistoryItem* item = backForward()->itemAtIndex(distance);
319     if (!item) {
320         if (distance > 0) {
321             if (int forwardCount = backForward()->forwardCount()) 
322                 item = backForward()->itemAtIndex(forwardCount);
323         } else {
324             if (int backCount = backForward()->backCount())
325                 item = backForward()->itemAtIndex(-backCount);
326         }
327     }
328
329     ASSERT(item);
330     if (!item)
331         return;
332
333     goToItem(item, FrameLoadTypeIndexedBackForward);
334 }
335
336 void Page::goToItem(HistoryItem* item, FrameLoadType type)
337 {
338     if (defersLoading())
339         return;
340
341     // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
342     // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
343     RefPtr<HistoryItem> protector(item);
344
345     if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
346         m_mainFrame->loader()->stopAllLoaders();
347
348     m_mainFrame->loader()->history()->goToItem(item, type);
349 }
350
351 int Page::getHistoryLength()
352 {
353     return backForward()->backCount() + 1 + backForward()->forwardCount();
354 }
355
356 void Page::setGroupName(const String& name)
357 {
358     if (m_group && !m_group->name().isEmpty()) {
359         ASSERT(m_group != m_singlePageGroup.get());
360         ASSERT(!m_singlePageGroup);
361         m_group->removePage(this);
362     }
363
364     if (name.isEmpty())
365         m_group = m_singlePageGroup.get();
366     else {
367         m_singlePageGroup.clear();
368         m_group = PageGroup::pageGroup(name);
369         m_group->addPage(this);
370     }
371 }
372
373 const String& Page::groupName() const
374 {
375     DEFINE_STATIC_LOCAL(String, nullString, ());
376     return m_group ? m_group->name() : nullString;
377 }
378
379 void Page::initGroup()
380 {
381     ASSERT(!m_singlePageGroup);
382     ASSERT(!m_group);
383     m_singlePageGroup = adoptPtr(new PageGroup(this));
384     m_group = m_singlePageGroup.get();
385 }
386
387 void Page::scheduleForcedStyleRecalcForAllPages()
388 {
389     if (!allPages)
390         return;
391     HashSet<Page*>::iterator end = allPages->end();
392     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
393         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
394             frame->document()->scheduleForcedStyleRecalc();
395 }
396
397 void Page::setNeedsRecalcStyleInAllFrames()
398 {
399     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
400         frame->document()->styleSelectorChanged(DeferRecalcStyle);
401 }
402
403 void Page::updateViewportArguments()
404 {
405     if (!mainFrame() || !mainFrame()->document() || mainFrame()->document()->viewportArguments() == m_viewportArguments)
406         return;
407
408     m_viewportArguments = mainFrame()->document()->viewportArguments();
409     chrome()->dispatchViewportDataDidChange(m_viewportArguments);
410 }
411
412 void Page::refreshPlugins(bool reload)
413 {
414     if (!allPages)
415         return;
416
417     PluginData::refresh();
418
419     Vector<RefPtr<Frame> > framesNeedingReload;
420
421     HashSet<Page*>::iterator end = allPages->end();
422     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
423         Page* page = *it;
424         
425         // Clear out the page's plug-in data.
426         if (page->m_pluginData)
427             page->m_pluginData = 0;
428
429         if (!reload)
430             continue;
431         
432         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
433             if (frame->loader()->subframeLoader()->containsPlugins())
434                 framesNeedingReload.append(frame);
435         }
436     }
437
438     for (size_t i = 0; i < framesNeedingReload.size(); ++i)
439         framesNeedingReload[i]->loader()->reload();
440 }
441
442 PluginData* Page::pluginData() const
443 {
444     if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
445         return 0;
446     if (!m_pluginData)
447         m_pluginData = PluginData::create(this);
448     return m_pluginData.get();
449 }
450
451 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
452 {
453     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
454         if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
455             return listener;
456     }
457     return 0;
458 }
459
460 void Page::setCanStartMedia(bool canStartMedia)
461 {
462     if (m_canStartMedia == canStartMedia)
463         return;
464
465     m_canStartMedia = canStartMedia;
466
467     while (m_canStartMedia) {
468         MediaCanStartListener* listener = takeAnyMediaCanStartListener();
469         if (!listener)
470             break;
471         listener->mediaCanStart();
472     }
473 }
474
475 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
476 {
477     return forward
478         ? curr->tree()->traverseNextWithWrap(wrapFlag)
479         : curr->tree()->traversePreviousWithWrap(wrapFlag);
480 }
481
482 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
483 {
484     return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
485 }
486
487 bool Page::findString(const String& target, FindOptions options)
488 {
489     if (target.isEmpty() || !mainFrame())
490         return false;
491
492     bool shouldWrap = options & WrapAround;
493     Frame* frame = focusController()->focusedOrMainFrame();
494     Frame* startFrame = frame;
495     do {
496         if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
497             if (frame != startFrame)
498                 startFrame->selection()->clear();
499             focusController()->setFocusedFrame(frame);
500             return true;
501         }
502         frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
503     } while (frame && frame != startFrame);
504
505     // Search contents of startFrame, on the other side of the selection that we did earlier.
506     // We cheat a bit and just research with wrap on
507     if (shouldWrap && !startFrame->selection()->isNone()) {
508         bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection);
509         focusController()->setFocusedFrame(frame);
510         return found;
511     }
512
513     return false;
514 }
515
516 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
517 {
518     return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
519 }
520
521 unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
522 {
523     if (target.isEmpty() || !mainFrame())
524         return 0;
525
526     unsigned matches = 0;
527
528     Frame* frame = mainFrame();
529     do {
530         frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
531         matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true);
532         frame = incrementFrame(frame, true, false);
533     } while (frame);
534
535     return matches;
536 }
537
538 void Page::unmarkAllTextMatches()
539 {
540     if (!mainFrame())
541         return;
542
543     Frame* frame = mainFrame();
544     do {
545         frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
546         frame = incrementFrame(frame, true, false);
547     } while (frame);
548 }
549
550 const VisibleSelection& Page::selection() const
551 {
552     return focusController()->focusedOrMainFrame()->selection()->selection();
553 }
554
555 void Page::setDefersLoading(bool defers)
556 {
557     if (!m_settings->loadDeferringEnabled())
558         return;
559
560     if (defers == m_defersLoading)
561         return;
562
563     m_defersLoading = defers;
564     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
565         frame->loader()->setDefersLoading(defers);
566 }
567
568 void Page::clearUndoRedoOperations()
569 {
570     m_editorClient->clearUndoRedoOperations();
571 }
572
573 bool Page::inLowQualityImageInterpolationMode() const
574 {
575     return m_inLowQualityInterpolationMode;
576 }
577
578 void Page::setInLowQualityImageInterpolationMode(bool mode)
579 {
580     m_inLowQualityInterpolationMode = mode;
581 }
582
583 void Page::setMediaVolume(float volume)
584 {
585     if (volume < 0 || volume > 1)
586         return;
587
588     if (m_mediaVolume == volume)
589         return;
590
591     m_mediaVolume = volume;
592     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
593         frame->document()->mediaVolumeDidChange();
594     }
595 }
596
597 void Page::didMoveOnscreen()
598 {
599     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
600         if (frame->view())
601             frame->view()->didMoveOnscreen();
602     }
603 }
604
605 void Page::willMoveOffscreen()
606 {
607     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
608         if (frame->view())
609             frame->view()->willMoveOffscreen();
610     }
611 }
612
613 void Page::userStyleSheetLocationChanged()
614 {
615     // FIXME: Eventually we will move to a model of just being handed the sheet
616     // text instead of loading the URL ourselves.
617     KURL url = m_settings->userStyleSheetLocation();
618     if (url.isLocalFile())
619         m_userStyleSheetPath = url.fileSystemPath();
620     else
621         m_userStyleSheetPath = String();
622
623     m_didLoadUserStyleSheet = false;
624     m_userStyleSheet = String();
625     m_userStyleSheetModificationTime = 0;
626
627     // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
628     // synchronously and avoid using a loader. 
629     if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
630         m_didLoadUserStyleSheet = true;
631
632         Vector<char> styleSheetAsUTF8;
633         if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, IgnoreWhitespace))
634             m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
635     }
636
637     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
638         if (frame->document())
639             frame->document()->updatePageUserSheet();
640     }
641 }
642
643 const String& Page::userStyleSheet() const
644 {
645     if (m_userStyleSheetPath.isEmpty())
646         return m_userStyleSheet;
647
648     time_t modTime;
649     if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
650         // The stylesheet either doesn't exist, was just deleted, or is
651         // otherwise unreadable. If we've read the stylesheet before, we should
652         // throw away that data now as it no longer represents what's on disk.
653         m_userStyleSheet = String();
654         return m_userStyleSheet;
655     }
656
657     // If the stylesheet hasn't changed since the last time we read it, we can
658     // just return the old data.
659     if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
660         return m_userStyleSheet;
661
662     m_didLoadUserStyleSheet = true;
663     m_userStyleSheet = String();
664     m_userStyleSheetModificationTime = modTime;
665
666     // FIXME: It would be better to load this asynchronously to avoid blocking
667     // the process, but we will first need to create an asynchronous loading
668     // mechanism that is not tied to a particular Frame. We will also have to
669     // determine what our behavior should be before the stylesheet is loaded
670     // and what should happen when it finishes loading, especially with respect
671     // to when the load event fires, when Document::close is called, and when
672     // layout/paint are allowed to happen.
673     RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
674     if (!data)
675         return m_userStyleSheet;
676
677     RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
678     m_userStyleSheet = decoder->decode(data->data(), data->size());
679     m_userStyleSheet += decoder->flush();
680
681     return m_userStyleSheet;
682 }
683
684 void Page::removeAllVisitedLinks()
685 {
686     if (!allPages)
687         return;
688     HashSet<PageGroup*> groups;
689     HashSet<Page*>::iterator pagesEnd = allPages->end();
690     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
691         if (PageGroup* group = (*it)->groupPtr())
692             groups.add(group);
693     }
694     HashSet<PageGroup*>::iterator groupsEnd = groups.end();
695     for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
696         (*it)->removeVisitedLinks();
697 }
698
699 void Page::allVisitedStateChanged(PageGroup* group)
700 {
701     ASSERT(group);
702     if (!allPages)
703         return;
704
705     HashSet<Page*>::iterator pagesEnd = allPages->end();
706     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
707         Page* page = *it;
708         if (page->m_group != group)
709             continue;
710         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
711             if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
712                 styleSelector->allVisitedStateChanged();
713         }
714     }
715 }
716
717 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
718 {
719     ASSERT(group);
720     if (!allPages)
721         return;
722
723     HashSet<Page*>::iterator pagesEnd = allPages->end();
724     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
725         Page* page = *it;
726         if (page->m_group != group)
727             continue;
728         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
729             if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
730                 styleSelector->visitedStateChanged(visitedLinkHash);
731         }
732     }
733 }
734
735 void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
736 {
737     ASSERT(allPages);
738
739     HashSet<Page*>::iterator end = allPages->end();
740     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
741         (*it)->setDebugger(debugger);
742 }
743
744 void Page::setDebugger(JSC::Debugger* debugger)
745 {
746     if (m_debugger == debugger)
747         return;
748
749     m_debugger = debugger;
750
751     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
752         frame->script()->attachDebugger(m_debugger);
753 }
754
755 SharedGraphicsContext3D* Page::sharedGraphicsContext3D()
756 {
757 #if ENABLE(ACCELERATED_2D_CANVAS)
758     if (!m_sharedGraphicsContext3D)
759 #if USE(SKIA)
760         // Temporary code to postpone massive test rebaselining
761         m_sharedGraphicsContext3D = SharedGraphicsContext3D::create(chrome(), settings()->legacyAccelerated2dCanvasEnabled() ? 0 : SharedGraphicsContext3D::UseSkiaGPU);
762 #else
763         m_sharedGraphicsContext3D = SharedGraphicsContext3D::create(chrome(), 0);
764 #endif
765     return m_sharedGraphicsContext3D.get();
766 #else // !ENABLE(ACCELERATED_2D_CANVAS)
767     return 0;
768 #endif
769 }
770
771 #if ENABLE(DOM_STORAGE)
772 StorageNamespace* Page::sessionStorage(bool optionalCreate)
773 {
774     if (!m_sessionStorage && optionalCreate)
775         m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
776
777     return m_sessionStorage.get();
778 }
779
780 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
781 {
782     m_sessionStorage = newStorage;
783 }
784 #endif
785
786 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
787 {
788     if (customHTMLTokenizerTimeDelay < 0) {
789         m_customHTMLTokenizerTimeDelay = -1;
790         return;
791     }
792     m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
793 }
794
795 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
796 {
797     if (customHTMLTokenizerChunkSize < 0) {
798         m_customHTMLTokenizerChunkSize = -1;
799         return;
800     }
801     m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
802 }
803
804 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
805 {
806     if (m_areMemoryCacheClientCallsEnabled == enabled)
807         return;
808
809     m_areMemoryCacheClientCallsEnabled = enabled;
810     if (!enabled)
811         return;
812
813     for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
814         frame->loader()->tellClientAboutPastMemoryCacheLoads();
815 }
816
817 void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
818 {
819     m_javaScriptURLsAreAllowed = areAllowed;
820 }
821
822 bool Page::javaScriptURLsAreAllowed() const
823 {
824     return m_javaScriptURLsAreAllowed;
825 }
826
827 void Page::setMinimumTimerInterval(double minimumTimerInterval)
828 {
829     double oldTimerInterval = m_minimumTimerInterval;
830     m_minimumTimerInterval = minimumTimerInterval;
831     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) {
832         if (frame->document())
833             frame->document()->adjustMinimumTimerInterval(oldTimerInterval);
834     }
835 }
836
837 double Page::minimumTimerInterval() const
838 {
839     return m_minimumTimerInterval;
840 }
841
842 #if ENABLE(INPUT_SPEECH)
843 SpeechInput* Page::speechInput()
844 {
845     ASSERT(m_speechInputClient);
846     if (!m_speechInput.get())
847         m_speechInput = adoptPtr(new SpeechInput(m_speechInputClient));
848     return m_speechInput.get();
849 }
850 #endif
851
852 void Page::dnsPrefetchingStateChanged()
853 {
854     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
855         frame->document()->initDNSPrefetch();
856 }
857
858 void Page::privateBrowsingStateChanged()
859 {
860     bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
861
862     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
863         frame->document()->privateBrowsingStateDidChange();
864
865     // Collect the PluginViews in to a vector to ensure that action the plug-in takes
866     // from below privateBrowsingStateChanged does not affect their lifetime.
867     Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
868     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
869         FrameView* view = frame->view();
870         if (!view)
871             return;
872
873         const HashSet<RefPtr<Widget> >* children = view->children();
874         ASSERT(children);
875
876         HashSet<RefPtr<Widget> >::const_iterator end = children->end();
877         for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
878             Widget* widget = (*it).get();
879             if (widget->isPluginViewBase())
880                 pluginViewBases.append(static_cast<PluginViewBase*>(widget));
881         }
882     }
883
884     for (size_t i = 0; i < pluginViewBases.size(); ++i)
885         pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
886 }
887
888 void Page::pluginAllowedRunTimeChanged()
889 {
890     if (m_pluginHalter)
891         m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
892 }
893
894 void Page::didStartPlugin(HaltablePlugin* obj)
895 {
896     if (m_pluginHalter)
897         m_pluginHalter->didStartPlugin(obj);
898 }
899
900 void Page::didStopPlugin(HaltablePlugin* obj)
901 {
902     if (m_pluginHalter)
903         m_pluginHalter->didStopPlugin(obj);
904 }
905
906 void Page::addScrollableArea(ScrollableArea* scrollableArea)
907 {
908     if (!m_scrollableAreaSet)
909         m_scrollableAreaSet = adoptPtr(new ScrollableAreaSet);
910     m_scrollableAreaSet->add(scrollableArea);
911 }
912
913 void Page::removeScrollableArea(ScrollableArea* scrollableArea)
914 {
915     if (!m_scrollableAreaSet)
916         return;
917     m_scrollableAreaSet->remove(scrollableArea);
918 }
919
920 bool Page::containsScrollableArea(ScrollableArea* scrollableArea) const
921 {
922     if (!m_scrollableAreaSet)
923         return false;
924     return m_scrollableAreaSet->contains(scrollableArea);
925 }
926
927 #if !ASSERT_DISABLED
928 void Page::checkFrameCountConsistency() const
929 {
930     ASSERT(m_frameCount >= 0);
931
932     int frameCount = 0;
933     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
934         ++frameCount;
935
936     ASSERT(m_frameCount + 1 == frameCount);
937 }
938 #endif
939
940 #if ENABLE(PAGE_VISIBILITY_API)
941 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
942 {
943     if (m_visibilityState == visibilityState)
944         return;
945     m_visibilityState = visibilityState;
946
947     if (!isInitialState && m_mainFrame)
948         m_mainFrame->dispatchVisibilityStateChangeEvent();
949 }
950
951 PageVisibilityState Page::visibilityState() const
952 {
953     return m_visibilityState;
954 }
955 #endif
956
957 Page::PageClients::PageClients()
958     : chromeClient(0)
959     , contextMenuClient(0)
960     , editorClient(0)
961     , dragClient(0)
962     , inspectorClient(0)
963     , pluginHalterClient(0)
964     , geolocationClient(0)
965     , deviceMotionClient(0)
966     , deviceOrientationClient(0)
967     , speechInputClient(0)
968     , mediaStreamClient(0)
969 {
970 }
971
972 Page::PageClients::~PageClients()
973 {
974 }
975
976 } // namespace WebCore