1/* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 "AlternativeTextClient.h" 24#include "AnimationController.h" 25#include "BackForwardClient.h" 26#include "BackForwardController.h" 27#include "Chrome.h" 28#include "ChromeClient.h" 29#include "ClientRectList.h" 30#include "ContextMenuClient.h" 31#include "ContextMenuController.h" 32#include "DocumentMarkerController.h" 33#include "DocumentStyleSheetCollection.h" 34#include "DragController.h" 35#include "Editor.h" 36#include "EditorClient.h" 37#include "Event.h" 38#include "EventNames.h" 39#include "ExceptionCode.h" 40#include "ExceptionCodePlaceholder.h" 41#include "FileSystem.h" 42#include "FocusController.h" 43#include "FrameLoader.h" 44#include "FrameLoaderClient.h" 45#include "FrameSelection.h" 46#include "FrameTree.h" 47#include "FrameView.h" 48#include "HTMLElement.h" 49#include "HistoryController.h" 50#include "HistoryItem.h" 51#include "InspectorController.h" 52#include "InspectorInstrumentation.h" 53#include "Logging.h" 54#include "MainFrame.h" 55#include "MediaCanStartListener.h" 56#include "Navigator.h" 57#include "NetworkStateNotifier.h" 58#include "PageActivityAssertionToken.h" 59#include "PageCache.h" 60#include "PageConsole.h" 61#include "PageDebuggable.h" 62#include "PageGroup.h" 63#include "PageThrottler.h" 64#include "PlugInClient.h" 65#include "PluginData.h" 66#include "PluginView.h" 67#include "PointerLockController.h" 68#include "ProgressTracker.h" 69#include "RenderLayerCompositor.h" 70#include "RenderTheme.h" 71#include "RenderView.h" 72#include "RenderWidget.h" 73#include "RuntimeEnabledFeatures.h" 74#include "SchemeRegistry.h" 75#include "ScriptController.h" 76#include "ScrollingCoordinator.h" 77#include "Settings.h" 78#include "SharedBuffer.h" 79#include "StorageArea.h" 80#include "StorageNamespace.h" 81#include "StyleResolver.h" 82#include "SubframeLoader.h" 83#include "TextResourceDecoder.h" 84#include "UserContentController.h" 85#include "UserInputBridge.h" 86#include "ViewStateChangeObserver.h" 87#include "VisitedLinkState.h" 88#include "VisitedLinkStore.h" 89#include "VoidCallback.h" 90#include "Widget.h" 91#include <wtf/HashMap.h> 92#include <wtf/RefCountedLeakCounter.h> 93#include <wtf/StdLibExtras.h> 94#include <wtf/text/Base64.h> 95#include <wtf/text/StringHash.h> 96 97#if ENABLE(WEB_REPLAY) 98#include "ReplayController.h" 99#include <replay/InputCursor.h> 100#endif 101 102namespace WebCore { 103 104static HashSet<Page*>* allPages; 105 106DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page")); 107 108static void networkStateChanged(bool isOnLine) 109{ 110 Vector<Ref<Frame>> frames; 111 112 // Get all the frames of all the pages in all the page groups 113 for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) { 114 for (Frame* frame = &(*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) 115 frames.append(*frame); 116 InspectorInstrumentation::networkStateChanged(*it); 117 } 118 119 AtomicString eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent; 120 for (unsigned i = 0; i < frames.size(); i++) 121 frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false)); 122} 123 124static const ViewState::Flags PageInitialViewState = ViewState::IsVisible | ViewState::IsInWindow; 125 126Page::Page(PageClients& pageClients) 127 : m_chrome(std::make_unique<Chrome>(*this, *pageClients.chromeClient)) 128 , m_dragCaretController(std::make_unique<DragCaretController>()) 129#if ENABLE(DRAG_SUPPORT) 130 , m_dragController(std::make_unique<DragController>(*this, *pageClients.dragClient)) 131#endif 132 , m_focusController(std::make_unique<FocusController>(*this, PageInitialViewState)) 133#if ENABLE(CONTEXT_MENUS) 134 , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageClients.contextMenuClient)) 135#endif 136 , m_userInputBridge(std::make_unique<UserInputBridge>(*this)) 137#if ENABLE(WEB_REPLAY) 138 , m_replayController(std::make_unique<ReplayController>(*this)) 139#endif 140#if ENABLE(INSPECTOR) 141 , m_inspectorController(std::make_unique<InspectorController>(*this, pageClients.inspectorClient)) 142#endif 143#if ENABLE(POINTER_LOCK) 144 , m_pointerLockController(std::make_unique<PointerLockController>(*this)) 145#endif 146 , m_settings(Settings::create(this)) 147 , m_progress(std::make_unique<ProgressTracker>(*pageClients.progressTrackerClient)) 148 , m_backForwardController(std::make_unique<BackForwardController>(*this, pageClients.backForwardClient)) 149 , m_mainFrame(MainFrame::create(*this, *pageClients.loaderClientForMainFrame)) 150 , m_theme(RenderTheme::themeForPage(this)) 151 , m_editorClient(pageClients.editorClient) 152 , m_plugInClient(pageClients.plugInClient) 153 , m_validationMessageClient(pageClients.validationMessageClient) 154 , m_subframeCount(0) 155 , m_openedByDOM(false) 156 , m_tabKeyCyclesThroughElements(true) 157 , m_defersLoading(false) 158 , m_defersLoadingCallCount(0) 159 , m_inLowQualityInterpolationMode(false) 160 , m_areMemoryCacheClientCallsEnabled(true) 161 , m_mediaVolume(1) 162 , m_pageScaleFactor(1) 163 , m_zoomedOutPageScaleFactor(0) 164 , m_deviceScaleFactor(1) 165 , m_topContentInset(0) 166#if ENABLE(IOS_TEXT_AUTOSIZING) 167 , m_textAutosizingWidth(0) 168#endif 169 , m_suppressScrollbarAnimations(false) 170 , m_verticalScrollElasticity(ScrollElasticityAllowed) 171 , m_horizontalScrollElasticity(ScrollElasticityAllowed) 172 , m_didLoadUserStyleSheet(false) 173 , m_userStyleSheetModificationTime(0) 174 , m_group(0) 175 , m_debugger(0) 176 , m_canStartMedia(true) 177#if ENABLE(VIEW_MODE_CSS_MEDIA) 178 , m_viewMode(ViewModeWindowed) 179#endif // ENABLE(VIEW_MODE_CSS_MEDIA) 180 , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval()) 181 , m_timerThrottlingEnabled(false) 182 , m_timerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()) 183 , m_isEditable(false) 184 , m_isPrerender(false) 185 , m_viewState(PageInitialViewState) 186 , m_requestedLayoutMilestones(0) 187 , m_headerHeight(0) 188 , m_footerHeight(0) 189 , m_isCountingRelevantRepaintedObjects(false) 190#ifndef NDEBUG 191 , m_isPainting(false) 192#endif 193 , m_alternativeTextClient(pageClients.alternativeTextClient) 194 , m_scriptedAnimationsSuspended(false) 195 , m_console(std::make_unique<PageConsole>(*this)) 196#if ENABLE(REMOTE_INSPECTOR) 197 , m_inspectorDebuggable(std::make_unique<PageDebuggable>(*this)) 198#endif 199 , m_lastSpatialNavigationCandidatesCount(0) // NOTE: Only called from Internals for Spatial Navigation testing. 200 , m_framesHandlingBeforeUnloadEvent(0) 201 , m_userContentController(WTF::move(pageClients.userContentController)) 202 , m_visitedLinkStore(WTF::move(pageClients.visitedLinkStore)) 203 , m_sessionID(SessionID::defaultSessionID()) 204 , m_isClosing(false) 205{ 206 ASSERT(m_editorClient); 207 208 setTimerThrottlingEnabled(m_viewState & ViewState::IsVisuallyIdle); 209 210 if (m_userContentController) 211 m_userContentController->addPage(*this); 212 213 if (m_visitedLinkStore) 214 m_visitedLinkStore->addPage(*this); 215 216 if (!allPages) { 217 allPages = new HashSet<Page*>; 218 219 networkStateNotifier().addNetworkStateChangeListener(networkStateChanged); 220 } 221 222 ASSERT(!allPages->contains(this)); 223 allPages->add(this); 224 225#ifndef NDEBUG 226 pageCounter.increment(); 227#endif 228 229#if ENABLE(REMOTE_INSPECTOR) 230 m_inspectorDebuggable->init(); 231#endif 232} 233 234Page::~Page() 235{ 236 m_mainFrame->setView(0); 237 setGroupName(String()); 238 allPages->remove(this); 239 240 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 241 frame->willDetachPage(); 242 frame->detachFromPage(); 243 } 244 245 m_editorClient->pageDestroyed(); 246 if (m_plugInClient) 247 m_plugInClient->pageDestroyed(); 248 if (m_alternativeTextClient) 249 m_alternativeTextClient->pageDestroyed(); 250 251#if ENABLE(INSPECTOR) 252 m_inspectorController->inspectedPageDestroyed(); 253#endif 254 255 if (m_scrollingCoordinator) 256 m_scrollingCoordinator->pageDestroyed(); 257 258 backForward().close(); 259 260#ifndef NDEBUG 261 pageCounter.decrement(); 262#endif 263 264 if (m_userContentController) 265 m_userContentController->removePage(*this); 266 if (m_visitedLinkStore) 267 m_visitedLinkStore->removePage(*this); 268} 269 270void Page::clearPreviousItemFromAllPages(HistoryItem* item) 271{ 272 if (!allPages) 273 return; 274 275 for (auto& page : *allPages) { 276 HistoryController& controller = page->mainFrame().loader().history(); 277 if (item == controller.previousItem()) { 278 controller.clearPreviousItem(); 279 return; 280 } 281 } 282} 283 284uint64_t Page::renderTreeSize() const 285{ 286 uint64_t total = 0; 287 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 288 if (!frame->document() || !frame->document()->renderView()) 289 continue; 290 total += frame->document()->renderView()->rendererCount(); 291 } 292 return total; 293} 294 295ViewportArguments Page::viewportArguments() const 296{ 297 return mainFrame().document() ? mainFrame().document()->viewportArguments() : ViewportArguments(); 298} 299 300ScrollingCoordinator* Page::scrollingCoordinator() 301{ 302 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { 303 m_scrollingCoordinator = chrome().client().createScrollingCoordinator(this); 304 if (!m_scrollingCoordinator) 305 m_scrollingCoordinator = ScrollingCoordinator::create(this); 306 } 307 308 return m_scrollingCoordinator.get(); 309} 310 311String Page::scrollingStateTreeAsText() 312{ 313 if (Document* document = m_mainFrame->document()) 314 document->updateLayout(); 315 316 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) 317 return scrollingCoordinator->scrollingStateTreeAsText(); 318 319 return String(); 320} 321 322String Page::synchronousScrollingReasonsAsText() 323{ 324 if (Document* document = m_mainFrame->document()) 325 document->updateLayout(); 326 327 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) 328 return scrollingCoordinator->synchronousScrollingReasonsAsText(); 329 330 return String(); 331} 332 333PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame) 334{ 335 if (Document* document = m_mainFrame->document()) 336 document->updateLayout(); 337 338 Vector<IntRect> rects; 339 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) 340 rects = scrollingCoordinator->computeNonFastScrollableRegion(frame, IntPoint()).rects(); 341 342 Vector<FloatQuad> quads(rects.size()); 343 for (size_t i = 0; i < rects.size(); ++i) 344 quads[i] = FloatRect(rects[i]); 345 return ClientRectList::create(quads); 346} 347 348#if ENABLE(VIEW_MODE_CSS_MEDIA) 349struct ViewModeInfo { 350 const char* name; 351 Page::ViewMode type; 352}; 353static const int viewModeMapSize = 5; 354static ViewModeInfo viewModeMap[viewModeMapSize] = { 355 {"windowed", Page::ViewModeWindowed}, 356 {"floating", Page::ViewModeFloating}, 357 {"fullscreen", Page::ViewModeFullscreen}, 358 {"maximized", Page::ViewModeMaximized}, 359 {"minimized", Page::ViewModeMinimized} 360}; 361 362Page::ViewMode Page::stringToViewMode(const String& text) 363{ 364 for (int i = 0; i < viewModeMapSize; ++i) { 365 if (text == viewModeMap[i].name) 366 return viewModeMap[i].type; 367 } 368 return Page::ViewModeInvalid; 369} 370 371void Page::setViewMode(ViewMode viewMode) 372{ 373 if (viewMode == m_viewMode || viewMode == ViewModeInvalid) 374 return; 375 376 m_viewMode = viewMode; 377 378 if (!m_mainFrame) 379 return; 380 381 if (m_mainFrame->view()) 382 m_mainFrame->view()->forceLayout(); 383 384 if (m_mainFrame->document()) 385 m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately); 386} 387#endif // ENABLE(VIEW_MODE_CSS_MEDIA) 388 389bool Page::openedByDOM() const 390{ 391 return m_openedByDOM; 392} 393 394void Page::setOpenedByDOM() 395{ 396 m_openedByDOM = true; 397} 398 399void Page::goToItem(HistoryItem* item, FrameLoadType type) 400{ 401 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem 402 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later. 403 RefPtr<HistoryItem> protector(item); 404 405 if (m_mainFrame->loader().history().shouldStopLoadingForHistoryItem(item)) 406 m_mainFrame->loader().stopAllLoaders(); 407 408 m_mainFrame->loader().history().goToItem(item, type); 409} 410 411void Page::setGroupName(const String& name) 412{ 413 if (m_group && !m_group->name().isEmpty()) { 414 ASSERT(m_group != m_singlePageGroup.get()); 415 ASSERT(!m_singlePageGroup); 416 m_group->removePage(*this); 417 } 418 419 if (name.isEmpty()) 420 m_group = m_singlePageGroup.get(); 421 else { 422 m_singlePageGroup = nullptr; 423 m_group = PageGroup::pageGroup(name); 424 m_group->addPage(*this); 425 } 426} 427 428const String& Page::groupName() const 429{ 430 return m_group ? m_group->name() : nullAtom.string(); 431} 432 433void Page::initGroup() 434{ 435 ASSERT(!m_singlePageGroup); 436 ASSERT(!m_group); 437 m_singlePageGroup = std::make_unique<PageGroup>(*this); 438 m_group = m_singlePageGroup.get(); 439} 440 441void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment() 442{ 443 if (!allPages) 444 return; 445 HashSet<Page*>::iterator end = allPages->end(); 446 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) 447 for (Frame* frame = &(*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) { 448 // If a change in the global environment has occurred, we need to 449 // make sure all the properties a recomputed, therefore we invalidate 450 // the properties cache. 451 if (StyleResolver* styleResolver = frame->document()->styleResolverIfExists()) 452 styleResolver->invalidateMatchedPropertiesCache(); 453 frame->document()->scheduleForcedStyleRecalc(); 454 } 455} 456 457void Page::setNeedsRecalcStyleInAllFrames() 458{ 459 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 460 if (Document* document = frame->document()) 461 document->styleResolverChanged(DeferRecalcStyle); 462 } 463} 464 465void Page::refreshPlugins(bool reload) 466{ 467 if (!allPages) 468 return; 469 470 PluginData::refresh(); 471 472 Vector<Ref<Frame>> framesNeedingReload; 473 474 for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) { 475 Page& page = **it; 476 page.m_pluginData.clear(); 477 478 if (!reload) 479 continue; 480 481 for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) { 482 if (frame->loader().subframeLoader().containsPlugins()) 483 framesNeedingReload.append(*frame); 484 } 485 } 486 487 for (size_t i = 0; i < framesNeedingReload.size(); ++i) 488 framesNeedingReload[i]->loader().reload(); 489} 490 491PluginData& Page::pluginData() const 492{ 493 if (!m_pluginData) 494 m_pluginData = PluginData::create(this); 495 return *m_pluginData; 496} 497 498inline MediaCanStartListener* Page::takeAnyMediaCanStartListener() 499{ 500 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 501 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener()) 502 return listener; 503 } 504 return 0; 505} 506 507void Page::setCanStartMedia(bool canStartMedia) 508{ 509 if (m_canStartMedia == canStartMedia) 510 return; 511 512 m_canStartMedia = canStartMedia; 513 514 while (m_canStartMedia) { 515 MediaCanStartListener* listener = takeAnyMediaCanStartListener(); 516 if (!listener) 517 break; 518 listener->mediaCanStart(); 519 } 520} 521 522static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag) 523{ 524 return forward 525 ? curr->tree().traverseNextWithWrap(wrapFlag) 526 : curr->tree().traversePreviousWithWrap(wrapFlag); 527} 528 529bool Page::findString(const String& target, FindOptions options) 530{ 531 if (target.isEmpty()) 532 return false; 533 534 bool shouldWrap = options & WrapAround; 535 Frame* frame = &focusController().focusedOrMainFrame(); 536 Frame* startFrame = frame; 537 do { 538 if (frame->editor().findString(target, (options & ~WrapAround) | StartInSelection)) { 539 if (frame != startFrame) 540 startFrame->selection().clear(); 541 focusController().setFocusedFrame(frame); 542 return true; 543 } 544 frame = incrementFrame(frame, !(options & Backwards), shouldWrap); 545 } while (frame && frame != startFrame); 546 547 // Search contents of startFrame, on the other side of the selection that we did earlier. 548 // We cheat a bit and just research with wrap on 549 if (shouldWrap && !startFrame->selection().isNone()) { 550 bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection); 551 focusController().setFocusedFrame(frame); 552 return found; 553 } 554 555 return false; 556} 557 558void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>& matchRanges, int& indexForSelection) 559{ 560 indexForSelection = 0; 561 562 Frame* frame = &mainFrame(); 563 Frame* frameWithSelection = 0; 564 do { 565 frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges.size()) : 0, true, &matchRanges); 566 if (frame->selection().isRange()) 567 frameWithSelection = frame; 568 frame = incrementFrame(frame, true, false); 569 } while (frame); 570 571 if (matchRanges.isEmpty()) 572 return; 573 574 if (frameWithSelection) { 575 indexForSelection = NoMatchAfterUserSelection; 576 RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange(); 577 if (options & Backwards) { 578 for (size_t i = matchRanges.size(); i > 0; --i) { 579 if (selectedRange->compareBoundaryPoints(Range::END_TO_START, matchRanges[i - 1].get(), IGNORE_EXCEPTION) > 0) { 580 indexForSelection = i - 1; 581 break; 582 } 583 } 584 } else { 585 for (size_t i = 0, size = matchRanges.size(); i < size; ++i) { 586 if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges[i].get(), IGNORE_EXCEPTION) < 0) { 587 indexForSelection = i; 588 break; 589 } 590 } 591 } 592 } else { 593 if (options & Backwards) 594 indexForSelection = matchRanges.size() - 1; 595 else 596 indexForSelection = 0; 597 } 598} 599 600PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options) 601{ 602 if (target.isEmpty()) 603 return 0; 604 605 if (referenceRange && referenceRange->ownerDocument().page() != this) 606 return 0; 607 608 bool shouldWrap = options & WrapAround; 609 Frame* frame = referenceRange ? referenceRange->ownerDocument().frame() : &mainFrame(); 610 Frame* startFrame = frame; 611 do { 612 if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround)) 613 return resultRange.release(); 614 615 frame = incrementFrame(frame, !(options & Backwards), shouldWrap); 616 } while (frame && frame != startFrame); 617 618 // Search contents of startFrame, on the other side of the reference range that we did earlier. 619 // We cheat a bit and just search again with wrap on. 620 if (shouldWrap && referenceRange) { 621 if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection)) 622 return resultRange.release(); 623 } 624 625 return 0; 626} 627 628unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches) 629{ 630 if (target.isEmpty()) 631 return 0; 632 633 unsigned matchCount = 0; 634 635 Frame* frame = &mainFrame(); 636 do { 637 if (shouldMarkMatches == MarkMatches) 638 frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches); 639 matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0); 640 frame = incrementFrame(frame, true, false); 641 } while (frame); 642 643 return matchCount; 644} 645 646unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount) 647{ 648 return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches); 649} 650 651unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount) 652{ 653 return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches); 654} 655 656void Page::unmarkAllTextMatches() 657{ 658 Frame* frame = &mainFrame(); 659 do { 660 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch); 661 frame = incrementFrame(frame, true, false); 662 } while (frame); 663} 664 665const VisibleSelection& Page::selection() const 666{ 667 return focusController().focusedOrMainFrame().selection().selection(); 668} 669 670void Page::setDefersLoading(bool defers) 671{ 672 if (!m_settings->loadDeferringEnabled()) 673 return; 674 675 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) { 676 ASSERT(defers || m_defersLoadingCallCount); 677 if (defers && ++m_defersLoadingCallCount > 1) 678 return; 679 if (!defers && --m_defersLoadingCallCount) 680 return; 681 } else { 682 ASSERT(!m_defersLoadingCallCount); 683 if (defers == m_defersLoading) 684 return; 685 } 686 687 m_defersLoading = defers; 688 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 689 frame->loader().setDefersLoading(defers); 690} 691 692void Page::clearUndoRedoOperations() 693{ 694 m_editorClient->clearUndoRedoOperations(); 695} 696 697bool Page::inLowQualityImageInterpolationMode() const 698{ 699 return m_inLowQualityInterpolationMode; 700} 701 702void Page::setInLowQualityImageInterpolationMode(bool mode) 703{ 704 m_inLowQualityInterpolationMode = mode; 705} 706 707void Page::setMediaVolume(float volume) 708{ 709 if (volume < 0 || volume > 1) 710 return; 711 712 if (m_mediaVolume == volume) 713 return; 714 715 m_mediaVolume = volume; 716 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 717 frame->document()->mediaVolumeDidChange(); 718 } 719} 720 721void Page::setZoomedOutPageScaleFactor(float scale) 722{ 723 if (m_zoomedOutPageScaleFactor == scale) 724 return; 725 m_zoomedOutPageScaleFactor = scale; 726 727 mainFrame().deviceOrPageScaleFactorChanged(); 728} 729 730void Page::setPageScaleFactor(float scale, const IntPoint& origin, bool inStableState) 731{ 732 Document* document = mainFrame().document(); 733 FrameView* view = document->view(); 734 735 if (scale == m_pageScaleFactor) { 736 if (view && view->scrollPosition() != origin) { 737 if (!m_settings->delegatesPageScaling()) 738 document->updateLayoutIgnorePendingStylesheets(); 739 740 if (!view->delegatesScrolling()) 741 view->setScrollPosition(origin); 742#if USE(TILED_BACKING_STORE) 743 else 744 view->hostWindow()->delegatedScrollRequested(origin); 745#endif 746 } 747#if ENABLE(MEDIA_CONTROLS_SCRIPT) 748 if (inStableState) { 749 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 750 frame->document()->pageScaleFactorChangedAndStable(); 751 } 752#endif 753 return; 754 } 755 756 m_pageScaleFactor = scale; 757 758 if (!m_settings->delegatesPageScaling()) { 759 if (document->renderView()) 760 document->renderView()->setNeedsLayout(); 761 762 document->recalcStyle(Style::Force); 763 764 // Transform change on RenderView doesn't trigger repaint on non-composited contents. 765 mainFrame().view()->invalidateRect(IntRect(LayoutRect::infiniteRect())); 766 } 767 768 mainFrame().deviceOrPageScaleFactorChanged(); 769 770 if (view && view->fixedElementsLayoutRelativeToFrame()) 771 view->setViewportConstrainedObjectsNeedLayout(); 772 773 if (view && view->scrollPosition() != origin) { 774 if (!m_settings->delegatesPageScaling() && document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout()) 775 view->layout(); 776 777 if (!view->delegatesScrolling()) 778 view->setScrollPosition(origin); 779#if USE(TILED_BACKING_STORE) 780 else 781 view->hostWindow()->delegatedScrollRequested(origin); 782#endif 783 } 784 785#if ENABLE(MEDIA_CONTROLS_SCRIPT) 786 if (inStableState) { 787 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 788 frame->document()->pageScaleFactorChangedAndStable(); 789 } 790#endif 791} 792 793void Page::setDeviceScaleFactor(float scaleFactor) 794{ 795 ASSERT(scaleFactor > 0); 796 if (scaleFactor <= 0) 797 return; 798 799 if (m_deviceScaleFactor == scaleFactor) 800 return; 801 802 m_deviceScaleFactor = scaleFactor; 803 setNeedsRecalcStyleInAllFrames(); 804 805 mainFrame().deviceOrPageScaleFactorChanged(); 806 pageCache()->markPagesForDeviceScaleChanged(this); 807 808 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 809 frame->editor().deviceScaleFactorChanged(); 810 811 pageCache()->markPagesForFullStyleRecalc(this); 812 GraphicsContext::updateDocumentMarkerResources(); 813} 814 815void Page::setTopContentInset(float contentInset) 816{ 817 if (m_topContentInset == contentInset) 818 return; 819 820 m_topContentInset = contentInset; 821 822 if (FrameView* view = mainFrame().view()) 823 view->topContentInsetDidChange(m_topContentInset); 824} 825 826void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations) 827{ 828 if (suppressAnimations == m_suppressScrollbarAnimations) 829 return; 830 831 lockAllOverlayScrollbarsToHidden(suppressAnimations); 832 m_suppressScrollbarAnimations = suppressAnimations; 833} 834 835void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars) 836{ 837 FrameView* view = mainFrame().view(); 838 if (!view) 839 return; 840 841 view->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars); 842 843 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 844 FrameView* frameView = frame->view(); 845 if (!frameView) 846 continue; 847 848 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas(); 849 if (!scrollableAreas) 850 continue; 851 852 for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) { 853 ScrollableArea* scrollableArea = *it; 854 scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars); 855 } 856 } 857} 858 859void Page::setVerticalScrollElasticity(ScrollElasticity elasticity) 860{ 861 if (m_verticalScrollElasticity == elasticity) 862 return; 863 864 m_verticalScrollElasticity = elasticity; 865 866 if (FrameView* view = mainFrame().view()) 867 view->setVerticalScrollElasticity(elasticity); 868} 869 870void Page::setHorizontalScrollElasticity(ScrollElasticity elasticity) 871{ 872 if (m_horizontalScrollElasticity == elasticity) 873 return; 874 875 m_horizontalScrollElasticity = elasticity; 876 877 if (FrameView* view = mainFrame().view()) 878 view->setHorizontalScrollElasticity(elasticity); 879} 880 881void Page::setPagination(const Pagination& pagination) 882{ 883 if (m_pagination == pagination) 884 return; 885 886 m_pagination = pagination; 887 888 setNeedsRecalcStyleInAllFrames(); 889 pageCache()->markPagesForFullStyleRecalc(this); 890} 891 892unsigned Page::pageCount() const 893{ 894 if (m_pagination.mode == Pagination::Unpaginated) 895 return 0; 896 897 if (Document* document = mainFrame().document()) 898 document->updateLayoutIgnorePendingStylesheets(); 899 900 RenderView* contentRenderer = mainFrame().contentRenderer(); 901 return contentRenderer ? contentRenderer->pageCount() : 0; 902} 903 904void Page::setIsInWindow(bool isInWindow) 905{ 906 setViewState(isInWindow ? m_viewState | ViewState::IsInWindow : m_viewState & ~ViewState::IsInWindow); 907} 908 909void Page::setIsInWindowInternal(bool isInWindow) 910{ 911 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 912 if (FrameView* frameView = frame->view()) 913 frameView->setIsInWindow(isInWindow); 914 } 915 916 if (isInWindow) 917 resumeAnimatingImages(); 918} 919 920void Page::addViewStateChangeObserver(ViewStateChangeObserver& observer) 921{ 922 m_viewStateChangeObservers.add(&observer); 923} 924 925void Page::removeViewStateChangeObserver(ViewStateChangeObserver& observer) 926{ 927 m_viewStateChangeObservers.remove(&observer); 928} 929 930void Page::suspendScriptedAnimations() 931{ 932 m_scriptedAnimationsSuspended = true; 933 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 934 if (frame->document()) 935 frame->document()->suspendScriptedAnimationControllerCallbacks(); 936 } 937} 938 939void Page::resumeScriptedAnimations() 940{ 941 m_scriptedAnimationsSuspended = false; 942 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 943 if (frame->document()) 944 frame->document()->resumeScriptedAnimationControllerCallbacks(); 945 } 946} 947 948void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle) 949{ 950 setTimerThrottlingEnabled(isVisuallyIdle); 951 952 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 953 if (frame->document()) 954 frame->document()->scriptedAnimationControllerSetThrottled(isVisuallyIdle); 955 } 956} 957 958void Page::userStyleSheetLocationChanged() 959{ 960 // FIXME: Eventually we will move to a model of just being handed the sheet 961 // text instead of loading the URL ourselves. 962 URL url = m_settings->userStyleSheetLocation(); 963 964 // Allow any local file URL scheme to be loaded. 965 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol())) 966 m_userStyleSheetPath = url.fileSystemPath(); 967 else 968 m_userStyleSheetPath = String(); 969 970 m_didLoadUserStyleSheet = false; 971 m_userStyleSheet = String(); 972 m_userStyleSheetModificationTime = 0; 973 974 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them 975 // synchronously and avoid using a loader. 976 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) { 977 m_didLoadUserStyleSheet = true; 978 979 Vector<char> styleSheetAsUTF8; 980 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace)) 981 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size()); 982 } 983 984 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 985 if (frame->document()) 986 frame->document()->styleSheetCollection().updatePageUserSheet(); 987 } 988} 989 990const String& Page::userStyleSheet() const 991{ 992 if (m_userStyleSheetPath.isEmpty()) 993 return m_userStyleSheet; 994 995 time_t modTime; 996 if (!getFileModificationTime(m_userStyleSheetPath, modTime)) { 997 // The stylesheet either doesn't exist, was just deleted, or is 998 // otherwise unreadable. If we've read the stylesheet before, we should 999 // throw away that data now as it no longer represents what's on disk. 1000 m_userStyleSheet = String(); 1001 return m_userStyleSheet; 1002 } 1003 1004 // If the stylesheet hasn't changed since the last time we read it, we can 1005 // just return the old data. 1006 if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime) 1007 return m_userStyleSheet; 1008 1009 m_didLoadUserStyleSheet = true; 1010 m_userStyleSheet = String(); 1011 m_userStyleSheetModificationTime = modTime; 1012 1013 // FIXME: It would be better to load this asynchronously to avoid blocking 1014 // the process, but we will first need to create an asynchronous loading 1015 // mechanism that is not tied to a particular Frame. We will also have to 1016 // determine what our behavior should be before the stylesheet is loaded 1017 // and what should happen when it finishes loading, especially with respect 1018 // to when the load event fires, when Document::close is called, and when 1019 // layout/paint are allowed to happen. 1020 RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath); 1021 if (!data) 1022 return m_userStyleSheet; 1023 1024 m_userStyleSheet = TextResourceDecoder::create("text/css")->decodeAndFlush(data->data(), data->size()); 1025 1026 return m_userStyleSheet; 1027} 1028 1029void Page::removeAllVisitedLinks() 1030{ 1031 if (!allPages) 1032 return; 1033 HashSet<PageGroup*> groups; 1034 HashSet<Page*>::iterator pagesEnd = allPages->end(); 1035 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 1036 if (PageGroup* group = (*it)->groupPtr()) 1037 groups.add(group); 1038 } 1039 HashSet<PageGroup*>::iterator groupsEnd = groups.end(); 1040 for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it) 1041 (*it)->removeVisitedLinks(); 1042} 1043 1044void Page::invalidateStylesForAllLinks() 1045{ 1046 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) 1047 frame->document()->visitedLinkState().invalidateStyleForAllLinks(); 1048} 1049 1050void Page::invalidateStylesForLink(LinkHash linkHash) 1051{ 1052 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) 1053 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash); 1054} 1055 1056void Page::setDebugger(JSC::Debugger* debugger) 1057{ 1058 if (m_debugger == debugger) 1059 return; 1060 1061 m_debugger = debugger; 1062 1063 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) 1064 frame->script().attachDebugger(m_debugger); 1065} 1066 1067StorageNamespace* Page::sessionStorage(bool optionalCreate) 1068{ 1069 if (!m_sessionStorage && optionalCreate) 1070 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this); 1071 1072 return m_sessionStorage.get(); 1073} 1074 1075void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage) 1076{ 1077 m_sessionStorage = newStorage; 1078} 1079 1080bool Page::hasCustomHTMLTokenizerTimeDelay() const 1081{ 1082 return m_settings->maxParseDuration() != -1; 1083} 1084 1085double Page::customHTMLTokenizerTimeDelay() const 1086{ 1087 ASSERT(m_settings->maxParseDuration() != -1); 1088 return m_settings->maxParseDuration(); 1089} 1090 1091void Page::setMemoryCacheClientCallsEnabled(bool enabled) 1092{ 1093 if (m_areMemoryCacheClientCallsEnabled == enabled) 1094 return; 1095 1096 m_areMemoryCacheClientCallsEnabled = enabled; 1097 if (!enabled) 1098 return; 1099 1100 for (RefPtr<Frame> frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1101 frame->loader().tellClientAboutPastMemoryCacheLoads(); 1102} 1103 1104void Page::setMinimumTimerInterval(double minimumTimerInterval) 1105{ 1106 double oldTimerInterval = m_minimumTimerInterval; 1107 m_minimumTimerInterval = minimumTimerInterval; 1108 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) { 1109 if (frame->document()) 1110 frame->document()->adjustMinimumTimerInterval(oldTimerInterval); 1111 } 1112} 1113 1114double Page::minimumTimerInterval() const 1115{ 1116 return m_minimumTimerInterval; 1117} 1118 1119void Page::hiddenPageDOMTimerThrottlingStateChanged() 1120{ 1121 setTimerThrottlingEnabled(m_viewState & ViewState::IsVisuallyIdle); 1122} 1123 1124void Page::setTimerThrottlingEnabled(bool enabled) 1125{ 1126#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) 1127 if (!m_settings->hiddenPageDOMTimerThrottlingEnabled()) 1128 enabled = false; 1129#endif 1130 1131 if (enabled == m_timerThrottlingEnabled) 1132 return; 1133 1134 m_timerThrottlingEnabled = enabled; 1135 m_timerAlignmentInterval = enabled ? Settings::hiddenPageDOMTimerAlignmentInterval() : Settings::defaultDOMTimerAlignmentInterval(); 1136 1137 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) { 1138 if (frame->document()) 1139 frame->document()->didChangeTimerAlignmentInterval(); 1140 } 1141} 1142 1143void Page::dnsPrefetchingStateChanged() 1144{ 1145 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1146 frame->document()->initDNSPrefetch(); 1147} 1148 1149Vector<Ref<PluginViewBase>> Page::pluginViews() 1150{ 1151 Vector<Ref<PluginViewBase>> views; 1152 1153 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { 1154 FrameView* view = frame->view(); 1155 if (!view) 1156 break; 1157 1158 for (auto it = view->children().begin(), end = view->children().end(); it != end; ++it) { 1159 Widget* widget = (*it).get(); 1160 if (widget->isPluginViewBase()) 1161 views.append(*toPluginViewBase(widget)); 1162 } 1163 } 1164 1165 return views; 1166} 1167 1168void Page::storageBlockingStateChanged() 1169{ 1170 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1171 frame->document()->storageBlockingStateDidChange(); 1172 1173 // Collect the PluginViews in to a vector to ensure that action the plug-in takes 1174 // from below storageBlockingStateChanged does not affect their lifetime. 1175 auto views = pluginViews(); 1176 1177 for (unsigned i = 0; i < views.size(); ++i) 1178 views[i]->storageBlockingStateChanged(); 1179} 1180 1181void Page::enableLegacyPrivateBrowsing(bool privateBrowsingEnabled) 1182{ 1183 // Don't allow changing the legacy private browsing state if we have set a session ID. 1184 ASSERT(m_sessionID == SessionID::defaultSessionID() || m_sessionID == SessionID::legacyPrivateSessionID()); 1185 1186 setSessionID(privateBrowsingEnabled ? SessionID::legacyPrivateSessionID() : SessionID::defaultSessionID()); 1187} 1188 1189#if !ASSERT_DISABLED 1190void Page::checkSubframeCountConsistency() const 1191{ 1192 ASSERT(m_subframeCount >= 0); 1193 1194 int subframeCount = 0; 1195 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1196 ++subframeCount; 1197 1198 ASSERT(m_subframeCount + 1 == subframeCount); 1199} 1200#endif 1201 1202void Page::resumeAnimatingImages() 1203{ 1204 // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.) 1205 // require that we repaint animated images to kickstart the animation loop. 1206 if (FrameView* view = mainFrame().view()) 1207 view->resumeVisibleImageAnimationsIncludingSubframes(); 1208} 1209 1210void Page::createPageThrottler() 1211{ 1212 ASSERT(!m_pageThrottler); 1213 m_pageThrottler = std::make_unique<PageThrottler>(*this, m_viewState); 1214} 1215 1216void Page::setViewState(ViewState::Flags viewState) 1217{ 1218 ViewState::Flags changed = m_viewState ^ viewState; 1219 if (!changed) 1220 return; 1221 1222 ViewState::Flags oldViewState = m_viewState; 1223 1224 m_viewState = viewState; 1225 m_focusController->setViewState(viewState); 1226 if (m_pageThrottler) 1227 m_pageThrottler->setViewState(viewState); 1228 1229 if (changed & ViewState::IsVisible) 1230 setIsVisibleInternal(viewState & ViewState::IsVisible); 1231 if (changed & ViewState::IsInWindow) 1232 setIsInWindowInternal(viewState & ViewState::IsInWindow); 1233 if (changed & ViewState::IsVisuallyIdle) 1234 setIsVisuallyIdleInternal(viewState & ViewState::IsVisuallyIdle); 1235 1236 for (auto* observer : m_viewStateChangeObservers) 1237 observer->viewStateDidChange(oldViewState, m_viewState); 1238} 1239 1240void Page::setIsVisible(bool isVisible) 1241{ 1242 if (isVisible) 1243 setViewState((m_viewState & ~ViewState::IsVisuallyIdle) | ViewState::IsVisible | ViewState::IsVisibleOrOccluded); 1244 else 1245 setViewState((m_viewState & ~(ViewState::IsVisible | ViewState::IsVisibleOrOccluded)) | ViewState::IsVisuallyIdle); 1246} 1247 1248void Page::setIsVisibleInternal(bool isVisible) 1249{ 1250 // FIXME: The visibility state should be stored on the top-level document. 1251 // https://bugs.webkit.org/show_bug.cgi?id=116769 1252 1253 if (isVisible) { 1254 m_isPrerender = false; 1255 1256 resumeScriptedAnimations(); 1257 1258 if (FrameView* view = mainFrame().view()) 1259 view->show(); 1260 1261 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) 1262 mainFrame().animation().resumeAnimations(); 1263 1264 resumeAnimatingImages(); 1265 } 1266 1267 Vector<Ref<Document>> documents; 1268 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) 1269 documents.append(*frame->document()); 1270 1271 for (size_t i = 0, size = documents.size(); i < size; ++i) 1272 documents[i]->visibilityStateChanged(); 1273 1274 if (!isVisible) { 1275 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) 1276 mainFrame().animation().suspendAnimations(); 1277 1278 suspendScriptedAnimations(); 1279 1280 if (FrameView* view = mainFrame().view()) 1281 view->hide(); 1282 } 1283} 1284 1285void Page::setIsPrerender() 1286{ 1287 m_isPrerender = true; 1288} 1289 1290PageVisibilityState Page::visibilityState() const 1291{ 1292 if (isVisible()) 1293 return PageVisibilityStateVisible; 1294 if (m_isPrerender) 1295 return PageVisibilityStatePrerender; 1296 return PageVisibilityStateHidden; 1297} 1298 1299#if ENABLE(RUBBER_BANDING) 1300void Page::addHeaderWithHeight(int headerHeight) 1301{ 1302 m_headerHeight = headerHeight; 1303 1304 FrameView* frameView = mainFrame().view(); 1305 if (!frameView) 1306 return; 1307 1308 RenderView* renderView = frameView->renderView(); 1309 if (!renderView) 1310 return; 1311 1312 frameView->setHeaderHeight(m_headerHeight); 1313 renderView->compositor().updateLayerForHeader(m_headerHeight); 1314} 1315 1316void Page::addFooterWithHeight(int footerHeight) 1317{ 1318 m_footerHeight = footerHeight; 1319 1320 FrameView* frameView = mainFrame().view(); 1321 if (!frameView) 1322 return; 1323 1324 RenderView* renderView = frameView->renderView(); 1325 if (!renderView) 1326 return; 1327 1328 frameView->setFooterHeight(m_footerHeight); 1329 renderView->compositor().updateLayerForFooter(m_footerHeight); 1330} 1331#endif 1332 1333#if ENABLE(REMOTE_INSPECTOR) 1334bool Page::remoteInspectionAllowed() const 1335{ 1336 return m_inspectorDebuggable->remoteDebuggingAllowed(); 1337} 1338 1339void Page::setRemoteInspectionAllowed(bool allowed) 1340{ 1341 m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed); 1342} 1343 1344void Page::remoteInspectorInformationDidChange() const 1345{ 1346 m_inspectorDebuggable->update(); 1347} 1348#endif 1349 1350void Page::addLayoutMilestones(LayoutMilestones milestones) 1351{ 1352 // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it. 1353 m_requestedLayoutMilestones |= milestones; 1354} 1355 1356void Page::removeLayoutMilestones(LayoutMilestones milestones) 1357{ 1358 m_requestedLayoutMilestones &= ~milestones; 1359} 1360 1361Color Page::pageExtendedBackgroundColor() const 1362{ 1363 FrameView* frameView = mainFrame().view(); 1364 if (!frameView) 1365 return Color(); 1366 1367 RenderView* renderView = frameView->renderView(); 1368 if (!renderView) 1369 return Color(); 1370 1371 return renderView->compositor().rootExtendedBackgroundColor(); 1372} 1373 1374// These are magical constants that might be tweaked over time. 1375static double gMinimumPaintedAreaRatio = 0.1; 1376static double gMaximumUnpaintedAreaRatio = 0.04; 1377 1378bool Page::isCountingRelevantRepaintedObjects() const 1379{ 1380 return m_isCountingRelevantRepaintedObjects && (m_requestedLayoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold); 1381} 1382 1383void Page::startCountingRelevantRepaintedObjects() 1384{ 1385 // Reset everything in case we didn't hit the threshold last time. 1386 resetRelevantPaintedObjectCounter(); 1387 1388 m_isCountingRelevantRepaintedObjects = true; 1389} 1390 1391void Page::resetRelevantPaintedObjectCounter() 1392{ 1393 m_isCountingRelevantRepaintedObjects = false; 1394 m_relevantUnpaintedRenderObjects.clear(); 1395 m_topRelevantPaintedRegion = Region(); 1396 m_bottomRelevantPaintedRegion = Region(); 1397 m_relevantUnpaintedRegion = Region(); 1398} 1399 1400static LayoutRect relevantViewRect(RenderView* view) 1401{ 1402 // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that 1403 // a certain relevant amount of content has been drawn to the screen. This is the rect that 1404 // has been determined to be relevant in the context of this goal. We may choose to tweak 1405 // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and 1406 // gMaximumUnpaintedAreaRatio. But this seems to work well right now. 1407 LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300); 1408 1409 LayoutRect viewRect = view->viewRect(); 1410 // If the viewRect is wider than the relevantViewRect, center the relevantViewRect. 1411 if (viewRect.width() > relevantViewRect.width()) 1412 relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2); 1413 1414 return relevantViewRect; 1415} 1416 1417void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect) 1418{ 1419 if (!isCountingRelevantRepaintedObjects()) 1420 return; 1421 1422 // Objects inside sub-frames are not considered to be relevant. 1423 if (&object->frame() != &mainFrame()) 1424 return; 1425 1426 LayoutRect relevantRect = relevantViewRect(&object->view()); 1427 1428 // The objects are only relevant if they are being painted within the viewRect(). 1429 if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantRect))) 1430 return; 1431 1432 IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect); 1433 1434 // If this object was previously counted as an unpainted object, remove it from that HashSet 1435 // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap. 1436 if (m_relevantUnpaintedRenderObjects.remove(object)) 1437 m_relevantUnpaintedRegion.subtract(snappedPaintRect); 1438 1439 // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in 1440 // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with 1441 // no content beneath that. 1442 LayoutRect topRelevantRect = relevantRect; 1443 topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2)); 1444 LayoutRect bottomRelevantRect = topRelevantRect; 1445 bottomRelevantRect.setY(relevantRect.height() / 2); 1446 1447 // If the rect straddles both Regions, split it appropriately. 1448 if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) { 1449 IntRect topIntersection = snappedPaintRect; 1450 topIntersection.intersect(pixelSnappedIntRect(topRelevantRect)); 1451 m_topRelevantPaintedRegion.unite(topIntersection); 1452 1453 IntRect bottomIntersection = snappedPaintRect; 1454 bottomIntersection.intersect(pixelSnappedIntRect(bottomRelevantRect)); 1455 m_bottomRelevantPaintedRegion.unite(bottomIntersection); 1456 } else if (topRelevantRect.intersects(snappedPaintRect)) 1457 m_topRelevantPaintedRegion.unite(snappedPaintRect); 1458 else 1459 m_bottomRelevantPaintedRegion.unite(snappedPaintRect); 1460 1461 float topPaintedArea = m_topRelevantPaintedRegion.totalArea(); 1462 float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea(); 1463 float viewArea = relevantRect.width() * relevantRect.height(); 1464 1465 float ratioThatIsPaintedOnTop = topPaintedArea / viewArea; 1466 float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea; 1467 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea; 1468 1469 if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2) 1470 && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) { 1471 m_isCountingRelevantRepaintedObjects = false; 1472 resetRelevantPaintedObjectCounter(); 1473 if (Frame* frame = &mainFrame()) 1474 frame->loader().didLayout(DidHitRelevantRepaintedObjectsAreaThreshold); 1475 } 1476} 1477 1478void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect) 1479{ 1480 if (!isCountingRelevantRepaintedObjects()) 1481 return; 1482 1483 // The objects are only relevant if they are being painted within the relevantViewRect(). 1484 if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantViewRect(&object->view())))) 1485 return; 1486 1487 m_relevantUnpaintedRenderObjects.add(object); 1488 m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect)); 1489} 1490 1491void Page::suspendActiveDOMObjectsAndAnimations() 1492{ 1493 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1494 frame->suspendActiveDOMObjectsAndAnimations(); 1495} 1496 1497void Page::resumeActiveDOMObjectsAndAnimations() 1498{ 1499 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1500 frame->resumeActiveDOMObjectsAndAnimations(); 1501 1502 resumeAnimatingImages(); 1503} 1504 1505bool Page::hasSeenAnyPlugin() const 1506{ 1507 return !m_seenPlugins.isEmpty(); 1508} 1509 1510bool Page::hasSeenPlugin(const String& serviceType) const 1511{ 1512 return m_seenPlugins.contains(serviceType); 1513} 1514 1515void Page::sawPlugin(const String& serviceType) 1516{ 1517 m_seenPlugins.add(serviceType); 1518} 1519 1520void Page::resetSeenPlugins() 1521{ 1522 m_seenPlugins.clear(); 1523} 1524 1525bool Page::hasSeenAnyMediaEngine() const 1526{ 1527 return !m_seenMediaEngines.isEmpty(); 1528} 1529 1530bool Page::hasSeenMediaEngine(const String& engineDescription) const 1531{ 1532 return m_seenMediaEngines.contains(engineDescription); 1533} 1534 1535void Page::sawMediaEngine(const String& engineDescription) 1536{ 1537 m_seenMediaEngines.add(engineDescription); 1538} 1539 1540void Page::resetSeenMediaEngines() 1541{ 1542 m_seenMediaEngines.clear(); 1543} 1544 1545void Page::hiddenPageCSSAnimationSuspensionStateChanged() 1546{ 1547 if (!isVisible()) { 1548 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) 1549 mainFrame().animation().suspendAnimations(); 1550 else 1551 mainFrame().animation().resumeAnimations(); 1552 } 1553} 1554 1555#if ENABLE(VIDEO_TRACK) 1556void Page::captionPreferencesChanged() 1557{ 1558 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1559 frame->document()->captionPreferencesChanged(); 1560} 1561#endif 1562 1563void Page::incrementFrameHandlingBeforeUnloadEventCount() 1564{ 1565 ++m_framesHandlingBeforeUnloadEvent; 1566} 1567 1568void Page::decrementFrameHandlingBeforeUnloadEventCount() 1569{ 1570 ASSERT(m_framesHandlingBeforeUnloadEvent); 1571 --m_framesHandlingBeforeUnloadEvent; 1572} 1573 1574bool Page::isAnyFrameHandlingBeforeUnloadEvent() 1575{ 1576 return m_framesHandlingBeforeUnloadEvent; 1577} 1578 1579void Page::setUserContentController(UserContentController* userContentController) 1580{ 1581 if (m_userContentController) 1582 m_userContentController->removePage(*this); 1583 1584 m_userContentController = userContentController; 1585 1586 if (m_userContentController) 1587 m_userContentController->addPage(*this); 1588} 1589 1590VisitedLinkStore& Page::visitedLinkStore() 1591{ 1592 if (m_visitedLinkStore) 1593 return *m_visitedLinkStore; 1594 1595 return group().visitedLinkStore(); 1596} 1597 1598SessionID Page::sessionID() const 1599{ 1600 return m_sessionID; 1601} 1602 1603void Page::setSessionID(SessionID sessionID) 1604{ 1605 ASSERT(sessionID.isValid()); 1606 1607 bool privateBrowsingStateChanged = (sessionID.isEphemeral() != m_sessionID.isEphemeral()); 1608 1609 m_sessionID = sessionID; 1610 1611 if (!privateBrowsingStateChanged) 1612 return; 1613 1614 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) 1615 frame->document()->privateBrowsingStateDidChange(); 1616 1617 // Collect the PluginViews in to a vector to ensure that action the plug-in takes 1618 // from below privateBrowsingStateChanged does not affect their lifetime. 1619 1620 for (auto& view : pluginViews()) 1621 view->privateBrowsingStateChanged(sessionID.isEphemeral()); 1622 1623} 1624 1625Page::PageClients::PageClients() 1626 : alternativeTextClient(nullptr) 1627 , chromeClient(nullptr) 1628#if ENABLE(CONTEXT_MENUS) 1629 , contextMenuClient(nullptr) 1630#endif 1631 , editorClient(nullptr) 1632 , dragClient(nullptr) 1633 , inspectorClient(nullptr) 1634 , plugInClient(nullptr) 1635 , progressTrackerClient(nullptr) 1636 , validationMessageClient(nullptr) 1637 , loaderClientForMainFrame(nullptr) 1638{ 1639} 1640 1641Page::PageClients::~PageClients() 1642{ 1643} 1644 1645} // namespace WebCore 1646