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 #if ENABLE(TIZEN_FIND_STRING)
47 #include "HTMLFrameOwnerElement.h"
49 #include "HistogramSupport.h"
50 #include "HistoryItem.h"
51 #include "InspectorController.h"
52 #include "InspectorInstrumentation.h"
54 #include "MediaCanStartListener.h"
55 #include "Navigator.h"
56 #include "NetworkStateNotifier.h"
57 #if ENABLE(TIZEN_FIND_STRING)
58 #include "NodeRenderStyle.h"
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"
75 #include "SharedBuffer.h"
76 #include "StorageArea.h"
77 #include "StorageNamespace.h"
78 #include "StyleResolver.h"
79 #include "TextResourceDecoder.h"
80 #include "VoidCallback.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>
90 #if ENABLE(TIZEN_NATIVE_MEMORY_SNAPSHOT)
91 HashSet<Page*>* allPages;
93 static HashSet<Page*>* allPages;
95 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
97 static void networkStateChanged()
99 Vector<RefPtr<Frame> > frames;
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);
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));
114 float deviceScaleFactor(Frame* frame)
118 Page* page = frame->page();
121 return page->deviceScaleFactor();
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))
130 , m_focusController(FocusController::create(this))
131 #if ENABLE(CONTEXT_MENUS)
132 , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
134 #if ENABLE(INSPECTOR)
135 , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
137 #if ENABLE(POINTER_LOCK)
138 , m_pointerLockController(PointerLockController::create(this))
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)
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)
154 , m_pageScaleFactor(1)
155 , m_deviceScaleFactor(1)
156 , m_javaScriptURLsAreAllowed(true)
157 , m_didLoadUserStyleSheet(false)
158 , m_userStyleSheetModificationTime(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)
168 #if ENABLE(PAGE_VISIBILITY_API)
169 , m_visibilityState(PageVisibilityStateVisible)
172 , m_isCountingRelevantRepaintedObjects(false)
174 , m_isPainting(false)
176 , m_alternativeTextClient(pageClients.alternativeTextClient)
177 , m_scriptedAnimationsSuspended(false)
179 ASSERT(m_editorClient);
182 allPages = new HashSet<Page*>;
184 networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
187 ASSERT(!allPages->contains(this));
191 pageCounter.increment();
197 m_mainFrame->setView(0);
198 setGroupName(String());
199 allPages->remove(this);
201 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
202 frame->willDetachPage();
203 frame->detachFromPage();
206 m_editorClient->pageDestroyed();
207 if (m_alternativeTextClient)
208 m_alternativeTextClient->pageDestroyed();
210 #if ENABLE(INSPECTOR)
211 m_inspectorController->inspectedPageDestroyed();
214 if (m_scrollingCoordinator)
215 m_scrollingCoordinator->pageDestroyed();
217 backForward()->close();
220 pageCounter.decrement();
225 ArenaSize Page::renderTreeSize() const
227 ArenaSize total(0, 0);
228 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
229 if (!frame->document())
231 if (RenderArena* arena = frame->document()->renderArena()) {
232 total.treeSize += arena->totalRenderArenaSize();
233 total.allocated += arena->totalRenderArenaAllocatedBytes();
239 ViewportArguments Page::viewportArguments() const
241 return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportArguments() : ViewportArguments();
244 ScrollingCoordinator* Page::scrollingCoordinator()
246 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
247 m_scrollingCoordinator = ScrollingCoordinator::create(this);
249 return m_scrollingCoordinator.get();
252 struct ViewModeInfo {
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}
265 Page::ViewMode Page::stringToViewMode(const String& text)
267 for (int i = 0; i < viewModeMapSize; ++i) {
268 if (text == viewModeMap[i].name)
269 return viewModeMap[i].type;
271 return Page::ViewModeInvalid;
274 void Page::setViewMode(ViewMode viewMode)
276 if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
279 m_viewMode = viewMode;
284 if (m_mainFrame->view())
285 m_mainFrame->view()->forceLayout();
287 if (m_mainFrame->document())
288 m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately);
291 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
293 ASSERT(!m_mainFrame); // Should only be called during initialization
294 m_mainFrame = mainFrame;
297 bool Page::openedByDOM() const
299 return m_openedByDOM;
302 void Page::setOpenedByDOM()
304 m_openedByDOM = true;
307 BackForwardList* Page::backForwardList() const
309 return m_backForwardController->client();
314 HistoryItem* item = backForward()->backItem();
317 goToItem(item, FrameLoadTypeBack);
323 bool Page::goForward()
325 HistoryItem* item = backForward()->forwardItem();
328 goToItem(item, FrameLoadTypeForward);
334 bool Page::canGoBackOrForward(int distance) const
338 if (distance > 0 && distance <= backForward()->forwardCount())
340 if (distance < 0 && -distance <= backForward()->backCount())
345 void Page::goBackOrForward(int distance)
350 HistoryItem* item = backForward()->itemAtIndex(distance);
353 if (int forwardCount = backForward()->forwardCount())
354 item = backForward()->itemAtIndex(forwardCount);
356 if (int backCount = backForward()->backCount())
357 item = backForward()->itemAtIndex(-backCount);
364 goToItem(item, FrameLoadTypeIndexedBackForward);
367 void Page::goToItem(HistoryItem* item, FrameLoadType type)
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);
373 if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
374 m_mainFrame->loader()->stopAllLoaders();
376 m_mainFrame->loader()->history()->goToItem(item, type);
379 int Page::getHistoryLength()
381 return backForward()->backCount() + 1 + backForward()->forwardCount();
384 void Page::setGroupName(const String& name)
386 if (m_group && !m_group->name().isEmpty()) {
387 ASSERT(m_group != m_singlePageGroup.get());
388 ASSERT(!m_singlePageGroup);
389 m_group->removePage(this);
393 m_group = m_singlePageGroup.get();
395 m_singlePageGroup.clear();
396 m_group = PageGroup::pageGroup(name);
397 m_group->addPage(this);
401 const String& Page::groupName() const
403 DEFINE_STATIC_LOCAL(String, nullString, ());
404 return m_group ? m_group->name() : nullString;
407 void Page::initGroup()
409 ASSERT(!m_singlePageGroup);
411 m_singlePageGroup = PageGroup::create(this);
412 m_group = m_singlePageGroup.get();
415 void Page::scheduleForcedStyleRecalcForAllPages()
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();
425 void Page::setNeedsRecalcStyleInAllFrames()
427 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
428 frame->document()->styleResolverChanged(DeferRecalcStyle);
431 void Page::refreshPlugins(bool reload)
436 PluginData::refresh();
438 Vector<RefPtr<Frame> > framesNeedingReload;
440 HashSet<Page*>::iterator end = allPages->end();
441 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
444 // Clear out the page's plug-in data.
445 if (page->m_pluginData)
446 page->m_pluginData = 0;
451 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
452 if (frame->loader()->subframeLoader()->containsPlugins())
453 framesNeedingReload.append(frame);
457 for (size_t i = 0; i < framesNeedingReload.size(); ++i)
458 framesNeedingReload[i]->loader()->reload();
461 PluginData* Page::pluginData() const
463 if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
466 m_pluginData = PluginData::create(this);
467 return m_pluginData.get();
470 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
472 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
473 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
479 void Page::setCanStartMedia(bool canStartMedia)
481 if (m_canStartMedia == canStartMedia)
484 m_canStartMedia = canStartMedia;
486 while (m_canStartMedia) {
487 MediaCanStartListener* listener = takeAnyMediaCanStartListener();
490 listener->mediaCanStart();
494 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
497 ? curr->tree()->traverseNextWithWrap(wrapFlag)
498 : curr->tree()->traversePreviousWithWrap(wrapFlag);
501 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
503 return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
506 bool Page::findString(const String& target, FindOptions options)
508 if (target.isEmpty() || !mainFrame())
511 bool shouldWrap = options & WrapAround;
512 Frame* frame = focusController()->focusedOrMainFrame();
513 Frame* startFrame = frame;
515 if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
516 if (frame != startFrame)
517 startFrame->selection()->clear();
518 focusController()->setFocusedFrame(frame);
521 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
522 } while (frame && frame != startFrame);
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);
535 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range> >* matchRanges, int& indexForSelection)
537 indexForSelection = 0;
541 Frame* frame = mainFrame();
542 Frame* frameWithSelection = 0;
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())
555 if (matchRanges->isEmpty())
558 if (frameWithSelection) {
559 indexForSelection = NoMatchBeforeUserSelection;
560 RefPtr<Range> selectedRange = frameWithSelection->selection()->selection().firstRange();
561 for (size_t i = 0; i < matchRanges->size(); ++i) {
563 if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), ec) < 0) {
564 indexForSelection = i;
571 PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
573 if (target.isEmpty() || !mainFrame())
576 if (referenceRange && referenceRange->ownerDocument()->page() != this)
579 bool shouldWrap = options & WrapAround;
580 Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame();
581 Frame* startFrame = frame;
583 if (RefPtr<Range> resultRange = frame->editor()->rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
584 return resultRange.release();
586 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
587 } while (frame && frame != startFrame);
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();
599 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
601 return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
604 unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
606 if (target.isEmpty() || !mainFrame())
609 unsigned matches = 0;
611 Frame* frame = mainFrame();
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())
626 void Page::unmarkAllTextMatches()
631 Frame* frame = mainFrame();
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())
643 const VisibleSelection& Page::selection() const
645 return focusController()->focusedOrMainFrame()->selection()->selection();
648 void Page::setDefersLoading(bool defers)
650 if (!m_settings->loadDeferringEnabled())
653 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
654 ASSERT(defers || m_defersLoadingCallCount);
655 if (defers && ++m_defersLoadingCallCount > 1)
657 if (!defers && --m_defersLoadingCallCount)
660 ASSERT(!m_defersLoadingCallCount);
661 if (defers == m_defersLoading)
665 m_defersLoading = defers;
666 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
667 frame->loader()->setDefersLoading(defers);
670 void Page::clearUndoRedoOperations()
672 m_editorClient->clearUndoRedoOperations();
675 bool Page::inLowQualityImageInterpolationMode() const
677 return m_inLowQualityInterpolationMode;
680 void Page::setInLowQualityImageInterpolationMode(bool mode)
682 m_inLowQualityInterpolationMode = mode;
685 void Page::setMediaVolume(float volume)
687 if (volume < 0 || volume > 1)
690 if (m_mediaVolume == volume)
693 m_mediaVolume = volume;
694 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
695 frame->document()->mediaVolumeDidChange();
699 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
701 Document* document = mainFrame()->document();
702 FrameView* view = document->view();
704 if (scale == m_pageScaleFactor) {
705 if (view && view->scrollPosition() != origin) {
706 document->updateLayoutIgnorePendingStylesheets();
707 view->setScrollPosition(origin);
712 m_pageScaleFactor = scale;
714 if (document->renderer())
715 document->renderer()->setNeedsLayout(true);
717 document->recalcStyle(Node::Force);
719 #if USE(ACCELERATED_COMPOSITING)
720 mainFrame()->deviceOrPageScaleFactorChanged();
723 if (view && view->scrollPosition() != origin) {
724 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
726 view->setScrollPosition(origin);
731 void Page::setDeviceScaleFactor(float scaleFactor)
733 if (m_deviceScaleFactor == scaleFactor)
736 m_deviceScaleFactor = scaleFactor;
737 setNeedsRecalcStyleInAllFrames();
739 #if USE(ACCELERATED_COMPOSITING)
741 mainFrame()->deviceOrPageScaleFactorChanged();
744 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
745 frame->editor()->deviceScaleFactorChanged();
747 pageCache()->markPagesForFullStyleRecalc(this);
750 void Page::setPagination(const Pagination& pagination)
752 if (m_pagination == pagination)
755 m_pagination = pagination;
757 setNeedsRecalcStyleInAllFrames();
758 pageCache()->markPagesForFullStyleRecalc(this);
761 unsigned Page::pageCount() const
763 if (m_pagination.mode == Pagination::Unpaginated)
766 FrameView* frameView = mainFrame()->view();
767 if (!frameView->didFirstLayout())
770 mainFrame()->view()->forceLayout();
772 RenderView* contentRenderer = mainFrame()->contentRenderer();
773 return contentRenderer->columnCount(contentRenderer->columnInfo());
776 void Page::didMoveOnscreen()
780 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
781 if (FrameView* frameView = frame->view())
782 frameView->didMoveOnscreen();
785 resumeScriptedAnimations();
788 void Page::willMoveOffscreen()
790 m_isOnscreen = false;
792 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
793 if (FrameView* frameView = frame->view())
794 frameView->willMoveOffscreen();
797 suspendScriptedAnimations();
800 void Page::windowScreenDidChange(PlatformDisplayID displayID)
802 m_displayID = displayID;
804 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
805 if (frame->document())
806 frame->document()->windowScreenDidChange(displayID);
810 void Page::suspendScriptedAnimations()
812 m_scriptedAnimationsSuspended = true;
813 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
814 if (frame->document())
815 frame->document()->suspendScriptedAnimationControllerCallbacks();
819 void Page::resumeScriptedAnimations()
821 m_scriptedAnimationsSuspended = false;
822 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
823 if (frame->document())
824 frame->document()->resumeScriptedAnimationControllerCallbacks();
828 void Page::userStyleSheetLocationChanged()
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();
834 // Allow any local file URL scheme to be loaded.
835 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
836 m_userStyleSheetPath = url.fileSystemPath();
838 m_userStyleSheetPath = String();
840 m_didLoadUserStyleSheet = false;
841 m_userStyleSheet = String();
842 m_userStyleSheetModificationTime = 0;
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;
849 Vector<char> styleSheetAsUTF8;
850 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
851 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
854 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
855 if (frame->document())
856 frame->document()->updatePageUserSheet();
860 const String& Page::userStyleSheet() const
862 if (m_userStyleSheetPath.isEmpty())
863 return m_userStyleSheet;
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;
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;
879 m_didLoadUserStyleSheet = true;
880 m_userStyleSheet = String();
881 m_userStyleSheetModificationTime = modTime;
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);
892 return m_userStyleSheet;
894 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
895 m_userStyleSheet = decoder->decode(data->data(), data->size());
896 m_userStyleSheet += decoder->flush();
898 return m_userStyleSheet;
901 void Page::removeAllVisitedLinks()
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())
911 HashSet<PageGroup*>::iterator groupsEnd = groups.end();
912 for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
913 (*it)->removeVisitedLinks();
916 void Page::allVisitedStateChanged(PageGroup* group)
922 HashSet<Page*>::iterator pagesEnd = allPages->end();
923 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
925 if (page->m_group != group)
927 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
928 if (StyleResolver* styleResolver = frame->document()->styleResolver())
929 styleResolver->allVisitedStateChanged();
934 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
940 HashSet<Page*>::iterator pagesEnd = allPages->end();
941 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
943 if (page->m_group != group)
945 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
946 if (StyleResolver* styleResolver = frame->document()->styleResolver())
947 styleResolver->visitedStateChanged(visitedLinkHash);
952 void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
956 HashSet<Page*>::iterator end = allPages->end();
957 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
958 (*it)->setDebugger(debugger);
961 void Page::setDebugger(JSC::Debugger* debugger)
963 if (m_debugger == debugger)
966 m_debugger = debugger;
968 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
969 frame->script()->attachDebugger(m_debugger);
972 StorageNamespace* Page::sessionStorage(bool optionalCreate)
974 if (!m_sessionStorage && optionalCreate)
975 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
977 return m_sessionStorage.get();
980 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
982 m_sessionStorage = newStorage;
985 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
987 if (customHTMLTokenizerTimeDelay < 0) {
988 m_customHTMLTokenizerTimeDelay = -1;
991 m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
994 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
996 if (customHTMLTokenizerChunkSize < 0) {
997 m_customHTMLTokenizerChunkSize = -1;
1000 m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
1003 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1005 if (m_areMemoryCacheClientCallsEnabled == enabled)
1008 m_areMemoryCacheClientCallsEnabled = enabled;
1012 for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1013 frame->loader()->tellClientAboutPastMemoryCacheLoads();
1016 void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
1018 m_javaScriptURLsAreAllowed = areAllowed;
1021 bool Page::javaScriptURLsAreAllowed() const
1023 return m_javaScriptURLsAreAllowed;
1026 void Page::setMinimumTimerInterval(double minimumTimerInterval)
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);
1036 double Page::minimumTimerInterval() const
1038 return m_minimumTimerInterval;
1041 void Page::dnsPrefetchingStateChanged()
1043 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1044 frame->document()->initDNSPrefetch();
1047 void Page::privateBrowsingStateChanged()
1049 bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
1051 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1052 frame->document()->privateBrowsingStateDidChange();
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();
1062 const HashSet<RefPtr<Widget> >* children = view->children();
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));
1073 for (size_t i = 0; i < pluginViewBases.size(); ++i)
1074 pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
1077 #if !ASSERT_DISABLED
1078 void Page::checkFrameCountConsistency() const
1080 ASSERT(m_frameCount >= 0);
1083 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1086 ASSERT(m_frameCount + 1 == frameCount);
1090 #if ENABLE(PAGE_VISIBILITY_API)
1091 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
1093 if (m_visibilityState == visibilityState)
1095 m_visibilityState = visibilityState;
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);
1103 m_mainFrame->dispatchVisibilityStateChangeEvent();
1107 PageVisibilityState Page::visibilityState() const
1109 return m_visibilityState;
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;
1120 // These are magical constants that might be tweaked over time.
1121 static double gMinimumPaintedAreaRatio = 0.1;
1122 static double gMaximumUnpaintedAreaRatio = 0.04;
1124 void Page::setRelevantRepaintedObjectsCounterThreshold(uint64_t threshold)
1126 gPaintedObjectCounterThreshold = threshold;
1129 bool Page::isCountingRelevantRepaintedObjects() const
1131 return m_isCountingRelevantRepaintedObjects && gPaintedObjectCounterThreshold > 0;
1134 void Page::startCountingRelevantRepaintedObjects()
1136 // Reset everything in case we didn't hit the threshold last time.
1137 resetRelevantPaintedObjectCounter();
1139 m_isCountingRelevantRepaintedObjects = true;
1142 void Page::resetRelevantPaintedObjectCounter()
1144 m_isCountingRelevantRepaintedObjects = false;
1145 m_relevantUnpaintedRenderObjects.clear();
1146 m_relevantPaintedRegion = Region();
1147 m_relevantUnpaintedRegion = Region();
1150 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1152 if (!isCountingRelevantRepaintedObjects())
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())))
1161 IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect);
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);
1171 m_relevantPaintedRegion.unite(snappedPaintRect);
1173 RenderView* view = object->view();
1177 float viewArea = view->viewRect().width() * view->viewRect().height();
1178 float ratioOfViewThatIsPainted = m_relevantPaintedRegion.totalArea() / viewArea;
1179 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1181 if (ratioOfViewThatIsPainted > gMinimumPaintedAreaRatio && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1182 m_isCountingRelevantRepaintedObjects = false;
1183 resetRelevantPaintedObjectCounter();
1184 if (Frame* frame = mainFrame())
1185 frame->loader()->didNewFirstVisuallyNonEmptyLayout();
1189 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1191 if (!isCountingRelevantRepaintedObjects())
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())))
1200 m_relevantUnpaintedRenderObjects.add(object);
1201 m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect));
1204 void Page::suspendActiveDOMObjectsAndAnimations()
1206 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1207 frame->suspendActiveDOMObjectsAndAnimations();
1210 void Page::resumeActiveDOMObjectsAndAnimations()
1212 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
1213 frame->resumeActiveDOMObjectsAndAnimations();
1216 bool Page::hasSeenAnyPlugin() const
1218 return !m_seenPlugins.isEmpty();
1221 bool Page::hasSeenPlugin(const String& serviceType) const
1223 return m_seenPlugins.contains(serviceType);
1226 void Page::sawPlugin(const String& serviceType)
1228 m_seenPlugins.add(serviceType);
1231 void Page::resetSeenPlugins()
1233 m_seenPlugins.clear();
1236 Page::PageClients::PageClients()
1237 : alternativeTextClient(0)
1239 #if ENABLE(CONTEXT_MENUS)
1240 , contextMenuClient(0)
1244 , inspectorClient(0)
1248 Page::PageClients::~PageClients()
1252 } // namespace WebCore