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/)
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.
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.
23 #include "AlternativeTextClient.h"
24 #include "BackForwardController.h"
25 #include "BackForwardList.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"
35 #include "EventNames.h"
36 #include "ExceptionCode.h"
37 #include "FileSystem.h"
38 #include "FocusController.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"
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"
69 #include "SharedBuffer.h"
70 #include "StorageArea.h"
71 #include "StorageNamespace.h"
72 #include "StyleResolver.h"
73 #include "TextResourceDecoder.h"
74 #include "VoidCallback.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>
84 #if ENABLE(TIZEN_NATIVE_MEMORY_SNAPSHOT)
85 HashSet<Page*>* allPages;
87 static HashSet<Page*>* allPages;
89 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
91 static void networkStateChanged()
93 Vector<RefPtr<Frame> > frames;
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())
100 InspectorInstrumentation::networkStateChanged(*it);
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));
108 float deviceScaleFactor(Frame* frame)
112 Page* page = frame->page();
115 return page->deviceScaleFactor();
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))
124 , m_focusController(FocusController::create(this))
125 #if ENABLE(CONTEXT_MENUS)
126 , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
128 #if ENABLE(INSPECTOR)
129 , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
131 #if ENABLE(POINTER_LOCK)
132 , m_pointerLockController(PointerLockController::create(this))
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)
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)
148 , m_pageScaleFactor(1)
149 , m_deviceScaleFactor(1)
150 , m_javaScriptURLsAreAllowed(true)
151 , m_didLoadUserStyleSheet(false)
152 , m_userStyleSheetModificationTime(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)
162 #if ENABLE(PAGE_VISIBILITY_API)
163 , m_visibilityState(PageVisibilityStateVisible)
166 , m_isCountingRelevantRepaintedObjects(false)
167 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
168 , m_recordingSurfaceSetEnable(false)
171 , m_isPainting(false)
173 , m_alternativeTextClient(pageClients.alternativeTextClient)
174 , m_scriptedAnimationsSuspended(false)
176 ASSERT(m_editorClient);
179 allPages = new HashSet<Page*>;
181 networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
184 ASSERT(!allPages->contains(this));
188 pageCounter.increment();
194 m_mainFrame->setView(0);
195 setGroupName(String());
196 allPages->remove(this);
198 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
199 frame->willDetachPage();
200 frame->detachFromPage();
203 m_editorClient->pageDestroyed();
204 if (m_alternativeTextClient)
205 m_alternativeTextClient->pageDestroyed();
207 #if ENABLE(INSPECTOR)
208 m_inspectorController->inspectedPageDestroyed();
211 if (m_scrollingCoordinator)
212 m_scrollingCoordinator->pageDestroyed();
214 backForward()->close();
217 pageCounter.decrement();
222 ArenaSize Page::renderTreeSize() const
224 ArenaSize total(0, 0);
225 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
226 if (!frame->document())
228 if (RenderArena* arena = frame->document()->renderArena()) {
229 total.treeSize += arena->totalRenderArenaSize();
230 total.allocated += arena->totalRenderArenaAllocatedBytes();
236 ViewportArguments Page::viewportArguments() const
238 return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportArguments() : ViewportArguments();
241 ScrollingCoordinator* Page::scrollingCoordinator()
243 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
244 m_scrollingCoordinator = ScrollingCoordinator::create(this);
246 return m_scrollingCoordinator.get();
249 struct ViewModeInfo {
253 static const int viewModeMapSize = 5;
254 static ViewModeInfo viewModeMap[viewModeMapSize] = {
255 {"windowed", Page::ViewModeWindowed},
256 {"floating", Page::ViewModeFloating},
257 {"fullscreen", Page::ViewModeFullscreen},
258 {"maximized", Page::ViewModeMaximized},
259 {"minimized", Page::ViewModeMinimized}
262 Page::ViewMode Page::stringToViewMode(const String& text)
264 for (int i = 0; i < viewModeMapSize; ++i) {
265 if (text == viewModeMap[i].name)
266 return viewModeMap[i].type;
268 return Page::ViewModeInvalid;
271 void Page::setViewMode(ViewMode viewMode)
273 if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
276 m_viewMode = viewMode;
281 if (m_mainFrame->view())
282 m_mainFrame->view()->forceLayout();
284 if (m_mainFrame->document())
285 m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately);
288 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
290 ASSERT(!m_mainFrame); // Should only be called during initialization
291 m_mainFrame = mainFrame;
294 bool Page::openedByDOM() const
296 return m_openedByDOM;
299 void Page::setOpenedByDOM()
301 m_openedByDOM = true;
304 BackForwardList* Page::backForwardList() const
306 return m_backForwardController->client();
311 HistoryItem* item = backForward()->backItem();
314 goToItem(item, FrameLoadTypeBack);
320 bool Page::goForward()
322 HistoryItem* item = backForward()->forwardItem();
325 goToItem(item, FrameLoadTypeForward);
331 bool Page::canGoBackOrForward(int distance) const
335 if (distance > 0 && distance <= backForward()->forwardCount())
337 if (distance < 0 && -distance <= backForward()->backCount())
342 void Page::goBackOrForward(int distance)
347 HistoryItem* item = backForward()->itemAtIndex(distance);
350 if (int forwardCount = backForward()->forwardCount())
351 item = backForward()->itemAtIndex(forwardCount);
353 if (int backCount = backForward()->backCount())
354 item = backForward()->itemAtIndex(-backCount);
361 goToItem(item, FrameLoadTypeIndexedBackForward);
364 void Page::goToItem(HistoryItem* item, FrameLoadType type)
366 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
367 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
368 RefPtr<HistoryItem> protector(item);
370 if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
371 m_mainFrame->loader()->stopAllLoaders();
373 m_mainFrame->loader()->history()->goToItem(item, type);
376 int Page::getHistoryLength()
378 return backForward()->backCount() + 1 + backForward()->forwardCount();
381 void Page::setGroupName(const String& name)
383 if (m_group && !m_group->name().isEmpty()) {
384 ASSERT(m_group != m_singlePageGroup.get());
385 ASSERT(!m_singlePageGroup);
386 m_group->removePage(this);
390 m_group = m_singlePageGroup.get();
392 m_singlePageGroup.clear();
393 m_group = PageGroup::pageGroup(name);
394 m_group->addPage(this);
398 const String& Page::groupName() const
400 DEFINE_STATIC_LOCAL(String, nullString, ());
401 return m_group ? m_group->name() : nullString;
404 void Page::initGroup()
406 ASSERT(!m_singlePageGroup);
408 m_singlePageGroup = PageGroup::create(this);
409 m_group = m_singlePageGroup.get();
412 void Page::scheduleForcedStyleRecalcForAllPages()
416 HashSet<Page*>::iterator end = allPages->end();
417 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
418 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
419 frame->document()->scheduleForcedStyleRecalc();
422 void Page::setNeedsRecalcStyleInAllFrames()
424 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
425 frame->document()->styleResolverChanged(DeferRecalcStyle);
428 void Page::refreshPlugins(bool reload)
433 PluginData::refresh();
435 Vector<RefPtr<Frame> > framesNeedingReload;
437 HashSet<Page*>::iterator end = allPages->end();
438 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
441 // Clear out the page's plug-in data.
442 if (page->m_pluginData)
443 page->m_pluginData = 0;
448 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
449 if (frame->loader()->subframeLoader()->containsPlugins())
450 framesNeedingReload.append(frame);
454 for (size_t i = 0; i < framesNeedingReload.size(); ++i)
455 framesNeedingReload[i]->loader()->reload();
458 PluginData* Page::pluginData() const
460 if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
463 m_pluginData = PluginData::create(this);
464 return m_pluginData.get();
467 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
469 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
470 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
476 void Page::setCanStartMedia(bool canStartMedia)
478 if (m_canStartMedia == canStartMedia)
481 m_canStartMedia = canStartMedia;
483 while (m_canStartMedia) {
484 MediaCanStartListener* listener = takeAnyMediaCanStartListener();
487 listener->mediaCanStart();
491 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
494 ? curr->tree()->traverseNextWithWrap(wrapFlag)
495 : curr->tree()->traversePreviousWithWrap(wrapFlag);
498 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
500 return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
503 bool Page::findString(const String& target, FindOptions options)
505 if (target.isEmpty() || !mainFrame())
508 bool shouldWrap = options & WrapAround;
509 Frame* frame = focusController()->focusedOrMainFrame();
510 Frame* startFrame = frame;
512 if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
513 if (frame != startFrame)
514 startFrame->selection()->clear();
515 focusController()->setFocusedFrame(frame);
518 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
519 } while (frame && frame != startFrame);
521 // Search contents of startFrame, on the other side of the selection that we did earlier.
522 // We cheat a bit and just research with wrap on
523 if (shouldWrap && !startFrame->selection()->isNone()) {
524 bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection);
525 focusController()->setFocusedFrame(frame);
532 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range> >* matchRanges, int& indexForSelection)
534 indexForSelection = 0;
538 Frame* frame = mainFrame();
539 Frame* frameWithSelection = 0;
541 frame->editor()->countMatchesForText(target, 0, options, limit ? (limit - matchRanges->size()) : 0, true, matchRanges);
542 if (frame->selection()->isRange())
543 frameWithSelection = frame;
544 frame = incrementFrame(frame, true, false);
547 if (matchRanges->isEmpty())
550 if (frameWithSelection) {
551 indexForSelection = NoMatchBeforeUserSelection;
552 RefPtr<Range> selectedRange = frameWithSelection->selection()->selection().firstRange();
553 for (size_t i = 0; i < matchRanges->size(); ++i) {
555 if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), ec) < 0) {
556 indexForSelection = i;
563 PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
565 if (target.isEmpty() || !mainFrame())
568 if (referenceRange && referenceRange->ownerDocument()->page() != this)
571 bool shouldWrap = options & WrapAround;
572 Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame();
573 Frame* startFrame = frame;
575 if (RefPtr<Range> resultRange = frame->editor()->rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
576 return resultRange.release();
578 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
579 } while (frame && frame != startFrame);
581 // Search contents of startFrame, on the other side of the reference range that we did earlier.
582 // We cheat a bit and just search again with wrap on.
583 if (shouldWrap && referenceRange) {
584 if (RefPtr<Range> resultRange = startFrame->editor()->rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
585 return resultRange.release();
591 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
593 return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
596 unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
598 if (target.isEmpty() || !mainFrame())
601 unsigned matches = 0;
603 Frame* frame = mainFrame();
605 frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
606 matches += frame->editor()->countMatchesForText(target, 0, options, limit ? (limit - matches) : 0, true, 0);
607 frame = incrementFrame(frame, true, false);
613 void Page::unmarkAllTextMatches()
618 Frame* frame = mainFrame();
620 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
621 frame = incrementFrame(frame, true, false);
625 const VisibleSelection& Page::selection() const
627 return focusController()->focusedOrMainFrame()->selection()->selection();
630 void Page::setDefersLoading(bool defers)
632 if (!m_settings->loadDeferringEnabled())
635 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
636 ASSERT(defers || m_defersLoadingCallCount);
637 if (defers && ++m_defersLoadingCallCount > 1)
639 if (!defers && --m_defersLoadingCallCount)
642 ASSERT(!m_defersLoadingCallCount);
643 if (defers == m_defersLoading)
647 m_defersLoading = defers;
648 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
649 frame->loader()->setDefersLoading(defers);
652 void Page::clearUndoRedoOperations()
654 m_editorClient->clearUndoRedoOperations();
657 bool Page::inLowQualityImageInterpolationMode() const
659 return m_inLowQualityInterpolationMode;
662 void Page::setInLowQualityImageInterpolationMode(bool mode)
664 m_inLowQualityInterpolationMode = mode;
667 void Page::setMediaVolume(float volume)
669 if (volume < 0 || volume > 1)
672 if (m_mediaVolume == volume)
675 m_mediaVolume = volume;
676 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
677 frame->document()->mediaVolumeDidChange();
681 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
683 Document* document = mainFrame()->document();
684 FrameView* view = document->view();
686 if (scale == m_pageScaleFactor) {
687 if (view && view->scrollPosition() != origin) {
688 document->updateLayoutIgnorePendingStylesheets();
689 view->setScrollPosition(origin);
694 m_pageScaleFactor = scale;
696 if (document->renderer())
697 document->renderer()->setNeedsLayout(true);
699 document->recalcStyle(Node::Force);
701 #if USE(ACCELERATED_COMPOSITING)
702 mainFrame()->deviceOrPageScaleFactorChanged();
705 if (view && view->scrollPosition() != origin) {
706 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
708 view->setScrollPosition(origin);
713 void Page::setDeviceScaleFactor(float scaleFactor)
715 if (m_deviceScaleFactor == scaleFactor)
718 m_deviceScaleFactor = scaleFactor;
719 setNeedsRecalcStyleInAllFrames();
721 #if USE(ACCELERATED_COMPOSITING)
723 mainFrame()->deviceOrPageScaleFactorChanged();
726 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
727 frame->editor()->deviceScaleFactorChanged();
729 pageCache()->markPagesForFullStyleRecalc(this);
732 void Page::setPagination(const Pagination& pagination)
734 if (m_pagination == pagination)
737 m_pagination = pagination;
739 setNeedsRecalcStyleInAllFrames();
740 pageCache()->markPagesForFullStyleRecalc(this);
743 unsigned Page::pageCount() const
745 if (m_pagination.mode == Pagination::Unpaginated)
748 FrameView* frameView = mainFrame()->view();
749 if (!frameView->didFirstLayout())
752 mainFrame()->view()->forceLayout();
754 RenderView* contentRenderer = mainFrame()->contentRenderer();
755 return contentRenderer->columnCount(contentRenderer->columnInfo());
758 void Page::didMoveOnscreen()
762 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
763 #if ENABLE(TIZEN_SUSPEND_CSS_ANIMATION_FOR_HIDDEN_PAGE)
764 frame->animation()->resumeAnimationsForDocument(frame->document());
766 if (FrameView* frameView = frame->view())
767 frameView->didMoveOnscreen();
770 resumeScriptedAnimations();
773 void Page::willMoveOffscreen()
775 m_isOnscreen = false;
777 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
778 #if ENABLE(TIZEN_SUSPEND_CSS_ANIMATION_FOR_HIDDEN_PAGE)
779 frame->animation()->suspendAnimationsForDocument(frame->document());
781 if (FrameView* frameView = frame->view())
782 frameView->willMoveOffscreen();
785 suspendScriptedAnimations();
788 void Page::windowScreenDidChange(PlatformDisplayID displayID)
790 m_displayID = displayID;
792 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
793 if (frame->document())
794 frame->document()->windowScreenDidChange(displayID);
798 void Page::suspendScriptedAnimations()
800 m_scriptedAnimationsSuspended = true;
801 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
802 if (frame->document())
803 frame->document()->suspendScriptedAnimationControllerCallbacks();
807 void Page::resumeScriptedAnimations()
809 m_scriptedAnimationsSuspended = false;
810 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
811 if (frame->document())
812 frame->document()->resumeScriptedAnimationControllerCallbacks();
816 void Page::userStyleSheetLocationChanged()
818 // FIXME: Eventually we will move to a model of just being handed the sheet
819 // text instead of loading the URL ourselves.
820 KURL url = m_settings->userStyleSheetLocation();
822 // Allow any local file URL scheme to be loaded.
823 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
824 m_userStyleSheetPath = url.fileSystemPath();
826 m_userStyleSheetPath = String();
828 m_didLoadUserStyleSheet = false;
829 m_userStyleSheet = String();
830 m_userStyleSheetModificationTime = 0;
832 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
833 // synchronously and avoid using a loader.
834 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
835 m_didLoadUserStyleSheet = true;
837 Vector<char> styleSheetAsUTF8;
838 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
839 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
842 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
843 if (frame->document())
844 frame->document()->updatePageUserSheet();
848 const String& Page::userStyleSheet() const
850 if (m_userStyleSheetPath.isEmpty())
851 return m_userStyleSheet;
854 if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
855 // The stylesheet either doesn't exist, was just deleted, or is
856 // otherwise unreadable. If we've read the stylesheet before, we should
857 // throw away that data now as it no longer represents what's on disk.
858 m_userStyleSheet = String();
859 return m_userStyleSheet;
862 // If the stylesheet hasn't changed since the last time we read it, we can
863 // just return the old data.
864 if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
865 return m_userStyleSheet;
867 m_didLoadUserStyleSheet = true;
868 m_userStyleSheet = String();
869 m_userStyleSheetModificationTime = modTime;
871 // FIXME: It would be better to load this asynchronously to avoid blocking
872 // the process, but we will first need to create an asynchronous loading
873 // mechanism that is not tied to a particular Frame. We will also have to
874 // determine what our behavior should be before the stylesheet is loaded
875 // and what should happen when it finishes loading, especially with respect
876 // to when the load event fires, when Document::close is called, and when
877 // layout/paint are allowed to happen.
878 RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
880 return m_userStyleSheet;
882 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
883 m_userStyleSheet = decoder->decode(data->data(), data->size());
884 m_userStyleSheet += decoder->flush();
886 return m_userStyleSheet;
889 void Page::removeAllVisitedLinks()
893 HashSet<PageGroup*> groups;
894 HashSet<Page*>::iterator pagesEnd = allPages->end();
895 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
896 if (PageGroup* group = (*it)->groupPtr())
899 HashSet<PageGroup*>::iterator groupsEnd = groups.end();
900 for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
901 (*it)->removeVisitedLinks();
904 void Page::allVisitedStateChanged(PageGroup* group)
910 HashSet<Page*>::iterator pagesEnd = allPages->end();
911 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
913 if (page->m_group != group)
915 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
916 if (StyleResolver* styleResolver = frame->document()->styleResolver())
917 styleResolver->allVisitedStateChanged();
922 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
928 HashSet<Page*>::iterator pagesEnd = allPages->end();
929 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
931 if (page->m_group != group)
933 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
934 if (StyleResolver* styleResolver = frame->document()->styleResolver())
935 styleResolver->visitedStateChanged(visitedLinkHash);
940 void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
944 HashSet<Page*>::iterator end = allPages->end();
945 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
946 (*it)->setDebugger(debugger);
949 void Page::setDebugger(JSC::Debugger* debugger)
951 if (m_debugger == debugger)
954 m_debugger = debugger;
956 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
957 frame->script()->attachDebugger(m_debugger);
960 StorageNamespace* Page::sessionStorage(bool optionalCreate)
962 if (!m_sessionStorage && optionalCreate)
963 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
965 return m_sessionStorage.get();
968 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
970 m_sessionStorage = newStorage;
973 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
975 if (customHTMLTokenizerTimeDelay < 0) {
976 m_customHTMLTokenizerTimeDelay = -1;
979 m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
982 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
984 if (customHTMLTokenizerChunkSize < 0) {
985 m_customHTMLTokenizerChunkSize = -1;
988 m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
991 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
993 if (m_areMemoryCacheClientCallsEnabled == enabled)
996 m_areMemoryCacheClientCallsEnabled = enabled;
1000 for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1001 frame->loader()->tellClientAboutPastMemoryCacheLoads();
1004 void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
1006 m_javaScriptURLsAreAllowed = areAllowed;
1009 bool Page::javaScriptURLsAreAllowed() const
1011 return m_javaScriptURLsAreAllowed;
1014 void Page::setMinimumTimerInterval(double minimumTimerInterval)
1016 double oldTimerInterval = m_minimumTimerInterval;
1017 m_minimumTimerInterval = minimumTimerInterval;
1018 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) {
1019 if (frame->document())
1020 frame->document()->adjustMinimumTimerInterval(oldTimerInterval);
1024 double Page::minimumTimerInterval() const
1026 return m_minimumTimerInterval;
1029 void Page::dnsPrefetchingStateChanged()
1031 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1032 frame->document()->initDNSPrefetch();
1035 void Page::privateBrowsingStateChanged()
1037 bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
1039 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1040 frame->document()->privateBrowsingStateDidChange();
1042 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1043 // from below privateBrowsingStateChanged does not affect their lifetime.
1044 Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
1045 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
1046 FrameView* view = frame->view();
1050 const HashSet<RefPtr<Widget> >* children = view->children();
1053 HashSet<RefPtr<Widget> >::const_iterator end = children->end();
1054 for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
1055 Widget* widget = (*it).get();
1056 if (widget->isPluginViewBase())
1057 pluginViewBases.append(static_cast<PluginViewBase*>(widget));
1061 for (size_t i = 0; i < pluginViewBases.size(); ++i)
1062 pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
1065 #if !ASSERT_DISABLED
1066 void Page::checkFrameCountConsistency() const
1068 ASSERT(m_frameCount >= 0);
1071 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1074 ASSERT(m_frameCount + 1 == frameCount);
1078 #if ENABLE(PAGE_VISIBILITY_API)
1079 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
1081 if (m_visibilityState == visibilityState)
1083 m_visibilityState = visibilityState;
1085 if (!isInitialState && m_mainFrame) {
1086 if (visibilityState == PageVisibilityStateHidden) {
1087 ArenaSize size = renderTreeSize();
1088 HistogramSupport::histogramCustomCounts("WebCore.Page.renderTreeSizeBytes", size.treeSize, 1000, 500000000, 50);
1089 HistogramSupport::histogramCustomCounts("WebCore.Page.renderTreeAllocatedBytes", size.allocated, 1000, 500000000, 50);
1091 m_mainFrame->dispatchVisibilityStateChangeEvent();
1095 PageVisibilityState Page::visibilityState() const
1097 return m_visibilityState;
1101 // FIXME: gPaintedObjectCounterThreshold is no longer used for calculating relevant repainted areas,
1102 // and it should be removed. For the time being, it is useful because it allows us to avoid doing
1103 // any of this work for ports that don't make sure of didNewFirstVisuallyNonEmptyLayout. We should
1104 // remove this when we resolve <rdar://problem/10791680> Need to merge didFirstVisuallyNonEmptyLayout
1105 // and didNewFirstVisuallyNonEmptyLayout
1106 static uint64_t gPaintedObjectCounterThreshold = 0;
1108 // These are magical constants that might be tweaked over time.
1109 static double gMinimumPaintedAreaRatio = 0.1;
1110 static double gMaximumUnpaintedAreaRatio = 0.04;
1112 void Page::setRelevantRepaintedObjectsCounterThreshold(uint64_t threshold)
1114 gPaintedObjectCounterThreshold = threshold;
1117 bool Page::isCountingRelevantRepaintedObjects() const
1119 return m_isCountingRelevantRepaintedObjects && gPaintedObjectCounterThreshold > 0;
1122 void Page::startCountingRelevantRepaintedObjects()
1124 // Reset everything in case we didn't hit the threshold last time.
1125 resetRelevantPaintedObjectCounter();
1127 m_isCountingRelevantRepaintedObjects = true;
1130 void Page::resetRelevantPaintedObjectCounter()
1132 m_isCountingRelevantRepaintedObjects = false;
1133 m_relevantUnpaintedRenderObjects.clear();
1134 m_relevantPaintedRegion = Region();
1135 m_relevantUnpaintedRegion = Region();
1138 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1140 if (!isCountingRelevantRepaintedObjects())
1143 // The objects are only relevant if they are being painted within the viewRect().
1144 if (RenderView* view = object->view()) {
1145 if (!objectPaintRect.intersects(pixelSnappedIntRect(view->viewRect())))
1149 IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect);
1151 // If this object was previously counted as an unpainted object, remove it from that HashSet
1152 // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
1153 HashSet<RenderObject*>::iterator it = m_relevantUnpaintedRenderObjects.find(object);
1154 if (it != m_relevantUnpaintedRenderObjects.end()) {
1155 m_relevantUnpaintedRenderObjects.remove(it);
1156 m_relevantUnpaintedRegion.subtract(snappedPaintRect);
1159 m_relevantPaintedRegion.unite(snappedPaintRect);
1161 RenderView* view = object->view();
1165 float viewArea = view->viewRect().width() * view->viewRect().height();
1166 float ratioOfViewThatIsPainted = m_relevantPaintedRegion.totalArea() / viewArea;
1167 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1169 if (ratioOfViewThatIsPainted > gMinimumPaintedAreaRatio && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1170 m_isCountingRelevantRepaintedObjects = false;
1171 resetRelevantPaintedObjectCounter();
1172 if (Frame* frame = mainFrame())
1173 frame->loader()->didNewFirstVisuallyNonEmptyLayout();
1177 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1179 if (!isCountingRelevantRepaintedObjects())
1182 // The objects are only relevant if they are being painted within the viewRect().
1183 if (RenderView* view = object->view()) {
1184 if (!objectPaintRect.intersects(pixelSnappedIntRect(view->viewRect())))
1188 m_relevantUnpaintedRenderObjects.add(object);
1189 m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect));
1192 void Page::suspendActiveDOMObjectsAndAnimations()
1194 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1195 frame->suspendActiveDOMObjectsAndAnimations();
1198 void Page::resumeActiveDOMObjectsAndAnimations()
1200 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1201 frame->resumeActiveDOMObjectsAndAnimations();
1204 bool Page::hasSeenAnyPlugin() const
1206 return !m_seenPlugins.isEmpty();
1209 bool Page::hasSeenPlugin(const String& serviceType) const
1211 return m_seenPlugins.contains(serviceType);
1214 void Page::sawPlugin(const String& serviceType)
1216 m_seenPlugins.add(serviceType);
1219 void Page::resetSeenPlugins()
1221 m_seenPlugins.clear();
1224 Page::PageClients::PageClients()
1225 : alternativeTextClient(0)
1227 #if ENABLE(CONTEXT_MENUS)
1228 , contextMenuClient(0)
1232 , inspectorClient(0)
1236 Page::PageClients::~PageClients()
1240 } // namespace WebCore