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