https://bugs.webkit.org/show_bug.cgi?id=77383
[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 "Navigator.h"
55 #include "NetworkStateNotifier.h"
56 #include "NotificationController.h"
57 #include "NotificationPresenter.h"
58 #include "PageGroup.h"
59 #include "PluginData.h"
60 #include "PluginView.h"
61 #include "PluginViewBase.h"
62 #include "PointerLockController.h"
63 #include "ProgressTracker.h"
64 #include "RenderTheme.h"
65 #include "RenderView.h"
66 #include "RenderWidget.h"
67 #include "RuntimeEnabledFeatures.h"
68 #include "SchemeRegistry.h"
69 #include "Settings.h"
70 #include "SharedBuffer.h"
71 #include "SpeechInput.h"
72 #include "SpeechInputClient.h"
73 #include "StorageArea.h"
74 #include "StorageNamespace.h"
75 #include "TextResourceDecoder.h"
76 #include "Widget.h"
77 #include <wtf/HashMap.h>
78 #include <wtf/RefCountedLeakCounter.h>
79 #include <wtf/StdLibExtras.h>
80 #include <wtf/text/StringHash.h>
81
82 #if ENABLE(CLIENT_BASED_GEOLOCATION)
83 #include "GeolocationController.h"
84 #endif
85
86 #if ENABLE(MEDIA_STREAM)
87 #include "UserMediaClient.h"
88 #endif
89
90 #if ENABLE(THREADED_SCROLLING)
91 #include "ScrollingCoordinator.h"
92 #endif
93
94 namespace WebCore {
95
96 static HashSet<Page*>* allPages;
97
98 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
99
100 static void networkStateChanged()
101 {
102     Vector<RefPtr<Frame> > frames;
103     
104     // Get all the frames of all the pages in all the page groups
105     HashSet<Page*>::iterator end = allPages->end();
106     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
107         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
108             frames.append(frame);
109         InspectorInstrumentation::networkStateChanged(*it);
110     }
111
112     AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
113     for (unsigned i = 0; i < frames.size(); i++)
114         frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
115 }
116
117 float deviceScaleFactor(Frame* frame)
118 {
119     if (!frame)
120         return 1;
121     Page* page = frame->page();
122     if (!page)
123         return 1;
124     return page->deviceScaleFactor();
125 }
126
127 Page::Page(PageClients& pageClients)
128     : m_chrome(Chrome::create(this, pageClients.chromeClient))
129     , m_dragCaretController(DragCaretController::create())
130 #if ENABLE(DRAG_SUPPORT)
131     , m_dragController(DragController::create(this, pageClients.dragClient))
132 #endif
133     , m_focusController(FocusController::create(this))
134 #if ENABLE(CONTEXT_MENUS)
135     , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
136 #endif
137 #if ENABLE(INSPECTOR)
138     , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
139 #endif
140 #if ENABLE(CLIENT_BASED_GEOLOCATION)
141     , m_geolocationController(GeolocationController::create(this, pageClients.geolocationClient))
142 #endif
143 #if ENABLE(DEVICE_ORIENTATION)
144     , m_deviceMotionController(RuntimeEnabledFeatures::deviceMotionEnabled() ? DeviceMotionController::create(pageClients.deviceMotionClient) : nullptr)
145     , m_deviceOrientationController(RuntimeEnabledFeatures::deviceOrientationEnabled() ? DeviceOrientationController::create(this, pageClients.deviceOrientationClient) : nullptr)
146 #endif
147 #if ENABLE(NOTIFICATIONS)
148     , m_notificationController(NotificationController::create(this, pageClients.notificationClient))
149 #endif
150 #if ENABLE(POINTER_LOCK)
151     , m_pointerLockController(PointerLockController::create(this))
152 #endif
153 #if ENABLE(INPUT_SPEECH)
154     , m_speechInputClient(pageClients.speechInputClient)
155 #endif
156 #if ENABLE(MEDIA_STREAM)
157     , m_userMediaClient(pageClients.userMediaClient)
158 #endif
159     , m_settings(Settings::create(this))
160     , m_progress(ProgressTracker::create())
161     , m_backForwardController(BackForwardController::create(this, pageClients.backForwardClient))
162     , m_theme(RenderTheme::themeForPage(this))
163     , m_editorClient(pageClients.editorClient)
164     , m_frameCount(0)
165     , m_openedByDOM(false)
166     , m_tabKeyCyclesThroughElements(true)
167     , m_defersLoading(false)
168     , m_inLowQualityInterpolationMode(false)
169     , m_cookieEnabled(true)
170     , m_areMemoryCacheClientCallsEnabled(true)
171     , m_mediaVolume(1)
172     , m_pageScaleFactor(1)
173     , m_deviceScaleFactor(1)
174     , m_javaScriptURLsAreAllowed(true)
175     , m_didLoadUserStyleSheet(false)
176     , m_userStyleSheetModificationTime(0)
177     , m_group(0)
178     , m_debugger(0)
179     , m_customHTMLTokenizerTimeDelay(-1)
180     , m_customHTMLTokenizerChunkSize(-1)
181     , m_canStartMedia(true)
182     , m_viewMode(ViewModeWindowed)
183     , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
184     , m_isEditable(false)
185 #if ENABLE(PAGE_VISIBILITY_API)
186     , m_visibilityState(PageVisibilityStateVisible)
187 #endif
188     , m_displayID(0)
189     , m_isCountingRelevantRepaintedObjects(false)
190 {
191     if (!allPages) {
192         allPages = new HashSet<Page*>;
193         
194         networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
195     }
196
197     ASSERT(!allPages->contains(this));
198     allPages->add(this);
199
200 #ifndef NDEBUG
201     pageCounter.increment();
202 #endif
203 }
204
205 Page::~Page()
206 {
207     m_mainFrame->setView(0);
208     setGroupName(String());
209     allPages->remove(this);
210     
211     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
212         frame->pageDestroyed();
213
214     if (m_scrollableAreaSet) {
215         ScrollableAreaSet::const_iterator end = m_scrollableAreaSet->end(); 
216         for (ScrollableAreaSet::const_iterator it = m_scrollableAreaSet->begin(); it != end; ++it)
217             (*it)->disconnectFromPage();
218     }
219
220     m_editorClient->pageDestroyed();
221
222 #if ENABLE(INSPECTOR)
223     m_inspectorController->inspectedPageDestroyed();
224 #endif
225
226 #if ENABLE(MEDIA_STREAM)
227     if (m_userMediaClient)
228         m_userMediaClient->pageDestroyed();
229 #endif
230
231 #if ENABLE(THREADED_SCROLLING)
232     if (m_scrollingCoordinator)
233         m_scrollingCoordinator->pageDestroyed();
234 #endif
235
236     backForward()->close();
237
238 #ifndef NDEBUG
239     pageCounter.decrement();
240 #endif
241 }
242
243 #if ENABLE(THREADED_SCROLLING)
244 ScrollingCoordinator* Page::scrollingCoordinator()
245 {
246     if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
247         m_scrollingCoordinator = ScrollingCoordinator::create(this);
248
249     return m_scrollingCoordinator.get();
250 }
251 #endif
252
253 struct ViewModeInfo {
254     const char* name;
255     Page::ViewMode type;
256 };
257 static const int viewModeMapSize = 5;
258 static ViewModeInfo viewModeMap[viewModeMapSize] = {
259     {"windowed", Page::ViewModeWindowed},
260     {"floating", Page::ViewModeFloating},
261     {"fullscreen", Page::ViewModeFullscreen},
262     {"maximized", Page::ViewModeMaximized},
263     {"minimized", Page::ViewModeMinimized}
264 };
265
266 Page::ViewMode Page::stringToViewMode(const String& text)
267 {
268     for (int i = 0; i < viewModeMapSize; ++i) {
269         if (text == viewModeMap[i].name)
270             return viewModeMap[i].type;
271     }
272     return Page::ViewModeInvalid;
273 }
274
275 void Page::setViewMode(ViewMode viewMode)
276 {
277     if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
278         return;
279
280     m_viewMode = viewMode;
281
282     if (!m_mainFrame)
283         return;
284
285     if (m_mainFrame->view())
286         m_mainFrame->view()->forceLayout();
287
288     if (m_mainFrame->document())
289         m_mainFrame->document()->styleSelectorChanged(RecalcStyleImmediately);
290 }
291
292 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
293 {
294     ASSERT(!m_mainFrame); // Should only be called during initialization
295     m_mainFrame = mainFrame;
296 }
297
298 bool Page::openedByDOM() const
299 {
300     return m_openedByDOM;
301 }
302
303 void Page::setOpenedByDOM()
304 {
305     m_openedByDOM = true;
306 }
307
308 BackForwardList* Page::backForwardList() const
309 {
310     return m_backForwardController->client();
311 }
312
313 bool Page::goBack()
314 {
315     HistoryItem* item = backForward()->backItem();
316     
317     if (item) {
318         goToItem(item, FrameLoadTypeBack);
319         return true;
320     }
321     return false;
322 }
323
324 bool Page::goForward()
325 {
326     HistoryItem* item = backForward()->forwardItem();
327     
328     if (item) {
329         goToItem(item, FrameLoadTypeForward);
330         return true;
331     }
332     return false;
333 }
334
335 bool Page::canGoBackOrForward(int distance) const
336 {
337     if (distance == 0)
338         return true;
339     if (distance > 0 && distance <= backForward()->forwardCount())
340         return true;
341     if (distance < 0 && -distance <= backForward()->backCount())
342         return true;
343     return false;
344 }
345
346 void Page::goBackOrForward(int distance)
347 {
348     if (distance == 0)
349         return;
350
351     HistoryItem* item = backForward()->itemAtIndex(distance);
352     if (!item) {
353         if (distance > 0) {
354             if (int forwardCount = backForward()->forwardCount()) 
355                 item = backForward()->itemAtIndex(forwardCount);
356         } else {
357             if (int backCount = backForward()->backCount())
358                 item = backForward()->itemAtIndex(-backCount);
359         }
360     }
361
362     ASSERT(item);
363     if (!item)
364         return;
365
366     goToItem(item, FrameLoadTypeIndexedBackForward);
367 }
368
369 void Page::goToItem(HistoryItem* item, FrameLoadType type)
370 {
371     // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
372     // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
373     RefPtr<HistoryItem> protector(item);
374
375     if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
376         m_mainFrame->loader()->stopAllLoaders();
377
378     m_mainFrame->loader()->history()->goToItem(item, type);
379 }
380
381 int Page::getHistoryLength()
382 {
383     return backForward()->backCount() + 1 + backForward()->forwardCount();
384 }
385
386 void Page::setGroupName(const String& name)
387 {
388     if (m_group && !m_group->name().isEmpty()) {
389         ASSERT(m_group != m_singlePageGroup.get());
390         ASSERT(!m_singlePageGroup);
391         m_group->removePage(this);
392     }
393
394     if (name.isEmpty())
395         m_group = m_singlePageGroup.get();
396     else {
397         m_singlePageGroup.clear();
398         m_group = PageGroup::pageGroup(name);
399         m_group->addPage(this);
400     }
401 }
402
403 const String& Page::groupName() const
404 {
405     DEFINE_STATIC_LOCAL(String, nullString, ());
406     return m_group ? m_group->name() : nullString;
407 }
408
409 void Page::initGroup()
410 {
411     ASSERT(!m_singlePageGroup);
412     ASSERT(!m_group);
413     m_singlePageGroup = PageGroup::create(this);
414     m_group = m_singlePageGroup.get();
415 }
416
417 void Page::scheduleForcedStyleRecalcForAllPages()
418 {
419     if (!allPages)
420         return;
421     HashSet<Page*>::iterator end = allPages->end();
422     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
423         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
424             frame->document()->scheduleForcedStyleRecalc();
425 }
426
427 void Page::setNeedsRecalcStyleInAllFrames()
428 {
429     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
430         frame->document()->styleSelectorChanged(DeferRecalcStyle);
431 }
432
433 void Page::updateViewportArguments()
434 {
435     if (!mainFrame() || !mainFrame()->document())
436         return;
437
438     m_viewportArguments = mainFrame()->document()->viewportArguments();
439     chrome()->dispatchViewportPropertiesDidChange(m_viewportArguments);
440 }
441
442 void Page::refreshPlugins(bool reload)
443 {
444     if (!allPages)
445         return;
446
447     PluginData::refresh();
448
449     Vector<RefPtr<Frame> > framesNeedingReload;
450
451     HashSet<Page*>::iterator end = allPages->end();
452     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
453         Page* page = *it;
454         
455         // Clear out the page's plug-in data.
456         if (page->m_pluginData)
457             page->m_pluginData = 0;
458
459         if (!reload)
460             continue;
461         
462         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
463             if (frame->loader()->subframeLoader()->containsPlugins())
464                 framesNeedingReload.append(frame);
465         }
466     }
467
468     for (size_t i = 0; i < framesNeedingReload.size(); ++i)
469         framesNeedingReload[i]->loader()->reload();
470 }
471
472 PluginData* Page::pluginData() const
473 {
474     if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
475         return 0;
476     if (!m_pluginData)
477         m_pluginData = PluginData::create(this);
478     return m_pluginData.get();
479 }
480
481 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
482 {
483     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
484         if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
485             return listener;
486     }
487     return 0;
488 }
489
490 void Page::setCanStartMedia(bool canStartMedia)
491 {
492     if (m_canStartMedia == canStartMedia)
493         return;
494
495     m_canStartMedia = canStartMedia;
496
497     while (m_canStartMedia) {
498         MediaCanStartListener* listener = takeAnyMediaCanStartListener();
499         if (!listener)
500             break;
501         listener->mediaCanStart();
502     }
503 }
504
505 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
506 {
507     return forward
508         ? curr->tree()->traverseNextWithWrap(wrapFlag)
509         : curr->tree()->traversePreviousWithWrap(wrapFlag);
510 }
511
512 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
513 {
514     return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
515 }
516
517 bool Page::findString(const String& target, FindOptions options)
518 {
519     if (target.isEmpty() || !mainFrame())
520         return false;
521
522     bool shouldWrap = options & WrapAround;
523     Frame* frame = focusController()->focusedOrMainFrame();
524     Frame* startFrame = frame;
525     do {
526         if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
527             if (frame != startFrame)
528                 startFrame->selection()->clear();
529             focusController()->setFocusedFrame(frame);
530             return true;
531         }
532         frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
533     } while (frame && frame != startFrame);
534
535     // Search contents of startFrame, on the other side of the selection that we did earlier.
536     // We cheat a bit and just research with wrap on
537     if (shouldWrap && !startFrame->selection()->isNone()) {
538         bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection);
539         focusController()->setFocusedFrame(frame);
540         return found;
541     }
542
543     return false;
544 }
545
546 PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
547 {
548     if (target.isEmpty() || !mainFrame())
549         return 0;
550
551     if (referenceRange && referenceRange->ownerDocument()->page() != this)
552         return 0;
553
554     bool shouldWrap = options & WrapAround;
555     Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame();
556     Frame* startFrame = frame;
557     do {
558         if (RefPtr<Range> resultRange = frame->editor()->rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
559             return resultRange.release();
560
561         frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
562     } while (frame && frame != startFrame);
563
564     // Search contents of startFrame, on the other side of the reference range that we did earlier.
565     // We cheat a bit and just search again with wrap on.
566     if (shouldWrap && referenceRange) {
567         if (RefPtr<Range> resultRange = startFrame->editor()->rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
568             return resultRange.release();
569     }
570
571     return 0;
572 }
573
574 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
575 {
576     return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
577 }
578
579 unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
580 {
581     if (target.isEmpty() || !mainFrame())
582         return 0;
583
584     unsigned matches = 0;
585
586     Frame* frame = mainFrame();
587     do {
588         frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
589         matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true);
590         frame = incrementFrame(frame, true, false);
591     } while (frame);
592
593     return matches;
594 }
595
596 void Page::unmarkAllTextMatches()
597 {
598     if (!mainFrame())
599         return;
600
601     Frame* frame = mainFrame();
602     do {
603         frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
604         frame = incrementFrame(frame, true, false);
605     } while (frame);
606 }
607
608 const VisibleSelection& Page::selection() const
609 {
610     return focusController()->focusedOrMainFrame()->selection()->selection();
611 }
612
613 void Page::setDefersLoading(bool defers)
614 {
615     if (!m_settings->loadDeferringEnabled())
616         return;
617
618     if (defers == m_defersLoading)
619         return;
620
621     m_defersLoading = defers;
622     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
623         frame->loader()->setDefersLoading(defers);
624 }
625
626 void Page::clearUndoRedoOperations()
627 {
628     m_editorClient->clearUndoRedoOperations();
629 }
630
631 bool Page::inLowQualityImageInterpolationMode() const
632 {
633     return m_inLowQualityInterpolationMode;
634 }
635
636 void Page::setInLowQualityImageInterpolationMode(bool mode)
637 {
638     m_inLowQualityInterpolationMode = mode;
639 }
640
641 void Page::setMediaVolume(float volume)
642 {
643     if (volume < 0 || volume > 1)
644         return;
645
646     if (m_mediaVolume == volume)
647         return;
648
649     m_mediaVolume = volume;
650     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
651         frame->document()->mediaVolumeDidChange();
652     }
653 }
654
655 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
656 {
657     if (scale == m_pageScaleFactor)
658         return;
659
660     Document* document = mainFrame()->document();
661
662     m_pageScaleFactor = scale;
663
664     if (document->renderer())
665         document->renderer()->setNeedsLayout(true);
666
667     document->recalcStyle(Node::Force);
668
669 #if USE(ACCELERATED_COMPOSITING)
670     mainFrame()->deviceOrPageScaleFactorChanged();
671 #endif
672
673     if (FrameView* view = document->view()) {
674         if (view->scrollPosition() != origin) {
675           if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
676               view->layout();
677           view->setScrollPosition(origin);
678         }
679     }
680 }
681
682
683 void Page::setDeviceScaleFactor(float scaleFactor)
684 {
685     if (m_deviceScaleFactor == scaleFactor)
686         return;
687
688     m_deviceScaleFactor = scaleFactor;
689     setNeedsRecalcStyleInAllFrames();
690
691 #if USE(ACCELERATED_COMPOSITING)
692     if (mainFrame())
693         mainFrame()->deviceOrPageScaleFactorChanged();
694 #endif
695
696     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
697         frame->editor()->deviceScaleFactorChanged();
698
699     backForward()->markPagesForFullStyleRecalc();
700 }
701
702 void Page::setPagination(const Pagination& pagination)
703 {
704     if (m_pagination == pagination)
705         return;
706
707     m_pagination = pagination;
708
709     setNeedsRecalcStyleInAllFrames();
710     backForward()->markPagesForFullStyleRecalc();
711 }
712
713 unsigned Page::pageCount() const
714 {
715     if (m_pagination.mode == Pagination::Unpaginated)
716         return 0;
717
718     FrameView* frameView = mainFrame()->view();
719     if (!frameView->didFirstLayout())
720         return 0;
721
722     mainFrame()->view()->forceLayout();
723
724     RenderView* contentRenderer = mainFrame()->contentRenderer();
725     return contentRenderer->columnCount(contentRenderer->columnInfo());
726 }
727
728 void Page::didMoveOnscreen()
729 {
730     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
731         if (frame->view())
732             frame->view()->didMoveOnscreen();
733     }
734     
735     resumeScriptedAnimations();
736 }
737
738 void Page::willMoveOffscreen()
739 {
740     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
741         if (frame->view())
742             frame->view()->willMoveOffscreen();
743     }
744     
745     suspendScriptedAnimations();
746 }
747
748 void Page::windowScreenDidChange(PlatformDisplayID displayID)
749 {
750     m_displayID = displayID;
751     
752     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
753         if (frame->document())
754             frame->document()->windowScreenDidChange(displayID);
755     }
756 }
757
758 void Page::suspendScriptedAnimations()
759 {
760     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
761         if (frame->document())
762             frame->document()->suspendScriptedAnimationControllerCallbacks();
763     }
764 }
765
766 void Page::resumeScriptedAnimations()
767 {
768     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
769         if (frame->document())
770             frame->document()->resumeScriptedAnimationControllerCallbacks();
771     }
772 }
773
774 void Page::userStyleSheetLocationChanged()
775 {
776     // FIXME: Eventually we will move to a model of just being handed the sheet
777     // text instead of loading the URL ourselves.
778     KURL url = m_settings->userStyleSheetLocation();
779     
780     // Allow any local file URL scheme to be loaded.
781     if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
782         m_userStyleSheetPath = url.fileSystemPath();
783     else
784         m_userStyleSheetPath = String();
785
786     m_didLoadUserStyleSheet = false;
787     m_userStyleSheet = String();
788     m_userStyleSheetModificationTime = 0;
789
790     // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
791     // synchronously and avoid using a loader. 
792     if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
793         m_didLoadUserStyleSheet = true;
794
795         Vector<char> styleSheetAsUTF8;
796         if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, IgnoreWhitespace))
797             m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
798     }
799
800     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
801         if (frame->document())
802             frame->document()->updatePageUserSheet();
803     }
804 }
805
806 const String& Page::userStyleSheet() const
807 {
808     if (m_userStyleSheetPath.isEmpty())
809         return m_userStyleSheet;
810
811     time_t modTime;
812     if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
813         // The stylesheet either doesn't exist, was just deleted, or is
814         // otherwise unreadable. If we've read the stylesheet before, we should
815         // throw away that data now as it no longer represents what's on disk.
816         m_userStyleSheet = String();
817         return m_userStyleSheet;
818     }
819
820     // If the stylesheet hasn't changed since the last time we read it, we can
821     // just return the old data.
822     if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
823         return m_userStyleSheet;
824
825     m_didLoadUserStyleSheet = true;
826     m_userStyleSheet = String();
827     m_userStyleSheetModificationTime = modTime;
828
829     // FIXME: It would be better to load this asynchronously to avoid blocking
830     // the process, but we will first need to create an asynchronous loading
831     // mechanism that is not tied to a particular Frame. We will also have to
832     // determine what our behavior should be before the stylesheet is loaded
833     // and what should happen when it finishes loading, especially with respect
834     // to when the load event fires, when Document::close is called, and when
835     // layout/paint are allowed to happen.
836     RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
837     if (!data)
838         return m_userStyleSheet;
839
840     RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
841     m_userStyleSheet = decoder->decode(data->data(), data->size());
842     m_userStyleSheet += decoder->flush();
843
844     return m_userStyleSheet;
845 }
846
847 void Page::removeAllVisitedLinks()
848 {
849     if (!allPages)
850         return;
851     HashSet<PageGroup*> groups;
852     HashSet<Page*>::iterator pagesEnd = allPages->end();
853     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
854         if (PageGroup* group = (*it)->groupPtr())
855             groups.add(group);
856     }
857     HashSet<PageGroup*>::iterator groupsEnd = groups.end();
858     for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
859         (*it)->removeVisitedLinks();
860 }
861
862 void Page::allVisitedStateChanged(PageGroup* group)
863 {
864     ASSERT(group);
865     if (!allPages)
866         return;
867
868     HashSet<Page*>::iterator pagesEnd = allPages->end();
869     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
870         Page* page = *it;
871         if (page->m_group != group)
872             continue;
873         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
874             if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
875                 styleSelector->allVisitedStateChanged();
876         }
877     }
878 }
879
880 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
881 {
882     ASSERT(group);
883     if (!allPages)
884         return;
885
886     HashSet<Page*>::iterator pagesEnd = allPages->end();
887     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
888         Page* page = *it;
889         if (page->m_group != group)
890             continue;
891         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
892             if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
893                 styleSelector->visitedStateChanged(visitedLinkHash);
894         }
895     }
896 }
897
898 void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
899 {
900     ASSERT(allPages);
901
902     HashSet<Page*>::iterator end = allPages->end();
903     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
904         (*it)->setDebugger(debugger);
905 }
906
907 void Page::setDebugger(JSC::Debugger* debugger)
908 {
909     if (m_debugger == debugger)
910         return;
911
912     m_debugger = debugger;
913
914     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
915         frame->script()->attachDebugger(m_debugger);
916 }
917
918 StorageNamespace* Page::sessionStorage(bool optionalCreate)
919 {
920     if (!m_sessionStorage && optionalCreate)
921         m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
922
923     return m_sessionStorage.get();
924 }
925
926 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
927 {
928     m_sessionStorage = newStorage;
929 }
930
931 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
932 {
933     if (customHTMLTokenizerTimeDelay < 0) {
934         m_customHTMLTokenizerTimeDelay = -1;
935         return;
936     }
937     m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
938 }
939
940 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
941 {
942     if (customHTMLTokenizerChunkSize < 0) {
943         m_customHTMLTokenizerChunkSize = -1;
944         return;
945     }
946     m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
947 }
948
949 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
950 {
951     if (m_areMemoryCacheClientCallsEnabled == enabled)
952         return;
953
954     m_areMemoryCacheClientCallsEnabled = enabled;
955     if (!enabled)
956         return;
957
958     for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
959         frame->loader()->tellClientAboutPastMemoryCacheLoads();
960 }
961
962 void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
963 {
964     m_javaScriptURLsAreAllowed = areAllowed;
965 }
966
967 bool Page::javaScriptURLsAreAllowed() const
968 {
969     return m_javaScriptURLsAreAllowed;
970 }
971
972 void Page::setMinimumTimerInterval(double minimumTimerInterval)
973 {
974     double oldTimerInterval = m_minimumTimerInterval;
975     m_minimumTimerInterval = minimumTimerInterval;
976     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) {
977         if (frame->document())
978             frame->document()->adjustMinimumTimerInterval(oldTimerInterval);
979     }
980 }
981
982 double Page::minimumTimerInterval() const
983 {
984     return m_minimumTimerInterval;
985 }
986
987 #if ENABLE(INPUT_SPEECH)
988 SpeechInput* Page::speechInput()
989 {
990     ASSERT(m_speechInputClient);
991     if (!m_speechInput.get())
992         m_speechInput = SpeechInput::create(m_speechInputClient);
993     return m_speechInput.get();
994 }
995 #endif
996
997 void Page::dnsPrefetchingStateChanged()
998 {
999     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1000         frame->document()->initDNSPrefetch();
1001 }
1002
1003 void Page::privateBrowsingStateChanged()
1004 {
1005     bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
1006
1007     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1008         frame->document()->privateBrowsingStateDidChange();
1009
1010     // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1011     // from below privateBrowsingStateChanged does not affect their lifetime.
1012     Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
1013     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
1014         FrameView* view = frame->view();
1015         if (!view)
1016             return;
1017
1018         const HashSet<RefPtr<Widget> >* children = view->children();
1019         ASSERT(children);
1020
1021         HashSet<RefPtr<Widget> >::const_iterator end = children->end();
1022         for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
1023             Widget* widget = (*it).get();
1024             if (widget->isPluginViewBase())
1025                 pluginViewBases.append(static_cast<PluginViewBase*>(widget));
1026         }
1027     }
1028
1029     for (size_t i = 0; i < pluginViewBases.size(); ++i)
1030         pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
1031 }
1032
1033 void Page::addScrollableArea(ScrollableArea* scrollableArea)
1034 {
1035     if (!m_scrollableAreaSet)
1036         m_scrollableAreaSet = adoptPtr(new ScrollableAreaSet);
1037     m_scrollableAreaSet->add(scrollableArea);
1038 }
1039
1040 void Page::removeScrollableArea(ScrollableArea* scrollableArea)
1041 {
1042     if (!m_scrollableAreaSet)
1043         return;
1044     m_scrollableAreaSet->remove(scrollableArea);
1045 }
1046
1047 bool Page::containsScrollableArea(ScrollableArea* scrollableArea) const
1048 {
1049     if (!m_scrollableAreaSet)
1050         return false;
1051     return m_scrollableAreaSet->contains(scrollableArea);
1052 }
1053
1054 #if !ASSERT_DISABLED
1055 void Page::checkFrameCountConsistency() const
1056 {
1057     ASSERT(m_frameCount >= 0);
1058
1059     int frameCount = 0;
1060     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1061         ++frameCount;
1062
1063     ASSERT(m_frameCount + 1 == frameCount);
1064 }
1065 #endif
1066
1067 #if ENABLE(PAGE_VISIBILITY_API)
1068 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
1069 {
1070     if (m_visibilityState == visibilityState)
1071         return;
1072     m_visibilityState = visibilityState;
1073
1074     if (!isInitialState && m_mainFrame)
1075         m_mainFrame->dispatchVisibilityStateChangeEvent();
1076 }
1077
1078 PageVisibilityState Page::visibilityState() const
1079 {
1080     return m_visibilityState;
1081 }
1082 #endif
1083
1084 static uint64_t gPaintedObjectCounterThreshold = 0;
1085
1086 void Page::setRelevantRepaintedObjectsCounterThreshold(uint64_t threshold)
1087 {
1088     gPaintedObjectCounterThreshold = threshold;
1089 }
1090
1091 void Page::startCountingRelevantRepaintedObjects()
1092 {
1093     m_isCountingRelevantRepaintedObjects = true;
1094
1095     // Clear the HashSet in case we didn't hit the threshold last time.
1096     m_relevantPaintedRenderObjects.clear();
1097 }
1098
1099 void Page::addRelevantRepaintedObject(RenderObject* object, const IntRect& objectPaintRect)
1100 {
1101     if (!m_isCountingRelevantRepaintedObjects)
1102         return;
1103
1104     // We don't need to do anything if there is no counter threshold.
1105     if (!gPaintedObjectCounterThreshold)
1106         return;
1107
1108     // The objects are only relevant if they are being painted within the viewRect().
1109     if (RenderView* view = object->view()) {
1110         if (!objectPaintRect.intersects(view->viewRect()))
1111             return;
1112     }
1113
1114     m_relevantPaintedRenderObjects.add(object);
1115
1116     if (m_relevantPaintedRenderObjects.size() == static_cast<int>(gPaintedObjectCounterThreshold)) {
1117         m_isCountingRelevantRepaintedObjects = false;
1118         m_relevantPaintedRenderObjects.clear();
1119         if (Frame* frame = mainFrame())
1120             frame->loader()->didNewFirstVisuallyNonEmptyLayout();
1121     }
1122 }
1123
1124 Page::PageClients::PageClients()
1125     : chromeClient(0)
1126     , contextMenuClient(0)
1127     , editorClient(0)
1128     , dragClient(0)
1129     , inspectorClient(0)
1130     , geolocationClient(0)
1131     , deviceMotionClient(0)
1132     , deviceOrientationClient(0)
1133     , speechInputClient(0)
1134     , notificationClient(0)
1135     , userMediaClient(0)
1136 {
1137 }
1138
1139 Page::PageClients::~PageClients()
1140 {
1141 }
1142
1143 } // namespace WebCore