• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 #include "Page.h"
22 
23 #include "BackForwardController.h"
24 #include "BackForwardList.h"
25 #include "Base64.h"
26 #include "CSSStyleSelector.h"
27 #include "Chrome.h"
28 #include "ChromeClient.h"
29 #include "ContextMenuClient.h"
30 #include "ContextMenuController.h"
31 #include "DOMWindow.h"
32 #include "DeviceMotionController.h"
33 #include "DeviceOrientationController.h"
34 #include "DocumentMarkerController.h"
35 #include "DragController.h"
36 #include "EditorClient.h"
37 #include "Event.h"
38 #include "EventNames.h"
39 #include "ExceptionCode.h"
40 #include "FileSystem.h"
41 #include "FocusController.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "FrameTree.h"
46 #include "FrameView.h"
47 #include "HTMLElement.h"
48 #include "HistoryItem.h"
49 #include "InspectorController.h"
50 #include "InspectorInstrumentation.h"
51 #include "Logging.h"
52 #include "MediaCanStartListener.h"
53 #include "Navigator.h"
54 #include "NetworkStateNotifier.h"
55 #include "PageGroup.h"
56 #include "PluginData.h"
57 #include "PluginHalter.h"
58 #include "PluginView.h"
59 #include "PluginViewBase.h"
60 #include "ProgressTracker.h"
61 #include "RenderTheme.h"
62 #include "RenderWidget.h"
63 #include "RuntimeEnabledFeatures.h"
64 #include "ScriptController.h"
65 #include "SelectionController.h"
66 #include "Settings.h"
67 #include "SharedBuffer.h"
68 #include "SpeechInput.h"
69 #include "SpeechInputClient.h"
70 #include "TextResourceDecoder.h"
71 #include "Widget.h"
72 #include <wtf/HashMap.h>
73 #include <wtf/RefCountedLeakCounter.h>
74 #include <wtf/StdLibExtras.h>
75 #include <wtf/text/StringHash.h>
76 
77 #if ENABLE(ACCELERATED_2D_CANVAS)
78 #include "SharedGraphicsContext3D.h"
79 #endif
80 
81 #if ENABLE(DOM_STORAGE)
82 #include "StorageArea.h"
83 #include "StorageNamespace.h"
84 #endif
85 
86 #if ENABLE(WML)
87 #include "WMLPageState.h"
88 #endif
89 
90 #if ENABLE(CLIENT_BASED_GEOLOCATION)
91 #include "GeolocationController.h"
92 #endif
93 
94 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
95 #include "PackageNotifier.h"
96 #endif
97 
98 namespace WebCore {
99 
100 static HashSet<Page*>* allPages;
101 
102 #ifndef NDEBUG
103 static WTF::RefCountedLeakCounter pageCounter("Page");
104 #endif
105 
networkStateChanged()106 static void networkStateChanged()
107 {
108     Vector<RefPtr<Frame> > frames;
109 
110     // Get all the frames of all the pages in all the page groups
111     HashSet<Page*>::iterator end = allPages->end();
112     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
113         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
114             frames.append(frame);
115         InspectorInstrumentation::networkStateChanged(*it);
116     }
117 
118     AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
119     for (unsigned i = 0; i < frames.size(); i++)
120         frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
121 }
122 
123 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
onPackageResultAvailable()124 static void onPackageResultAvailable()
125 {
126     HashSet<Page*>::iterator end = allPages->end();
127     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
128         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
129             frame->domWindow()->navigator()->onPackageResult();
130     }
131 }
132 #endif
133 
Page(const PageClients & pageClients)134 Page::Page(const PageClients& pageClients)
135     : m_chrome(adoptPtr(new Chrome(this, pageClients.chromeClient)))
136     , m_dragCaretController(adoptPtr(new SelectionController(0, true)))
137 #if ENABLE(DRAG_SUPPORT)
138     , m_dragController(adoptPtr(new DragController(this, pageClients.dragClient)))
139 #endif
140     , m_focusController(adoptPtr(new FocusController(this)))
141 #if ENABLE(CONTEXT_MENUS)
142     , m_contextMenuController(adoptPtr(new ContextMenuController(this, pageClients.contextMenuClient)))
143 #endif
144 #if ENABLE(INSPECTOR)
145     , m_inspectorController(adoptPtr(new InspectorController(this, pageClients.inspectorClient)))
146 #endif
147 #if ENABLE(CLIENT_BASED_GEOLOCATION)
148     , m_geolocationController(adoptPtr(new GeolocationController(this, pageClients.geolocationClient)))
149 #endif
150 #if ENABLE(DEVICE_ORIENTATION)
151     , m_deviceMotionController(RuntimeEnabledFeatures::deviceMotionEnabled() ? new DeviceMotionController(pageClients.deviceMotionClient) : 0)
152     , m_deviceOrientationController(RuntimeEnabledFeatures::deviceOrientationEnabled() ? new DeviceOrientationController(this, pageClients.deviceOrientationClient) : 0)
153 #endif
154 #if ENABLE(INPUT_SPEECH)
155     , m_speechInputClient(pageClients.speechInputClient)
156 #endif
157     , m_settings(adoptPtr(new Settings(this)))
158     , m_progress(adoptPtr(new ProgressTracker))
159     , m_backForwardController(adoptPtr(new BackForwardController(this, pageClients.backForwardClient)))
160     , m_theme(RenderTheme::themeForPage(this))
161     , m_editorClient(pageClients.editorClient)
162     , m_frameCount(0)
163     , m_openedByDOM(false)
164     , m_tabKeyCyclesThroughElements(true)
165     , m_defersLoading(false)
166     , m_inLowQualityInterpolationMode(false)
167     , m_cookieEnabled(true)
168     , m_areMemoryCacheClientCallsEnabled(true)
169     , m_mediaVolume(1)
170     , m_javaScriptURLsAreAllowed(true)
171     , m_didLoadUserStyleSheet(false)
172     , m_userStyleSheetModificationTime(0)
173     , m_group(0)
174     , m_debugger(0)
175     , m_customHTMLTokenizerTimeDelay(-1)
176     , m_customHTMLTokenizerChunkSize(-1)
177     , m_canStartMedia(true)
178     , m_viewMode(ViewModeWindowed)
179     , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
180     , m_isEditable(false)
181 {
182     if (!allPages) {
183         allPages = new HashSet<Page*>;
184 
185         networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
186 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
187         packageNotifier().setOnResultAvailable(onPackageResultAvailable);
188 #endif
189     }
190 
191     ASSERT(!allPages->contains(this));
192     allPages->add(this);
193 
194     if (pageClients.pluginHalterClient) {
195         m_pluginHalter.set(new PluginHalter(pageClients.pluginHalterClient));
196         m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
197     }
198 
199 #ifndef NDEBUG
200     pageCounter.increment();
201 #endif
202 }
203 
~Page()204 Page::~Page()
205 {
206     m_mainFrame->setView(0);
207     setGroupName(String());
208     allPages->remove(this);
209 
210     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
211         frame->pageDestroyed();
212 
213     if (m_scrollableAreaSet) {
214         ScrollableAreaSet::const_iterator end = m_scrollableAreaSet->end();
215         for (ScrollableAreaSet::const_iterator it = m_scrollableAreaSet->begin(); it != end; ++it)
216             (*it)->disconnectFromPage();
217     }
218 
219     m_editorClient->pageDestroyed();
220 
221     InspectorInstrumentation::inspectedPageDestroyed(this);
222 
223     backForward()->close();
224 
225 #ifndef NDEBUG
226     pageCounter.decrement();
227 
228     // Cancel keepAlive timers, to ensure we release all Frames before exiting.
229     // It's safe to do this because we prohibit closing a Page while JavaScript
230     // is executing.
231     Frame::cancelAllKeepAlive();
232 #endif
233 }
234 
235 struct ViewModeInfo {
236     const char* name;
237     Page::ViewMode type;
238 };
239 static const int viewModeMapSize = 5;
240 static ViewModeInfo viewModeMap[viewModeMapSize] = {
241     {"windowed", Page::ViewModeWindowed},
242     {"floating", Page::ViewModeFloating},
243     {"fullscreen", Page::ViewModeFullscreen},
244     {"maximized", Page::ViewModeMaximized},
245     {"minimized", Page::ViewModeMinimized}
246 };
247 
stringToViewMode(const String & text)248 Page::ViewMode Page::stringToViewMode(const String& text)
249 {
250     for (int i = 0; i < viewModeMapSize; ++i) {
251         if (text == viewModeMap[i].name)
252             return viewModeMap[i].type;
253     }
254     return Page::ViewModeInvalid;
255 }
256 
setViewMode(ViewMode viewMode)257 void Page::setViewMode(ViewMode viewMode)
258 {
259     if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
260         return;
261 
262     m_viewMode = viewMode;
263 
264     if (!m_mainFrame)
265         return;
266 
267     if (m_mainFrame->view())
268         m_mainFrame->view()->forceLayout();
269 
270     if (m_mainFrame->document())
271         m_mainFrame->document()->styleSelectorChanged(RecalcStyleImmediately);
272 }
273 
setMainFrame(PassRefPtr<Frame> mainFrame)274 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
275 {
276     ASSERT(!m_mainFrame); // Should only be called during initialization
277     m_mainFrame = mainFrame;
278 }
279 
openedByDOM() const280 bool Page::openedByDOM() const
281 {
282     return m_openedByDOM;
283 }
284 
setOpenedByDOM()285 void Page::setOpenedByDOM()
286 {
287     m_openedByDOM = true;
288 }
289 
backForwardList() const290 BackForwardList* Page::backForwardList() const
291 {
292     return m_backForwardController->client();
293 }
294 
goBack()295 bool Page::goBack()
296 {
297     HistoryItem* item = backForward()->backItem();
298 
299     if (item) {
300         goToItem(item, FrameLoadTypeBack);
301         return true;
302     }
303     return false;
304 }
305 
goForward()306 bool Page::goForward()
307 {
308     HistoryItem* item = backForward()->forwardItem();
309 
310     if (item) {
311         goToItem(item, FrameLoadTypeForward);
312         return true;
313     }
314     return false;
315 }
316 
canGoBackOrForward(int distance) const317 bool Page::canGoBackOrForward(int distance) const
318 {
319     if (distance == 0)
320         return true;
321     if (distance > 0 && distance <= backForward()->forwardCount())
322         return true;
323     if (distance < 0 && -distance <= backForward()->backCount())
324         return true;
325     return false;
326 }
327 
goBackOrForward(int distance)328 void Page::goBackOrForward(int distance)
329 {
330     if (distance == 0)
331         return;
332 
333     HistoryItem* item = backForward()->itemAtIndex(distance);
334     if (!item) {
335         if (distance > 0) {
336             if (int forwardCount = backForward()->forwardCount())
337                 item = backForward()->itemAtIndex(forwardCount);
338         } else {
339             if (int backCount = backForward()->backCount())
340                 item = backForward()->itemAtIndex(-backCount);
341         }
342     }
343 
344     ASSERT(item);
345     if (!item)
346         return;
347 
348     goToItem(item, FrameLoadTypeIndexedBackForward);
349 }
350 
goToItem(HistoryItem * item,FrameLoadType type)351 void Page::goToItem(HistoryItem* item, FrameLoadType type)
352 {
353     if (defersLoading())
354         return;
355 
356     // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
357     // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
358     RefPtr<HistoryItem> protector(item);
359 
360     if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
361         m_mainFrame->loader()->stopAllLoaders();
362 
363     m_mainFrame->loader()->history()->goToItem(item, type);
364 }
365 
getHistoryLength()366 int Page::getHistoryLength()
367 {
368     return backForward()->backCount() + 1 + backForward()->forwardCount();
369 }
370 
setGroupName(const String & name)371 void Page::setGroupName(const String& name)
372 {
373     if (m_group && !m_group->name().isEmpty()) {
374         ASSERT(m_group != m_singlePageGroup.get());
375         ASSERT(!m_singlePageGroup);
376         m_group->removePage(this);
377     }
378 
379     if (name.isEmpty())
380         m_group = m_singlePageGroup.get();
381     else {
382         m_singlePageGroup.clear();
383         m_group = PageGroup::pageGroup(name);
384         m_group->addPage(this);
385     }
386 }
387 
groupName() const388 const String& Page::groupName() const
389 {
390     DEFINE_STATIC_LOCAL(String, nullString, ());
391     return m_group ? m_group->name() : nullString;
392 }
393 
initGroup()394 void Page::initGroup()
395 {
396     ASSERT(!m_singlePageGroup);
397     ASSERT(!m_group);
398     m_singlePageGroup.set(new PageGroup(this));
399     m_group = m_singlePageGroup.get();
400 }
401 
scheduleForcedStyleRecalcForAllPages()402 void Page::scheduleForcedStyleRecalcForAllPages()
403 {
404     if (!allPages)
405         return;
406     HashSet<Page*>::iterator end = allPages->end();
407     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
408         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
409             frame->document()->scheduleForcedStyleRecalc();
410 }
411 
setNeedsRecalcStyleInAllFrames()412 void Page::setNeedsRecalcStyleInAllFrames()
413 {
414     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
415         frame->document()->styleSelectorChanged(DeferRecalcStyle);
416 }
417 
updateViewportArguments()418 void Page::updateViewportArguments()
419 {
420     if (!mainFrame() || !mainFrame()->document() || mainFrame()->document()->viewportArguments() == m_viewportArguments)
421         return;
422 
423     m_viewportArguments = mainFrame()->document()->viewportArguments();
424     chrome()->dispatchViewportDataDidChange(m_viewportArguments);
425 }
426 
refreshPlugins(bool reload)427 void Page::refreshPlugins(bool reload)
428 {
429     if (!allPages)
430         return;
431 
432     PluginData::refresh();
433 
434     Vector<RefPtr<Frame> > framesNeedingReload;
435 
436     HashSet<Page*>::iterator end = allPages->end();
437     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
438         Page* page = *it;
439 
440         // Clear out the page's plug-in data.
441         if (page->m_pluginData)
442             page->m_pluginData = 0;
443 
444         if (!reload)
445             continue;
446 
447         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
448             if (frame->loader()->subframeLoader()->containsPlugins())
449                 framesNeedingReload.append(frame);
450         }
451     }
452 
453     for (size_t i = 0; i < framesNeedingReload.size(); ++i)
454         framesNeedingReload[i]->loader()->reload();
455 }
456 
pluginData() const457 PluginData* Page::pluginData() const
458 {
459     if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
460         return 0;
461     if (!m_pluginData)
462         m_pluginData = PluginData::create(this);
463     return m_pluginData.get();
464 }
465 
takeAnyMediaCanStartListener()466 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
467 {
468     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
469         if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
470             return listener;
471     }
472     return 0;
473 }
474 
setCanStartMedia(bool canStartMedia)475 void Page::setCanStartMedia(bool canStartMedia)
476 {
477     if (m_canStartMedia == canStartMedia)
478         return;
479 
480     m_canStartMedia = canStartMedia;
481 
482     while (m_canStartMedia) {
483         MediaCanStartListener* listener = takeAnyMediaCanStartListener();
484         if (!listener)
485             break;
486         listener->mediaCanStart();
487     }
488 }
489 
incrementFrame(Frame * curr,bool forward,bool wrapFlag)490 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
491 {
492     return forward
493         ? curr->tree()->traverseNextWithWrap(wrapFlag)
494         : curr->tree()->traversePreviousWithWrap(wrapFlag);
495 }
496 
findString(const String & target,TextCaseSensitivity caseSensitivity,FindDirection direction,bool shouldWrap)497 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
498 {
499     return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
500 }
501 
findString(const String & target,FindOptions options)502 bool Page::findString(const String& target, FindOptions options)
503 {
504     if (target.isEmpty() || !mainFrame())
505         return false;
506 
507     bool shouldWrap = options & WrapAround;
508     Frame* frame = focusController()->focusedOrMainFrame();
509     Frame* startFrame = frame;
510     do {
511         if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
512             if (frame != startFrame)
513                 startFrame->selection()->clear();
514             focusController()->setFocusedFrame(frame);
515             return true;
516         }
517         frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
518     } while (frame && frame != startFrame);
519 
520     // Search contents of startFrame, on the other side of the selection that we did earlier.
521     // We cheat a bit and just research with wrap on
522     if (shouldWrap && !startFrame->selection()->isNone()) {
523         bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection);
524         focusController()->setFocusedFrame(frame);
525         return found;
526     }
527 
528     return false;
529 }
530 
markAllMatchesForText(const String & target,TextCaseSensitivity caseSensitivity,bool shouldHighlight,unsigned limit)531 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
532 {
533     return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
534 }
535 
markAllMatchesForText(const String & target,FindOptions options,bool shouldHighlight,unsigned limit)536 unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
537 {
538     if (target.isEmpty() || !mainFrame())
539         return 0;
540 
541     unsigned matches = 0;
542 
543     Frame* frame = mainFrame();
544     do {
545         frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
546         matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true);
547         frame = incrementFrame(frame, true, false);
548     } while (frame);
549 
550     return matches;
551 }
552 
unmarkAllTextMatches()553 void Page::unmarkAllTextMatches()
554 {
555     if (!mainFrame())
556         return;
557 
558     Frame* frame = mainFrame();
559     do {
560         frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
561         frame = incrementFrame(frame, true, false);
562     } while (frame);
563 }
564 
selection() const565 const VisibleSelection& Page::selection() const
566 {
567     return focusController()->focusedOrMainFrame()->selection()->selection();
568 }
569 
setDefersLoading(bool defers)570 void Page::setDefersLoading(bool defers)
571 {
572     if (!m_settings->loadDeferringEnabled())
573         return;
574 
575     if (defers == m_defersLoading)
576         return;
577 
578     m_defersLoading = defers;
579     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
580         frame->loader()->setDefersLoading(defers);
581 }
582 
clearUndoRedoOperations()583 void Page::clearUndoRedoOperations()
584 {
585     m_editorClient->clearUndoRedoOperations();
586 }
587 
inLowQualityImageInterpolationMode() const588 bool Page::inLowQualityImageInterpolationMode() const
589 {
590     return m_inLowQualityInterpolationMode;
591 }
592 
setInLowQualityImageInterpolationMode(bool mode)593 void Page::setInLowQualityImageInterpolationMode(bool mode)
594 {
595     m_inLowQualityInterpolationMode = mode;
596 }
597 
setMediaVolume(float volume)598 void Page::setMediaVolume(float volume)
599 {
600     if (volume < 0 || volume > 1)
601         return;
602 
603     if (m_mediaVolume == volume)
604         return;
605 
606     m_mediaVolume = volume;
607     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
608         frame->document()->mediaVolumeDidChange();
609     }
610 }
611 
didMoveOnscreen()612 void Page::didMoveOnscreen()
613 {
614     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
615         if (frame->view())
616             frame->view()->didMoveOnscreen();
617     }
618 }
619 
willMoveOffscreen()620 void Page::willMoveOffscreen()
621 {
622     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
623         if (frame->view())
624             frame->view()->willMoveOffscreen();
625     }
626 }
627 
userStyleSheetLocationChanged()628 void Page::userStyleSheetLocationChanged()
629 {
630     // FIXME: Eventually we will move to a model of just being handed the sheet
631     // text instead of loading the URL ourselves.
632     KURL url = m_settings->userStyleSheetLocation();
633     if (url.isLocalFile())
634         m_userStyleSheetPath = url.fileSystemPath();
635     else
636         m_userStyleSheetPath = String();
637 
638     m_didLoadUserStyleSheet = false;
639     m_userStyleSheet = String();
640     m_userStyleSheetModificationTime = 0;
641 
642     // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
643     // synchronously and avoid using a loader.
644     if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
645         m_didLoadUserStyleSheet = true;
646 
647         Vector<char> styleSheetAsUTF8;
648         if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, IgnoreWhitespace))
649             m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
650     }
651 
652     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
653         if (frame->document())
654             frame->document()->updatePageUserSheet();
655     }
656 }
657 
userStyleSheet() const658 const String& Page::userStyleSheet() const
659 {
660     if (m_userStyleSheetPath.isEmpty())
661         return m_userStyleSheet;
662 
663     time_t modTime;
664     if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
665         // The stylesheet either doesn't exist, was just deleted, or is
666         // otherwise unreadable. If we've read the stylesheet before, we should
667         // throw away that data now as it no longer represents what's on disk.
668         m_userStyleSheet = String();
669         return m_userStyleSheet;
670     }
671 
672     // If the stylesheet hasn't changed since the last time we read it, we can
673     // just return the old data.
674     if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
675         return m_userStyleSheet;
676 
677     m_didLoadUserStyleSheet = true;
678     m_userStyleSheet = String();
679     m_userStyleSheetModificationTime = modTime;
680 
681     // FIXME: It would be better to load this asynchronously to avoid blocking
682     // the process, but we will first need to create an asynchronous loading
683     // mechanism that is not tied to a particular Frame. We will also have to
684     // determine what our behavior should be before the stylesheet is loaded
685     // and what should happen when it finishes loading, especially with respect
686     // to when the load event fires, when Document::close is called, and when
687     // layout/paint are allowed to happen.
688     RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
689     if (!data)
690         return m_userStyleSheet;
691 
692     RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
693     m_userStyleSheet = decoder->decode(data->data(), data->size());
694     m_userStyleSheet += decoder->flush();
695 
696     return m_userStyleSheet;
697 }
698 
removeAllVisitedLinks()699 void Page::removeAllVisitedLinks()
700 {
701     if (!allPages)
702         return;
703     HashSet<PageGroup*> groups;
704     HashSet<Page*>::iterator pagesEnd = allPages->end();
705     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
706         if (PageGroup* group = (*it)->groupPtr())
707             groups.add(group);
708     }
709     HashSet<PageGroup*>::iterator groupsEnd = groups.end();
710     for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
711         (*it)->removeVisitedLinks();
712 }
713 
allVisitedStateChanged(PageGroup * group)714 void Page::allVisitedStateChanged(PageGroup* group)
715 {
716     ASSERT(group);
717     if (!allPages)
718         return;
719 
720     HashSet<Page*>::iterator pagesEnd = allPages->end();
721     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
722         Page* page = *it;
723         if (page->m_group != group)
724             continue;
725         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
726             if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
727                 styleSelector->allVisitedStateChanged();
728         }
729     }
730 }
731 
visitedStateChanged(PageGroup * group,LinkHash visitedLinkHash)732 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
733 {
734     ASSERT(group);
735     if (!allPages)
736         return;
737 
738     HashSet<Page*>::iterator pagesEnd = allPages->end();
739     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
740         Page* page = *it;
741         if (page->m_group != group)
742             continue;
743         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
744             if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
745                 styleSelector->visitedStateChanged(visitedLinkHash);
746         }
747     }
748 }
749 
setDebuggerForAllPages(JSC::Debugger * debugger)750 void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
751 {
752     ASSERT(allPages);
753 
754     HashSet<Page*>::iterator end = allPages->end();
755     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
756         (*it)->setDebugger(debugger);
757 }
758 
setDebugger(JSC::Debugger * debugger)759 void Page::setDebugger(JSC::Debugger* debugger)
760 {
761     if (m_debugger == debugger)
762         return;
763 
764     m_debugger = debugger;
765 
766     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
767         frame->script()->attachDebugger(m_debugger);
768 }
769 
sharedGraphicsContext3D()770 SharedGraphicsContext3D* Page::sharedGraphicsContext3D()
771 {
772 #if ENABLE(ACCELERATED_2D_CANVAS)
773     if (!m_sharedGraphicsContext3D)
774         m_sharedGraphicsContext3D = SharedGraphicsContext3D::create(chrome());
775 
776     return m_sharedGraphicsContext3D.get();
777 #else
778     return 0;
779 #endif
780 }
781 
782 #if ENABLE(DOM_STORAGE)
sessionStorage(bool optionalCreate)783 StorageNamespace* Page::sessionStorage(bool optionalCreate)
784 {
785     if (!m_sessionStorage && optionalCreate)
786         m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
787 
788     return m_sessionStorage.get();
789 }
790 
setSessionStorage(PassRefPtr<StorageNamespace> newStorage)791 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
792 {
793     m_sessionStorage = newStorage;
794 }
795 #endif
796 
797 #if ENABLE(WML)
wmlPageState()798 WMLPageState* Page::wmlPageState()
799 {
800     if (!m_wmlPageState)
801         m_wmlPageState.set(new WMLPageState(this));
802     return m_wmlPageState.get();
803 }
804 #endif
805 
setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)806 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
807 {
808     if (customHTMLTokenizerTimeDelay < 0) {
809         m_customHTMLTokenizerTimeDelay = -1;
810         return;
811     }
812     m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
813 }
814 
setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)815 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
816 {
817     if (customHTMLTokenizerChunkSize < 0) {
818         m_customHTMLTokenizerChunkSize = -1;
819         return;
820     }
821     m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
822 }
823 
setMemoryCacheClientCallsEnabled(bool enabled)824 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
825 {
826     if (m_areMemoryCacheClientCallsEnabled == enabled)
827         return;
828 
829     m_areMemoryCacheClientCallsEnabled = enabled;
830     if (!enabled)
831         return;
832 
833     for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
834         frame->loader()->tellClientAboutPastMemoryCacheLoads();
835 }
836 
setJavaScriptURLsAreAllowed(bool areAllowed)837 void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
838 {
839     m_javaScriptURLsAreAllowed = areAllowed;
840 }
841 
javaScriptURLsAreAllowed() const842 bool Page::javaScriptURLsAreAllowed() const
843 {
844     return m_javaScriptURLsAreAllowed;
845 }
846 
setMinimumTimerInterval(double minimumTimerInterval)847 void Page::setMinimumTimerInterval(double minimumTimerInterval)
848 {
849     double oldTimerInterval = m_minimumTimerInterval;
850     m_minimumTimerInterval = minimumTimerInterval;
851     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) {
852         if (frame->document())
853             frame->document()->adjustMinimumTimerInterval(oldTimerInterval);
854     }
855 }
856 
minimumTimerInterval() const857 double Page::minimumTimerInterval() const
858 {
859     return m_minimumTimerInterval;
860 }
861 
862 #if ENABLE(INPUT_SPEECH)
speechInput()863 SpeechInput* Page::speechInput()
864 {
865     ASSERT(m_speechInputClient);
866     if (!m_speechInput.get())
867         m_speechInput.set(new SpeechInput(m_speechInputClient));
868     return m_speechInput.get();
869 }
870 #endif
871 
dnsPrefetchingStateChanged()872 void Page::dnsPrefetchingStateChanged()
873 {
874     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
875         frame->document()->initDNSPrefetch();
876 }
877 
privateBrowsingStateChanged()878 void Page::privateBrowsingStateChanged()
879 {
880     bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
881 
882     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
883         frame->document()->privateBrowsingStateDidChange();
884 
885     // Collect the PluginViews in to a vector to ensure that action the plug-in takes
886     // from below privateBrowsingStateChanged does not affect their lifetime.
887     Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
888     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
889         FrameView* view = frame->view();
890         if (!view)
891             return;
892 
893         const HashSet<RefPtr<Widget> >* children = view->children();
894         ASSERT(children);
895 
896         HashSet<RefPtr<Widget> >::const_iterator end = children->end();
897         for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
898             Widget* widget = (*it).get();
899             if (widget->isPluginViewBase())
900                 pluginViewBases.append(static_cast<PluginViewBase*>(widget));
901         }
902     }
903 
904     for (size_t i = 0; i < pluginViewBases.size(); ++i)
905         pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
906 }
907 
pluginAllowedRunTimeChanged()908 void Page::pluginAllowedRunTimeChanged()
909 {
910     if (m_pluginHalter)
911         m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
912 }
913 
didStartPlugin(HaltablePlugin * obj)914 void Page::didStartPlugin(HaltablePlugin* obj)
915 {
916     if (m_pluginHalter)
917         m_pluginHalter->didStartPlugin(obj);
918 }
919 
didStopPlugin(HaltablePlugin * obj)920 void Page::didStopPlugin(HaltablePlugin* obj)
921 {
922     if (m_pluginHalter)
923         m_pluginHalter->didStopPlugin(obj);
924 }
925 
addScrollableArea(ScrollableArea * scrollableArea)926 void Page::addScrollableArea(ScrollableArea* scrollableArea)
927 {
928     if (!m_scrollableAreaSet)
929         m_scrollableAreaSet = adoptPtr(new ScrollableAreaSet);
930     m_scrollableAreaSet->add(scrollableArea);
931 }
932 
removeScrollableArea(ScrollableArea * scrollableArea)933 void Page::removeScrollableArea(ScrollableArea* scrollableArea)
934 {
935     if (!m_scrollableAreaSet)
936         return;
937     m_scrollableAreaSet->remove(scrollableArea);
938 }
939 
containsScrollableArea(ScrollableArea * scrollableArea) const940 bool Page::containsScrollableArea(ScrollableArea* scrollableArea) const
941 {
942     if (!m_scrollableAreaSet)
943         return false;
944     return m_scrollableAreaSet->contains(scrollableArea);
945 }
946 
947 #if !ASSERT_DISABLED
checkFrameCountConsistency() const948 void Page::checkFrameCountConsistency() const
949 {
950     ASSERT(m_frameCount >= 0);
951 
952     int frameCount = 0;
953     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
954         ++frameCount;
955 
956     ASSERT(m_frameCount + 1 == frameCount);
957 }
958 #endif
959 
PageClients()960 Page::PageClients::PageClients()
961     : chromeClient(0)
962     , contextMenuClient(0)
963     , editorClient(0)
964     , dragClient(0)
965     , inspectorClient(0)
966     , pluginHalterClient(0)
967     , geolocationClient(0)
968     , deviceMotionClient(0)
969     , deviceOrientationClient(0)
970     , speechInputClient(0)
971 {
972 }
973 
~PageClients()974 Page::PageClients::~PageClients()
975 {
976 }
977 
978 } // namespace WebCore
979