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