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