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