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)
168 , m_isPainting(false)
170 , m_alternativeTextClient(pageClients.alternativeTextClient)
171 , m_scriptedAnimationsSuspended(false)
173 ASSERT(m_editorClient);
176 allPages = new HashSet<Page*>;
178 networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
181 ASSERT(!allPages->contains(this));
185 pageCounter.increment();
191 m_mainFrame->setView(0);
192 setGroupName(String());
193 allPages->remove(this);
195 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
196 frame->willDetachPage();
197 frame->detachFromPage();
200 m_editorClient->pageDestroyed();
201 if (m_alternativeTextClient)
202 m_alternativeTextClient->pageDestroyed();
204 #if ENABLE(INSPECTOR)
205 m_inspectorController->inspectedPageDestroyed();
208 if (m_scrollingCoordinator)
209 m_scrollingCoordinator->pageDestroyed();
211 backForward()->close();
214 pageCounter.decrement();
219 ArenaSize Page::renderTreeSize() const
221 ArenaSize total(0, 0);
222 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
223 if (!frame->document())
225 if (RenderArena* arena = frame->document()->renderArena()) {
226 total.treeSize += arena->totalRenderArenaSize();
227 total.allocated += arena->totalRenderArenaAllocatedBytes();
233 ViewportArguments Page::viewportArguments() const
235 return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportArguments() : ViewportArguments();
238 ScrollingCoordinator* Page::scrollingCoordinator()
240 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
241 m_scrollingCoordinator = ScrollingCoordinator::create(this);
243 return m_scrollingCoordinator.get();
246 struct ViewModeInfo {
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}
259 Page::ViewMode Page::stringToViewMode(const String& text)
261 for (int i = 0; i < viewModeMapSize; ++i) {
262 if (text == viewModeMap[i].name)
263 return viewModeMap[i].type;
265 return Page::ViewModeInvalid;
268 void Page::setViewMode(ViewMode viewMode)
270 if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
273 m_viewMode = viewMode;
278 if (m_mainFrame->view())
279 m_mainFrame->view()->forceLayout();
281 if (m_mainFrame->document())
282 m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately);
285 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
287 ASSERT(!m_mainFrame); // Should only be called during initialization
288 m_mainFrame = mainFrame;
291 bool Page::openedByDOM() const
293 return m_openedByDOM;
296 void Page::setOpenedByDOM()
298 m_openedByDOM = true;
301 BackForwardList* Page::backForwardList() const
303 return m_backForwardController->client();
308 HistoryItem* item = backForward()->backItem();
311 goToItem(item, FrameLoadTypeBack);
317 bool Page::goForward()
319 HistoryItem* item = backForward()->forwardItem();
322 goToItem(item, FrameLoadTypeForward);
328 bool Page::canGoBackOrForward(int distance) const
332 if (distance > 0 && distance <= backForward()->forwardCount())
334 if (distance < 0 && -distance <= backForward()->backCount())
339 void Page::goBackOrForward(int distance)
344 HistoryItem* item = backForward()->itemAtIndex(distance);
347 if (int forwardCount = backForward()->forwardCount())
348 item = backForward()->itemAtIndex(forwardCount);
350 if (int backCount = backForward()->backCount())
351 item = backForward()->itemAtIndex(-backCount);
358 goToItem(item, FrameLoadTypeIndexedBackForward);
361 void Page::goToItem(HistoryItem* item, FrameLoadType type)
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);
367 if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
368 m_mainFrame->loader()->stopAllLoaders();
370 m_mainFrame->loader()->history()->goToItem(item, type);
373 int Page::getHistoryLength()
375 return backForward()->backCount() + 1 + backForward()->forwardCount();
378 void Page::setGroupName(const String& name)
380 if (m_group && !m_group->name().isEmpty()) {
381 ASSERT(m_group != m_singlePageGroup.get());
382 ASSERT(!m_singlePageGroup);
383 m_group->removePage(this);
387 m_group = m_singlePageGroup.get();
389 m_singlePageGroup.clear();
390 m_group = PageGroup::pageGroup(name);
391 m_group->addPage(this);
395 const String& Page::groupName() const
397 DEFINE_STATIC_LOCAL(String, nullString, ());
398 return m_group ? m_group->name() : nullString;
401 void Page::initGroup()
403 ASSERT(!m_singlePageGroup);
405 m_singlePageGroup = PageGroup::create(this);
406 m_group = m_singlePageGroup.get();
409 void Page::scheduleForcedStyleRecalcForAllPages()
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();
419 void Page::setNeedsRecalcStyleInAllFrames()
421 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
422 frame->document()->styleResolverChanged(DeferRecalcStyle);
425 void Page::refreshPlugins(bool reload)
430 PluginData::refresh();
432 Vector<RefPtr<Frame> > framesNeedingReload;
434 HashSet<Page*>::iterator end = allPages->end();
435 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
438 // Clear out the page's plug-in data.
439 if (page->m_pluginData)
440 page->m_pluginData = 0;
445 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
446 if (frame->loader()->subframeLoader()->containsPlugins())
447 framesNeedingReload.append(frame);
451 for (size_t i = 0; i < framesNeedingReload.size(); ++i)
452 framesNeedingReload[i]->loader()->reload();
455 PluginData* Page::pluginData() const
457 if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
460 m_pluginData = PluginData::create(this);
461 return m_pluginData.get();
464 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
466 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
467 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
473 void Page::setCanStartMedia(bool canStartMedia)
475 if (m_canStartMedia == canStartMedia)
478 m_canStartMedia = canStartMedia;
480 while (m_canStartMedia) {
481 MediaCanStartListener* listener = takeAnyMediaCanStartListener();
484 listener->mediaCanStart();
488 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
491 ? curr->tree()->traverseNextWithWrap(wrapFlag)
492 : curr->tree()->traversePreviousWithWrap(wrapFlag);
495 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
497 return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
500 bool Page::findString(const String& target, FindOptions options)
502 if (target.isEmpty() || !mainFrame())
505 bool shouldWrap = options & WrapAround;
506 Frame* frame = focusController()->focusedOrMainFrame();
507 Frame* startFrame = frame;
509 if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
510 if (frame != startFrame)
511 startFrame->selection()->clear();
512 focusController()->setFocusedFrame(frame);
515 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
516 } while (frame && frame != startFrame);
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);
529 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range> >* matchRanges, int& indexForSelection)
531 indexForSelection = 0;
535 Frame* frame = mainFrame();
536 Frame* frameWithSelection = 0;
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);
544 if (matchRanges->isEmpty())
547 if (frameWithSelection) {
548 indexForSelection = NoMatchBeforeUserSelection;
549 RefPtr<Range> selectedRange = frameWithSelection->selection()->selection().firstRange();
550 for (size_t i = 0; i < matchRanges->size(); ++i) {
552 if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), ec) < 0) {
553 indexForSelection = i;
560 PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
562 if (target.isEmpty() || !mainFrame())
565 if (referenceRange && referenceRange->ownerDocument()->page() != this)
568 bool shouldWrap = options & WrapAround;
569 Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame();
570 Frame* startFrame = frame;
572 if (RefPtr<Range> resultRange = frame->editor()->rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
573 return resultRange.release();
575 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
576 } while (frame && frame != startFrame);
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();
588 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
590 return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
593 unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
595 if (target.isEmpty() || !mainFrame())
598 unsigned matches = 0;
600 Frame* frame = mainFrame();
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);
610 void Page::unmarkAllTextMatches()
615 Frame* frame = mainFrame();
617 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
618 frame = incrementFrame(frame, true, false);
622 const VisibleSelection& Page::selection() const
624 return focusController()->focusedOrMainFrame()->selection()->selection();
627 void Page::setDefersLoading(bool defers)
629 if (!m_settings->loadDeferringEnabled())
632 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
633 ASSERT(defers || m_defersLoadingCallCount);
634 if (defers && ++m_defersLoadingCallCount > 1)
636 if (!defers && --m_defersLoadingCallCount)
639 ASSERT(!m_defersLoadingCallCount);
640 if (defers == m_defersLoading)
644 m_defersLoading = defers;
645 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
646 frame->loader()->setDefersLoading(defers);
649 void Page::clearUndoRedoOperations()
651 m_editorClient->clearUndoRedoOperations();
654 bool Page::inLowQualityImageInterpolationMode() const
656 return m_inLowQualityInterpolationMode;
659 void Page::setInLowQualityImageInterpolationMode(bool mode)
661 m_inLowQualityInterpolationMode = mode;
664 void Page::setMediaVolume(float volume)
666 if (volume < 0 || volume > 1)
669 if (m_mediaVolume == volume)
672 m_mediaVolume = volume;
673 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
674 frame->document()->mediaVolumeDidChange();
678 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
680 Document* document = mainFrame()->document();
681 FrameView* view = document->view();
683 if (scale == m_pageScaleFactor) {
684 if (view && view->scrollPosition() != origin) {
685 document->updateLayoutIgnorePendingStylesheets();
686 view->setScrollPosition(origin);
691 m_pageScaleFactor = scale;
693 if (document->renderer())
694 document->renderer()->setNeedsLayout(true);
696 document->recalcStyle(Node::Force);
698 #if USE(ACCELERATED_COMPOSITING)
699 mainFrame()->deviceOrPageScaleFactorChanged();
702 if (view && view->scrollPosition() != origin) {
703 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
705 view->setScrollPosition(origin);
710 void Page::setDeviceScaleFactor(float scaleFactor)
712 if (m_deviceScaleFactor == scaleFactor)
715 m_deviceScaleFactor = scaleFactor;
716 setNeedsRecalcStyleInAllFrames();
718 #if USE(ACCELERATED_COMPOSITING)
720 mainFrame()->deviceOrPageScaleFactorChanged();
723 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
724 frame->editor()->deviceScaleFactorChanged();
726 pageCache()->markPagesForFullStyleRecalc(this);
729 void Page::setPagination(const Pagination& pagination)
731 if (m_pagination == pagination)
734 m_pagination = pagination;
736 setNeedsRecalcStyleInAllFrames();
737 pageCache()->markPagesForFullStyleRecalc(this);
740 unsigned Page::pageCount() const
742 if (m_pagination.mode == Pagination::Unpaginated)
745 FrameView* frameView = mainFrame()->view();
746 if (!frameView->didFirstLayout())
749 mainFrame()->view()->forceLayout();
751 RenderView* contentRenderer = mainFrame()->contentRenderer();
752 return contentRenderer->columnCount(contentRenderer->columnInfo());
755 void Page::didMoveOnscreen()
759 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
760 if (FrameView* frameView = frame->view())
761 frameView->didMoveOnscreen();
764 resumeScriptedAnimations();
767 void Page::willMoveOffscreen()
769 m_isOnscreen = false;
771 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
772 if (FrameView* frameView = frame->view())
773 frameView->willMoveOffscreen();
776 suspendScriptedAnimations();
779 void Page::windowScreenDidChange(PlatformDisplayID displayID)
781 m_displayID = displayID;
783 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
784 if (frame->document())
785 frame->document()->windowScreenDidChange(displayID);
789 void Page::suspendScriptedAnimations()
791 m_scriptedAnimationsSuspended = true;
792 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
793 if (frame->document())
794 frame->document()->suspendScriptedAnimationControllerCallbacks();
798 void Page::resumeScriptedAnimations()
800 m_scriptedAnimationsSuspended = false;
801 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
802 if (frame->document())
803 frame->document()->resumeScriptedAnimationControllerCallbacks();
807 void Page::userStyleSheetLocationChanged()
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();
813 // Allow any local file URL scheme to be loaded.
814 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
815 m_userStyleSheetPath = url.fileSystemPath();
817 m_userStyleSheetPath = String();
819 m_didLoadUserStyleSheet = false;
820 m_userStyleSheet = String();
821 m_userStyleSheetModificationTime = 0;
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;
828 Vector<char> styleSheetAsUTF8;
829 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
830 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
833 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
834 if (frame->document())
835 frame->document()->updatePageUserSheet();
839 const String& Page::userStyleSheet() const
841 if (m_userStyleSheetPath.isEmpty())
842 return m_userStyleSheet;
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;
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;
858 m_didLoadUserStyleSheet = true;
859 m_userStyleSheet = String();
860 m_userStyleSheetModificationTime = modTime;
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);
871 return m_userStyleSheet;
873 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
874 m_userStyleSheet = decoder->decode(data->data(), data->size());
875 m_userStyleSheet += decoder->flush();
877 return m_userStyleSheet;
880 void Page::removeAllVisitedLinks()
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())
890 HashSet<PageGroup*>::iterator groupsEnd = groups.end();
891 for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
892 (*it)->removeVisitedLinks();
895 void Page::allVisitedStateChanged(PageGroup* group)
901 HashSet<Page*>::iterator pagesEnd = allPages->end();
902 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
904 if (page->m_group != group)
906 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
907 if (StyleResolver* styleResolver = frame->document()->styleResolver())
908 styleResolver->allVisitedStateChanged();
913 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
919 HashSet<Page*>::iterator pagesEnd = allPages->end();
920 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
922 if (page->m_group != group)
924 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
925 if (StyleResolver* styleResolver = frame->document()->styleResolver())
926 styleResolver->visitedStateChanged(visitedLinkHash);
931 void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
935 HashSet<Page*>::iterator end = allPages->end();
936 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
937 (*it)->setDebugger(debugger);
940 void Page::setDebugger(JSC::Debugger* debugger)
942 if (m_debugger == debugger)
945 m_debugger = debugger;
947 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
948 frame->script()->attachDebugger(m_debugger);
951 StorageNamespace* Page::sessionStorage(bool optionalCreate)
953 if (!m_sessionStorage && optionalCreate)
954 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
956 return m_sessionStorage.get();
959 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
961 m_sessionStorage = newStorage;
964 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
966 if (customHTMLTokenizerTimeDelay < 0) {
967 m_customHTMLTokenizerTimeDelay = -1;
970 m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
973 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
975 if (customHTMLTokenizerChunkSize < 0) {
976 m_customHTMLTokenizerChunkSize = -1;
979 m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
982 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
984 if (m_areMemoryCacheClientCallsEnabled == enabled)
987 m_areMemoryCacheClientCallsEnabled = enabled;
991 for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
992 frame->loader()->tellClientAboutPastMemoryCacheLoads();
995 void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
997 m_javaScriptURLsAreAllowed = areAllowed;
1000 bool Page::javaScriptURLsAreAllowed() const
1002 return m_javaScriptURLsAreAllowed;
1005 void Page::setMinimumTimerInterval(double minimumTimerInterval)
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);
1015 double Page::minimumTimerInterval() const
1017 return m_minimumTimerInterval;
1020 void Page::dnsPrefetchingStateChanged()
1022 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1023 frame->document()->initDNSPrefetch();
1026 void Page::privateBrowsingStateChanged()
1028 bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
1030 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1031 frame->document()->privateBrowsingStateDidChange();
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();
1041 const HashSet<RefPtr<Widget> >* children = view->children();
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));
1052 for (size_t i = 0; i < pluginViewBases.size(); ++i)
1053 pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
1056 #if !ASSERT_DISABLED
1057 void Page::checkFrameCountConsistency() const
1059 ASSERT(m_frameCount >= 0);
1062 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1065 ASSERT(m_frameCount + 1 == frameCount);
1069 #if ENABLE(PAGE_VISIBILITY_API)
1070 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
1072 if (m_visibilityState == visibilityState)
1074 m_visibilityState = visibilityState;
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);
1082 m_mainFrame->dispatchVisibilityStateChangeEvent();
1086 PageVisibilityState Page::visibilityState() const
1088 return m_visibilityState;
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;
1099 // These are magical constants that might be tweaked over time.
1100 static double gMinimumPaintedAreaRatio = 0.1;
1101 static double gMaximumUnpaintedAreaRatio = 0.04;
1103 void Page::setRelevantRepaintedObjectsCounterThreshold(uint64_t threshold)
1105 gPaintedObjectCounterThreshold = threshold;
1108 bool Page::isCountingRelevantRepaintedObjects() const
1110 return m_isCountingRelevantRepaintedObjects && gPaintedObjectCounterThreshold > 0;
1113 void Page::startCountingRelevantRepaintedObjects()
1115 // Reset everything in case we didn't hit the threshold last time.
1116 resetRelevantPaintedObjectCounter();
1118 m_isCountingRelevantRepaintedObjects = true;
1121 void Page::resetRelevantPaintedObjectCounter()
1123 m_isCountingRelevantRepaintedObjects = false;
1124 m_relevantUnpaintedRenderObjects.clear();
1125 m_relevantPaintedRegion = Region();
1126 m_relevantUnpaintedRegion = Region();
1129 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1131 if (!isCountingRelevantRepaintedObjects())
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())))
1140 IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect);
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);
1150 m_relevantPaintedRegion.unite(snappedPaintRect);
1152 RenderView* view = object->view();
1156 float viewArea = view->viewRect().width() * view->viewRect().height();
1157 float ratioOfViewThatIsPainted = m_relevantPaintedRegion.totalArea() / viewArea;
1158 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1160 if (ratioOfViewThatIsPainted > gMinimumPaintedAreaRatio && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1161 m_isCountingRelevantRepaintedObjects = false;
1162 resetRelevantPaintedObjectCounter();
1163 if (Frame* frame = mainFrame())
1164 frame->loader()->didNewFirstVisuallyNonEmptyLayout();
1168 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1170 if (!isCountingRelevantRepaintedObjects())
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())))
1179 m_relevantUnpaintedRenderObjects.add(object);
1180 m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect));
1183 void Page::suspendActiveDOMObjectsAndAnimations()
1185 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1186 frame->suspendActiveDOMObjectsAndAnimations();
1189 void Page::resumeActiveDOMObjectsAndAnimations()
1191 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1192 frame->resumeActiveDOMObjectsAndAnimations();
1195 bool Page::hasSeenAnyPlugin() const
1197 return !m_seenPlugins.isEmpty();
1200 bool Page::hasSeenPlugin(const String& serviceType) const
1202 return m_seenPlugins.contains(serviceType);
1205 void Page::sawPlugin(const String& serviceType)
1207 m_seenPlugins.add(serviceType);
1210 void Page::resetSeenPlugins()
1212 m_seenPlugins.clear();
1215 Page::PageClients::PageClients()
1216 : alternativeTextClient(0)
1218 #if ENABLE(CONTEXT_MENUS)
1219 , contextMenuClient(0)
1223 , inspectorClient(0)
1227 Page::PageClients::~PageClients()
1231 } // namespace WebCore