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