Home | History | Annotate | Download | only in page
      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 "core/page/Page.h"
     22 
     23 #include "core/dom/ClientRectList.h"
     24 #include "core/dom/DocumentMarkerController.h"
     25 #include "core/dom/StyleEngine.h"
     26 #include "core/dom/VisitedLinkState.h"
     27 #include "core/editing/Caret.h"
     28 #include "core/editing/UndoStack.h"
     29 #include "core/events/Event.h"
     30 #include "core/events/ThreadLocalEventNames.h"
     31 #include "core/fetch/ResourceFetcher.h"
     32 #include "core/frame/DOMTimer.h"
     33 #include "core/frame/DOMWindow.h"
     34 #include "core/frame/Frame.h"
     35 #include "core/frame/FrameView.h"
     36 #include "core/history/HistoryItem.h"
     37 #include "core/inspector/InspectorController.h"
     38 #include "core/inspector/InspectorInstrumentation.h"
     39 #include "core/loader/FrameLoader.h"
     40 #include "core/loader/ProgressTracker.h"
     41 #include "core/page/AutoscrollController.h"
     42 #include "core/page/Chrome.h"
     43 #include "core/page/ChromeClient.h"
     44 #include "core/page/ContextMenuController.h"
     45 #include "core/page/DragController.h"
     46 #include "core/page/FocusController.h"
     47 #include "core/page/FrameTree.h"
     48 #include "core/page/PageConsole.h"
     49 #include "core/page/PageGroup.h"
     50 #include "core/page/PageLifecycleNotifier.h"
     51 #include "core/page/PointerLockController.h"
     52 #include "core/frame/Settings.h"
     53 #include "core/page/ValidationMessageClient.h"
     54 #include "core/page/scrolling/ScrollingCoordinator.h"
     55 #include "core/rendering/RenderView.h"
     56 #include "core/rendering/TextAutosizer.h"
     57 #include "core/storage/StorageNamespace.h"
     58 #include "core/workers/SharedWorkerRepositoryClient.h"
     59 #include "platform/plugins/PluginData.h"
     60 #include "wtf/HashMap.h"
     61 #include "wtf/RefCountedLeakCounter.h"
     62 #include "wtf/StdLibExtras.h"
     63 #include "wtf/text/Base64.h"
     64 
     65 namespace WebCore {
     66 
     67 static HashSet<Page*>* allPages;
     68 
     69 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
     70 
     71 void Page::networkStateChanged(bool online)
     72 {
     73     if (!allPages)
     74         return;
     75 
     76     Vector<RefPtr<Frame> > frames;
     77 
     78     // Get all the frames of all the pages in all the page groups
     79     HashSet<Page*>::iterator end = allPages->end();
     80     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
     81         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
     82             frames.append(frame);
     83         InspectorInstrumentation::networkStateChanged(*it, online);
     84     }
     85 
     86     AtomicString eventName = online ? EventTypeNames::online : EventTypeNames::offline;
     87     for (unsigned i = 0; i < frames.size(); i++)
     88         frames[i]->domWindow()->dispatchEvent(Event::create(eventName));
     89 }
     90 
     91 float deviceScaleFactor(Frame* frame)
     92 {
     93     if (!frame)
     94         return 1;
     95     Page* page = frame->page();
     96     if (!page)
     97         return 1;
     98     return page->deviceScaleFactor();
     99 }
    100 
    101 Page::Page(PageClients& pageClients)
    102     : SettingsDelegate(Settings::create())
    103     , m_autoscrollController(AutoscrollController::create(*this))
    104     , m_chrome(Chrome::create(this, pageClients.chromeClient))
    105     , m_dragCaretController(DragCaretController::create())
    106     , m_dragController(DragController::create(this, pageClients.dragClient))
    107     , m_focusController(FocusController::create(this))
    108     , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
    109     , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
    110     , m_pointerLockController(PointerLockController::create(this))
    111     , m_historyController(adoptPtr(new HistoryController(this)))
    112     , m_progress(ProgressTracker::create())
    113     , m_undoStack(UndoStack::create())
    114     , m_backForwardClient(pageClients.backForwardClient)
    115     , m_editorClient(pageClients.editorClient)
    116     , m_validationMessageClient(0)
    117     , m_sharedWorkerRepositoryClient(0)
    118     , m_spellCheckerClient(pageClients.spellCheckerClient)
    119     , m_subframeCount(0)
    120     , m_openedByDOM(false)
    121     , m_tabKeyCyclesThroughElements(true)
    122     , m_defersLoading(false)
    123     , m_pageScaleFactor(1)
    124     , m_deviceScaleFactor(1)
    125     , m_group(0)
    126     , m_timerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval())
    127     , m_visibilityState(PageVisibilityStateVisible)
    128     , m_isCursorVisible(true)
    129 #ifndef NDEBUG
    130     , m_isPainting(false)
    131 #endif
    132     , m_console(PageConsole::create(this))
    133 {
    134     ASSERT(m_editorClient);
    135 
    136     if (!allPages)
    137         allPages = new HashSet<Page*>;
    138 
    139     ASSERT(!allPages->contains(this));
    140     allPages->add(this);
    141 
    142 #ifndef NDEBUG
    143     pageCounter.increment();
    144 #endif
    145 }
    146 
    147 Page::~Page()
    148 {
    149     m_mainFrame->setView(0);
    150     clearPageGroup();
    151     allPages->remove(this);
    152 
    153     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
    154         frame->willDetachPage();
    155         frame->detachFromPage();
    156     }
    157 
    158     m_inspectorController->inspectedPageDestroyed();
    159 
    160     if (m_scrollingCoordinator)
    161         m_scrollingCoordinator->pageDestroyed();
    162 
    163 #ifndef NDEBUG
    164     pageCounter.decrement();
    165 #endif
    166 }
    167 
    168 ViewportDescription Page::viewportDescription() const
    169 {
    170     return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportDescription() : ViewportDescription();
    171 }
    172 
    173 ScrollingCoordinator* Page::scrollingCoordinator()
    174 {
    175     if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
    176         m_scrollingCoordinator = ScrollingCoordinator::create(this);
    177 
    178     return m_scrollingCoordinator.get();
    179 }
    180 
    181 String Page::mainThreadScrollingReasonsAsText()
    182 {
    183     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
    184         return scrollingCoordinator->mainThreadScrollingReasonsAsText();
    185 
    186     return String();
    187 }
    188 
    189 PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame)
    190 {
    191     if (Document* document = m_mainFrame->document())
    192         document->updateLayout();
    193 
    194     Vector<IntRect> rects;
    195     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
    196         rects = scrollingCoordinator->computeShouldHandleScrollGestureOnMainThreadRegion(frame, IntPoint()).rects();
    197 
    198     Vector<FloatQuad> quads(rects.size());
    199     for (size_t i = 0; i < rects.size(); ++i)
    200         quads[i] = FloatRect(rects[i]);
    201     return ClientRectList::create(quads);
    202 }
    203 
    204 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
    205 {
    206     ASSERT(!m_mainFrame); // Should only be called during initialization
    207     m_mainFrame = mainFrame;
    208 }
    209 
    210 void Page::documentDetached(Document* document)
    211 {
    212     m_pointerLockController->documentDetached(document);
    213     m_contextMenuController->documentDetached(document);
    214     if (m_validationMessageClient)
    215         m_validationMessageClient->documentDetached(*document);
    216     if (m_sharedWorkerRepositoryClient)
    217         m_sharedWorkerRepositoryClient->documentDetached(document);
    218 }
    219 
    220 bool Page::openedByDOM() const
    221 {
    222     return m_openedByDOM;
    223 }
    224 
    225 void Page::setOpenedByDOM()
    226 {
    227     m_openedByDOM = true;
    228 }
    229 
    230 void Page::clearPageGroup()
    231 {
    232     if (!m_group)
    233         return;
    234     m_group->removePage(this);
    235     m_group = 0;
    236 }
    237 
    238 void Page::setGroupType(PageGroupType type)
    239 {
    240     clearPageGroup();
    241 
    242     switch (type) {
    243     case PrivatePageGroup:
    244         m_group = PageGroup::create();
    245         break;
    246     case SharedPageGroup:
    247         m_group = PageGroup::sharedGroup();
    248         break;
    249     }
    250 
    251     m_group->addPage(this);
    252 }
    253 
    254 void Page::scheduleForcedStyleRecalcForAllPages()
    255 {
    256     if (!allPages)
    257         return;
    258     HashSet<Page*>::iterator end = allPages->end();
    259     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
    260         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
    261             frame->document()->setNeedsStyleRecalc();
    262 }
    263 
    264 void Page::setNeedsRecalcStyleInAllFrames()
    265 {
    266     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
    267         frame->document()->styleResolverChanged(RecalcStyleDeferred);
    268 }
    269 
    270 void Page::refreshPlugins(bool reload)
    271 {
    272     if (!allPages)
    273         return;
    274 
    275     PluginData::refresh();
    276 
    277     Vector<RefPtr<Frame> > framesNeedingReload;
    278 
    279     HashSet<Page*>::iterator end = allPages->end();
    280     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
    281         Page* page = *it;
    282 
    283         // Clear out the page's plug-in data.
    284         if (page->m_pluginData)
    285             page->m_pluginData = 0;
    286 
    287         if (!reload)
    288             continue;
    289 
    290         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
    291             if (frame->document()->containsPlugins())
    292                 framesNeedingReload.append(frame);
    293         }
    294     }
    295 
    296     for (size_t i = 0; i < framesNeedingReload.size(); ++i)
    297         framesNeedingReload[i]->loader().reload();
    298 }
    299 
    300 PluginData* Page::pluginData() const
    301 {
    302     if (!mainFrame()->loader().allowPlugins(NotAboutToInstantiatePlugin))
    303         return 0;
    304     if (!m_pluginData)
    305         m_pluginData = PluginData::create(this);
    306     return m_pluginData.get();
    307 }
    308 
    309 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
    310 {
    311     return forward
    312         ? curr->tree().traverseNextWithWrap(wrapFlag)
    313         : curr->tree().traversePreviousWithWrap(wrapFlag);
    314 }
    315 
    316 void Page::unmarkAllTextMatches()
    317 {
    318     if (!mainFrame())
    319         return;
    320 
    321     Frame* frame = mainFrame();
    322     do {
    323         frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
    324         frame = incrementFrame(frame, true, false);
    325     } while (frame);
    326 }
    327 
    328 void Page::setDefersLoading(bool defers)
    329 {
    330     if (defers == m_defersLoading)
    331         return;
    332 
    333     m_defersLoading = defers;
    334     m_historyController->setDefersLoading(defers);
    335     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
    336         frame->loader().setDefersLoading(defers);
    337 }
    338 
    339 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
    340 {
    341     FrameView* view = mainFrame()->view();
    342 
    343     if (scale != m_pageScaleFactor) {
    344         m_pageScaleFactor = scale;
    345 
    346         if (view)
    347             view->setVisibleContentScaleFactor(scale);
    348 
    349         mainFrame()->deviceOrPageScaleFactorChanged();
    350         m_chrome->client().deviceOrPageScaleFactorChanged();
    351 
    352         if (view)
    353             view->setViewportConstrainedObjectsNeedLayout();
    354     }
    355 
    356     if (view && view->scrollPosition() != origin)
    357         view->notifyScrollPositionChanged(origin);
    358 }
    359 
    360 void Page::setDeviceScaleFactor(float scaleFactor)
    361 {
    362     if (m_deviceScaleFactor == scaleFactor)
    363         return;
    364 
    365     m_deviceScaleFactor = scaleFactor;
    366     setNeedsRecalcStyleInAllFrames();
    367 
    368     if (mainFrame()) {
    369         mainFrame()->deviceOrPageScaleFactorChanged();
    370         m_chrome->client().deviceOrPageScaleFactorChanged();
    371     }
    372 }
    373 
    374 void Page::setPagination(const Pagination& pagination)
    375 {
    376     if (m_pagination == pagination)
    377         return;
    378 
    379     m_pagination = pagination;
    380 
    381     setNeedsRecalcStyleInAllFrames();
    382 }
    383 
    384 void Page::allVisitedStateChanged(PageGroup* group)
    385 {
    386     ASSERT(group);
    387     if (!allPages)
    388         return;
    389 
    390     HashSet<Page*>::iterator pagesEnd = allPages->end();
    391     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
    392         Page* page = *it;
    393         if (page->m_group != group)
    394             continue;
    395         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
    396             frame->document()->visitedLinkState().invalidateStyleForAllLinks();
    397     }
    398 }
    399 
    400 void Page::visitedStateChanged(PageGroup* group, LinkHash linkHash)
    401 {
    402     ASSERT(group);
    403     if (!allPages)
    404         return;
    405 
    406     HashSet<Page*>::iterator pagesEnd = allPages->end();
    407     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
    408         Page* page = *it;
    409         if (page->m_group != group)
    410             continue;
    411         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
    412             frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
    413     }
    414 }
    415 
    416 StorageNamespace* Page::sessionStorage(bool optionalCreate)
    417 {
    418     if (!m_sessionStorage && optionalCreate)
    419         m_sessionStorage = StorageNamespace::sessionStorageNamespace(this);
    420     return m_sessionStorage.get();
    421 }
    422 
    423 void Page::setTimerAlignmentInterval(double interval)
    424 {
    425     if (interval == m_timerAlignmentInterval)
    426         return;
    427 
    428     m_timerAlignmentInterval = interval;
    429     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
    430         if (frame->document())
    431             frame->document()->didChangeTimerAlignmentInterval();
    432     }
    433 }
    434 
    435 double Page::timerAlignmentInterval() const
    436 {
    437     return m_timerAlignmentInterval;
    438 }
    439 
    440 #if !ASSERT_DISABLED
    441 void Page::checkSubframeCountConsistency() const
    442 {
    443     ASSERT(m_subframeCount >= 0);
    444 
    445     int subframeCount = 0;
    446     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
    447         ++subframeCount;
    448 
    449     ASSERT(m_subframeCount + 1 == subframeCount);
    450 }
    451 #endif
    452 
    453 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
    454 {
    455     if (m_visibilityState == visibilityState)
    456         return;
    457     m_visibilityState = visibilityState;
    458 
    459     if (visibilityState == WebCore::PageVisibilityStateHidden)
    460         setTimerAlignmentInterval(DOMTimer::hiddenPageAlignmentInterval());
    461     else
    462         setTimerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval());
    463 
    464     if (!isInitialState)
    465         lifecycleNotifier().notifyPageVisibilityChanged();
    466 
    467     if (!isInitialState && m_mainFrame)
    468         m_mainFrame->dispatchVisibilityStateChangeEvent();
    469 }
    470 
    471 PageVisibilityState Page::visibilityState() const
    472 {
    473     return m_visibilityState;
    474 }
    475 
    476 void Page::addMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
    477 {
    478     m_multisamplingChangedObservers.add(observer);
    479 }
    480 
    481 void Page::removeMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
    482 {
    483     m_multisamplingChangedObservers.remove(observer);
    484 }
    485 
    486 void Page::settingsChanged(SettingsDelegate::ChangeType changeType)
    487 {
    488     switch (changeType) {
    489     case SettingsDelegate::StyleChange:
    490         setNeedsRecalcStyleInAllFrames();
    491         break;
    492     case SettingsDelegate::ViewportDescriptionChange:
    493         if (mainFrame())
    494             mainFrame()->document()->updateViewportDescription();
    495         break;
    496     case SettingsDelegate::MediaTypeChange:
    497         m_mainFrame->view()->setMediaType(settings().mediaTypeOverride());
    498         setNeedsRecalcStyleInAllFrames();
    499         break;
    500     case SettingsDelegate::DNSPrefetchingChange:
    501         for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
    502             frame->document()->initDNSPrefetch();
    503         break;
    504     case SettingsDelegate::MultisamplingChange: {
    505         HashSet<MultisamplingChangedObserver*>::iterator stop = m_multisamplingChangedObservers.end();
    506         for (HashSet<MultisamplingChangedObserver*>::iterator it = m_multisamplingChangedObservers.begin(); it != stop; ++it)
    507             (*it)->multisamplingChanged(m_settings->openGLMultisamplingEnabled());
    508         break;
    509     }
    510     case SettingsDelegate::ImageLoadingChange:
    511         for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
    512             frame->document()->fetcher()->setImagesEnabled(settings().imagesEnabled());
    513             frame->document()->fetcher()->setAutoLoadImages(settings().loadsImagesAutomatically());
    514         }
    515         break;
    516     case SettingsDelegate::TextAutosizingChange:
    517         // FIXME: I wonder if this needs to traverse frames like in WebViewImpl::resize, or whether there is only one document per Settings instance?
    518         for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
    519             TextAutosizer* textAutosizer = frame->document()->textAutosizer();
    520             if (textAutosizer)
    521                 textAutosizer->recalculateMultipliers();
    522         }
    523         setNeedsRecalcStyleInAllFrames();
    524         break;
    525     }
    526 }
    527 
    528 void Page::didCommitLoad(Frame* frame)
    529 {
    530     lifecycleNotifier().notifyDidCommitLoad(frame);
    531     if (m_mainFrame == frame)
    532         useCounter().didCommitLoad();
    533 }
    534 
    535 PageLifecycleNotifier& Page::lifecycleNotifier()
    536 {
    537     return static_cast<PageLifecycleNotifier&>(LifecycleContext<Page>::lifecycleNotifier());
    538 }
    539 
    540 PassOwnPtr<LifecycleNotifier<Page> > Page::createLifecycleNotifier()
    541 {
    542     return PageLifecycleNotifier::create(this);
    543 }
    544 
    545 Page::PageClients::PageClients()
    546     : chromeClient(0)
    547     , contextMenuClient(0)
    548     , editorClient(0)
    549     , dragClient(0)
    550     , inspectorClient(0)
    551     , backForwardClient(0)
    552     , spellCheckerClient(0)
    553 {
    554 }
    555 
    556 Page::PageClients::~PageClients()
    557 {
    558 }
    559 
    560 } // namespace WebCore
    561