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/fetch/ResourceFetcher.h"
31#include "core/frame/DOMTimer.h"
32#include "core/frame/FrameConsole.h"
33#include "core/frame/FrameHost.h"
34#include "core/frame/FrameView.h"
35#include "core/frame/LocalDOMWindow.h"
36#include "core/frame/LocalFrame.h"
37#include "core/frame/RemoteFrame.h"
38#include "core/frame/RemoteFrameView.h"
39#include "core/frame/Settings.h"
40#include "core/inspector/InspectorController.h"
41#include "core/inspector/InspectorInstrumentation.h"
42#include "core/loader/FrameLoader.h"
43#include "core/loader/HistoryItem.h"
44#include "core/page/AutoscrollController.h"
45#include "core/page/Chrome.h"
46#include "core/page/ChromeClient.h"
47#include "core/page/ContextMenuController.h"
48#include "core/page/DragController.h"
49#include "core/page/FocusController.h"
50#include "core/page/FrameTree.h"
51#include "core/page/PageLifecycleNotifier.h"
52#include "core/page/PointerLockController.h"
53#include "core/page/StorageClient.h"
54#include "core/page/ValidationMessageClient.h"
55#include "core/page/scrolling/ScrollingCoordinator.h"
56#include "core/rendering/RenderView.h"
57#include "core/rendering/TextAutosizer.h"
58#include "core/storage/StorageNamespace.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
65namespace blink {
66
67DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
68
69// static
70HashSet<Page*>& Page::allPages()
71{
72    DEFINE_STATIC_LOCAL(HashSet<Page*>, allPages, ());
73    return allPages;
74}
75
76// static
77HashSet<Page*>& Page::ordinaryPages()
78{
79    DEFINE_STATIC_LOCAL(HashSet<Page*>, ordinaryPages, ());
80    return ordinaryPages;
81}
82
83
84void Page::networkStateChanged(bool online)
85{
86    WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > frames;
87
88    // Get all the frames of all the pages in all the page groups
89    HashSet<Page*>::iterator end = allPages().end();
90    for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it) {
91        for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
92            // FIXME: There is currently no way to dispatch events to out-of-process frames.
93            if (frame->isLocalFrame())
94                frames.append(toLocalFrame(frame));
95        }
96        InspectorInstrumentation::networkStateChanged(*it, online);
97    }
98
99    AtomicString eventName = online ? EventTypeNames::online : EventTypeNames::offline;
100    for (unsigned i = 0; i < frames.size(); i++)
101        frames[i]->domWindow()->dispatchEvent(Event::create(eventName));
102}
103
104float deviceScaleFactor(LocalFrame* frame)
105{
106    if (!frame)
107        return 1;
108    Page* page = frame->page();
109    if (!page)
110        return 1;
111    return page->deviceScaleFactor();
112}
113
114Page::Page(PageClients& pageClients)
115    : SettingsDelegate(Settings::create())
116    , m_animator(PageAnimator::create(*this))
117    , m_autoscrollController(AutoscrollController::create(*this))
118    , m_chrome(Chrome::create(this, pageClients.chromeClient))
119    , m_dragCaretController(DragCaretController::create())
120    , m_dragController(DragController::create(this, pageClients.dragClient))
121    , m_focusController(FocusController::create(this))
122    , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
123    , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
124    , m_pointerLockController(PointerLockController::create(this))
125    , m_undoStack(UndoStack::create())
126    , m_mainFrame(nullptr)
127    , m_backForwardClient(pageClients.backForwardClient)
128    , m_editorClient(pageClients.editorClient)
129    , m_spellCheckerClient(pageClients.spellCheckerClient)
130    , m_storageClient(pageClients.storageClient)
131    , m_subframeCount(0)
132    , m_openedByDOM(false)
133    , m_tabKeyCyclesThroughElements(true)
134    , m_defersLoading(false)
135    , m_deviceScaleFactor(1)
136    , m_timerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval())
137    , m_visibilityState(PageVisibilityStateVisible)
138    , m_isCursorVisible(true)
139#if ENABLE(ASSERT)
140    , m_isPainting(false)
141#endif
142    , m_frameHost(FrameHost::create(*this))
143{
144    ASSERT(m_editorClient);
145
146    ASSERT(!allPages().contains(this));
147    allPages().add(this);
148
149#ifndef NDEBUG
150    pageCounter.increment();
151#endif
152}
153
154Page::~Page()
155{
156    // willBeDestroyed() must be called before Page destruction.
157    ASSERT(!m_mainFrame);
158}
159
160void Page::makeOrdinary()
161{
162    ASSERT(!ordinaryPages().contains(this));
163    ordinaryPages().add(this);
164}
165
166ViewportDescription Page::viewportDescription() const
167{
168    return mainFrame() && mainFrame()->isLocalFrame() && deprecatedLocalMainFrame()->document() ? deprecatedLocalMainFrame()->document()->viewportDescription() : ViewportDescription();
169}
170
171ScrollingCoordinator* Page::scrollingCoordinator()
172{
173    if (!m_scrollingCoordinator && m_settings->acceleratedCompositingEnabled())
174        m_scrollingCoordinator = ScrollingCoordinator::create(this);
175
176    return m_scrollingCoordinator.get();
177}
178
179String Page::mainThreadScrollingReasonsAsText()
180{
181    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
182        return scrollingCoordinator->mainThreadScrollingReasonsAsText();
183
184    return String();
185}
186
187PassRefPtrWillBeRawPtr<ClientRectList> Page::nonFastScrollableRects(const LocalFrame* frame)
188{
189    if (m_mainFrame->isLocalFrame() && deprecatedLocalMainFrame()->document())
190        deprecatedLocalMainFrame()->document()->updateLayout();
191
192    Vector<IntRect> rects;
193    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
194        rects = scrollingCoordinator->computeShouldHandleScrollGestureOnMainThreadRegion(frame, IntPoint()).rects();
195
196    Vector<FloatQuad> quads(rects.size());
197    for (size_t i = 0; i < rects.size(); ++i)
198        quads[i] = FloatRect(rects[i]);
199    return ClientRectList::create(quads);
200}
201
202void Page::setMainFrame(Frame* mainFrame)
203{
204    // Should only be called during initialization or swaps between local and
205    // remote frames.
206    // FIXME: Unfortunately we can't assert on this at the moment, because this
207    // is called in the base constructor for both LocalFrame and RemoteFrame,
208    // when the vtables for the derived classes have not yet been setup.
209    m_mainFrame = mainFrame;
210}
211
212void Page::documentDetached(Document* document)
213{
214    m_multisamplingChangedObservers.clear();
215    m_pointerLockController->documentDetached(document);
216    m_contextMenuController->documentDetached(document);
217    if (m_validationMessageClient)
218        m_validationMessageClient->documentDetached(*document);
219}
220
221bool Page::openedByDOM() const
222{
223    return m_openedByDOM;
224}
225
226void Page::setOpenedByDOM()
227{
228    m_openedByDOM = true;
229}
230
231void Page::scheduleForcedStyleRecalcForAllPages()
232{
233    HashSet<Page*>::iterator end = allPages().end();
234    for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it)
235        for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
236            if (frame->isLocalFrame())
237                toLocalFrame(frame)->document()->setNeedsStyleRecalc(SubtreeStyleChange);
238        }
239}
240
241void Page::setNeedsRecalcStyleInAllFrames()
242{
243    for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
244        if (frame->isLocalFrame())
245            toLocalFrame(frame)->document()->styleResolverChanged();
246    }
247}
248
249void Page::setNeedsLayoutInAllFrames()
250{
251    for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
252        if (!frame->isLocalFrame())
253            continue;
254        if (FrameView* view = toLocalFrame(frame)->view()) {
255            view->setNeedsLayout();
256            view->scheduleRelayout();
257        }
258    }
259}
260
261void Page::refreshPlugins(bool reload)
262{
263    if (allPages().isEmpty())
264        return;
265
266    PluginData::refresh();
267
268    WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > framesNeedingReload;
269
270    HashSet<Page*>::iterator end = allPages().end();
271    for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it) {
272        Page* page = *it;
273
274        // Clear out the page's plug-in data.
275        if (page->m_pluginData)
276            page->m_pluginData = nullptr;
277
278        if (!reload)
279            continue;
280
281        for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
282            if (frame->isLocalFrame() && toLocalFrame(frame)->document()->containsPlugins())
283                framesNeedingReload.append(toLocalFrame(frame));
284        }
285    }
286
287    for (size_t i = 0; i < framesNeedingReload.size(); ++i)
288        framesNeedingReload[i]->loader().reload();
289}
290
291PluginData* Page::pluginData() const
292{
293    if (!deprecatedLocalMainFrame()->loader().allowPlugins(NotAboutToInstantiatePlugin))
294        return 0;
295    if (!m_pluginData)
296        m_pluginData = PluginData::create(this);
297    return m_pluginData.get();
298}
299
300static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
301{
302    return forward
303        ? curr->tree().traverseNextWithWrap(wrapFlag)
304        : curr->tree().traversePreviousWithWrap(wrapFlag);
305}
306
307void Page::unmarkAllTextMatches()
308{
309    if (!mainFrame())
310        return;
311
312    Frame* frame = mainFrame();
313    do {
314        if (frame->isLocalFrame())
315            toLocalFrame(frame)->document()->markers().removeMarkers(DocumentMarker::TextMatch);
316        frame = incrementFrame(frame, true, false);
317    } while (frame);
318}
319
320void Page::setValidationMessageClient(PassOwnPtrWillBeRawPtr<ValidationMessageClient> client)
321{
322    m_validationMessageClient = client;
323}
324
325void Page::setDefersLoading(bool defers)
326{
327    if (defers == m_defersLoading)
328        return;
329
330    m_defersLoading = defers;
331    for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
332        if (frame->isLocalFrame())
333            toLocalFrame(frame)->loader().setDefersLoading(defers);
334    }
335}
336
337void Page::setPageScaleFactor(float scale, const IntPoint& origin)
338{
339    if (!mainFrame()->isLocalFrame())
340        return;
341
342    FrameView* view = deprecatedLocalMainFrame()->view();
343    PinchViewport& viewport = frameHost().pinchViewport();
344
345    if (scale != viewport.scale()) {
346        viewport.setScale(scale);
347
348        if (view && !settings().pinchVirtualViewportEnabled())
349            view->setVisibleContentScaleFactor(scale);
350
351        deprecatedLocalMainFrame()->deviceOrPageScaleFactorChanged();
352        m_chrome->client().deviceOrPageScaleFactorChanged();
353
354        // FIXME: In virtual-viewport pinch mode, scale doesn't change the fixed-pos viewport;
355        // remove once it's the only pinch mode in town.
356        if (view)
357            view->viewportConstrainedVisibleContentSizeChanged(true, true);
358
359        deprecatedLocalMainFrame()->loader().saveScrollState();
360    }
361
362    if (view && view->scrollPosition() != origin)
363        view->notifyScrollPositionChanged(origin);
364}
365
366float Page::pageScaleFactor() const
367{
368    return frameHost().pinchViewport().scale();
369}
370
371void Page::setDeviceScaleFactor(float scaleFactor)
372{
373    if (m_deviceScaleFactor == scaleFactor)
374        return;
375
376    m_deviceScaleFactor = scaleFactor;
377    setNeedsRecalcStyleInAllFrames();
378
379    if (mainFrame() && mainFrame()->isLocalFrame()) {
380        deprecatedLocalMainFrame()->deviceOrPageScaleFactorChanged();
381        m_chrome->client().deviceOrPageScaleFactorChanged();
382    }
383}
384
385void Page::setDeviceColorProfile(const Vector<char>& profile)
386{
387    // FIXME: implement.
388}
389
390void Page::resetDeviceColorProfile()
391{
392    // FIXME: implement.
393}
394
395void Page::allVisitedStateChanged()
396{
397    HashSet<Page*>::iterator pagesEnd = ordinaryPages().end();
398    for (HashSet<Page*>::iterator it = ordinaryPages().begin(); it != pagesEnd; ++it) {
399        Page* page = *it;
400        for (Frame* frame = page->m_mainFrame; frame; frame = frame->tree().traverseNext()) {
401            if (frame->isLocalFrame())
402                toLocalFrame(frame)->document()->visitedLinkState().invalidateStyleForAllLinks();
403        }
404    }
405}
406
407void Page::visitedStateChanged(LinkHash linkHash)
408{
409    HashSet<Page*>::iterator pagesEnd = ordinaryPages().end();
410    for (HashSet<Page*>::iterator it = ordinaryPages().begin(); it != pagesEnd; ++it) {
411        Page* page = *it;
412        for (Frame* frame = page->m_mainFrame; frame; frame = frame->tree().traverseNext()) {
413            if (frame->isLocalFrame())
414                toLocalFrame(frame)->document()->visitedLinkState().invalidateStyleForLink(linkHash);
415        }
416    }
417}
418
419StorageNamespace* Page::sessionStorage(bool optionalCreate)
420{
421    if (!m_sessionStorage && optionalCreate)
422        m_sessionStorage = m_storageClient->createSessionStorageNamespace();
423    return m_sessionStorage.get();
424}
425
426void Page::setTimerAlignmentInterval(double interval)
427{
428    if (interval == m_timerAlignmentInterval)
429        return;
430
431    m_timerAlignmentInterval = interval;
432    for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
433        if (frame->isLocalFrame() && toLocalFrame(frame)->document())
434            toLocalFrame(frame)->document()->didChangeTimerAlignmentInterval();
435    }
436}
437
438double Page::timerAlignmentInterval() const
439{
440    return m_timerAlignmentInterval;
441}
442
443#if ENABLE(ASSERT)
444void Page::checkSubframeCountConsistency() const
445{
446    ASSERT(m_subframeCount >= 0);
447
448    int subframeCount = 0;
449    for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
450        ++subframeCount;
451
452    ASSERT(m_subframeCount + 1 == subframeCount);
453}
454#endif
455
456void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
457{
458    if (m_visibilityState == visibilityState)
459        return;
460    m_visibilityState = visibilityState;
461
462    if (visibilityState == blink::PageVisibilityStateVisible)
463        setTimerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval());
464    else
465        setTimerAlignmentInterval(DOMTimer::hiddenPageAlignmentInterval());
466
467    if (!isInitialState)
468        lifecycleNotifier().notifyPageVisibilityChanged();
469
470    if (!isInitialState && m_mainFrame && m_mainFrame->isLocalFrame())
471        deprecatedLocalMainFrame()->didChangeVisibilityState();
472}
473
474PageVisibilityState Page::visibilityState() const
475{
476    return m_visibilityState;
477}
478
479bool Page::isCursorVisible() const
480{
481    return m_isCursorVisible && settings().deviceSupportsMouse();
482}
483
484void Page::addMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
485{
486    m_multisamplingChangedObservers.add(observer);
487}
488
489void Page::removeMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
490{
491    m_multisamplingChangedObservers.remove(observer);
492}
493
494void Page::settingsChanged(SettingsDelegate::ChangeType changeType)
495{
496    switch (changeType) {
497    case SettingsDelegate::StyleChange:
498        setNeedsRecalcStyleInAllFrames();
499        break;
500    case SettingsDelegate::ViewportDescriptionChange:
501        if (mainFrame() && mainFrame()->isLocalFrame())
502            deprecatedLocalMainFrame()->document()->updateViewportDescription();
503        break;
504    case SettingsDelegate::MediaTypeChange:
505        if (m_mainFrame->isLocalFrame()) {
506            deprecatedLocalMainFrame()->view()->setMediaType(AtomicString(settings().mediaTypeOverride()));
507            setNeedsRecalcStyleInAllFrames();
508        }
509        break;
510    case SettingsDelegate::DNSPrefetchingChange:
511        for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
512            if (frame->isLocalFrame())
513                toLocalFrame(frame)->document()->initDNSPrefetch();
514        }
515        break;
516    case SettingsDelegate::MultisamplingChange: {
517        WillBeHeapHashSet<RawPtrWillBeWeakMember<MultisamplingChangedObserver> >::iterator stop = m_multisamplingChangedObservers.end();
518        for (WillBeHeapHashSet<RawPtrWillBeWeakMember<MultisamplingChangedObserver> >::iterator it = m_multisamplingChangedObservers.begin(); it != stop; ++it)
519            (*it)->multisamplingChanged(m_settings->openGLMultisamplingEnabled());
520        break;
521    }
522    case SettingsDelegate::ImageLoadingChange:
523        for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
524            if (frame->isLocalFrame()) {
525                toLocalFrame(frame)->document()->fetcher()->setImagesEnabled(settings().imagesEnabled());
526                toLocalFrame(frame)->document()->fetcher()->setAutoLoadImages(settings().loadsImagesAutomatically());
527            }
528        }
529        break;
530    case SettingsDelegate::TextAutosizingChange:
531        if (!mainFrame() || !mainFrame()->isLocalFrame())
532            break;
533        if (TextAutosizer* textAutosizer = deprecatedLocalMainFrame()->document()->textAutosizer())
534            textAutosizer->updatePageInfoInAllFrames();
535        break;
536    case SettingsDelegate::ScriptEnableChange:
537        m_inspectorController->scriptsEnabled(settings().scriptEnabled());
538        break;
539    case SettingsDelegate::FontFamilyChange:
540        for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
541            if (frame->isLocalFrame())
542                toLocalFrame(frame)->document()->styleEngine()->updateGenericFontFamilySettings();
543        }
544        setNeedsRecalcStyleInAllFrames();
545        break;
546    case SettingsDelegate::AcceleratedCompositingChange:
547        updateAcceleratedCompositingSettings();
548        break;
549    case SettingsDelegate::MediaQueryChange:
550        for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
551            if (frame->isLocalFrame())
552                toLocalFrame(frame)->document()->mediaQueryAffectingValueChanged();
553        }
554        setNeedsRecalcStyleInAllFrames();
555        break;
556    }
557}
558
559void Page::updateAcceleratedCompositingSettings()
560{
561    for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
562        if (!frame->isLocalFrame())
563            continue;
564        if (FrameView* view = toLocalFrame(frame)->view())
565            view->updateAcceleratedCompositingSettings();
566    }
567}
568
569void Page::didCommitLoad(LocalFrame* frame)
570{
571    lifecycleNotifier().notifyDidCommitLoad(frame);
572    if (m_mainFrame == frame) {
573        frame->console().clearMessages();
574        useCounter().didCommitLoad();
575        m_inspectorController->didCommitLoadForMainFrame();
576        UserGestureIndicator::clearProcessedUserGestureSinceLoad();
577    }
578}
579
580void Page::acceptLanguagesChanged()
581{
582    WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > frames;
583
584    // Even though we don't fire an event from here, the LocalDOMWindow's will fire
585    // an event so we keep the frames alive until we are done.
586    for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
587        if (frame->isLocalFrame())
588            frames.append(toLocalFrame(frame));
589    }
590
591    for (unsigned i = 0; i < frames.size(); ++i)
592        frames[i]->domWindow()->acceptLanguagesChanged();
593}
594
595PageLifecycleNotifier& Page::lifecycleNotifier()
596{
597    return static_cast<PageLifecycleNotifier&>(LifecycleContext<Page>::lifecycleNotifier());
598}
599
600PassOwnPtr<LifecycleNotifier<Page> > Page::createLifecycleNotifier()
601{
602    return PageLifecycleNotifier::create(this);
603}
604
605void Page::trace(Visitor* visitor)
606{
607#if ENABLE(OILPAN)
608    visitor->trace(m_animator);
609    visitor->trace(m_dragCaretController);
610    visitor->trace(m_dragController);
611    visitor->trace(m_focusController);
612    visitor->trace(m_contextMenuController);
613    visitor->trace(m_inspectorController);
614    visitor->trace(m_pointerLockController);
615    visitor->trace(m_undoStack);
616    visitor->trace(m_mainFrame);
617    visitor->trace(m_validationMessageClient);
618    visitor->trace(m_multisamplingChangedObservers);
619    visitor->trace(m_frameHost);
620    HeapSupplementable<Page>::trace(visitor);
621#endif
622    LifecycleContext<Page>::trace(visitor);
623}
624
625void Page::willBeDestroyed()
626{
627    // Destroy inspector first, since it uses frame and view during destruction.
628    m_inspectorController->willBeDestroyed();
629
630    RefPtrWillBeRawPtr<Frame> mainFrame = m_mainFrame;
631
632    mainFrame->detach();
633
634    if (mainFrame->isLocalFrame()) {
635        toLocalFrame(mainFrame.get())->setView(nullptr);
636    } else {
637        ASSERT(m_mainFrame->isRemoteFrame());
638        toRemoteFrame(mainFrame.get())->setView(nullptr);
639    }
640
641    allPages().remove(this);
642    if (ordinaryPages().contains(this))
643        ordinaryPages().remove(this);
644
645    if (m_scrollingCoordinator)
646        m_scrollingCoordinator->willBeDestroyed();
647
648#ifndef NDEBUG
649    pageCounter.decrement();
650#endif
651
652    m_chrome->willBeDestroyed();
653    if (m_validationMessageClient)
654        m_validationMessageClient->willBeDestroyed();
655    m_mainFrame = nullptr;
656}
657
658Page::PageClients::PageClients()
659    : chromeClient(0)
660    , contextMenuClient(0)
661    , editorClient(0)
662    , dragClient(0)
663    , inspectorClient(0)
664    , backForwardClient(0)
665    , spellCheckerClient(0)
666    , storageClient(0)
667{
668}
669
670Page::PageClients::~PageClients()
671{
672}
673
674} // namespace blink
675