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