1/*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6 * Copyright (C) Research In Motion Limited 2009. All rights reserved.
7 * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com>
8 * Copyright (C) 2011 Google Inc. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1.  Redistributions of source code must retain the above copyright
15 *     notice, this list of conditions and the following disclaimer.
16 * 2.  Redistributions in binary form must reproduce the above copyright
17 *     notice, this list of conditions and the following disclaimer in the
18 *     documentation and/or other materials provided with the distribution.
19 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
20 *     its contributors may be used to endorse or promote products derived
21 *     from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "config.h"
36#include "FrameLoader.h"
37
38#include "AXObjectCache.h"
39#include "ApplicationCacheHost.h"
40#include "BackForwardController.h"
41#include "BeforeUnloadEvent.h"
42#include "CachedPage.h"
43#include "CachedResourceLoader.h"
44#include "Chrome.h"
45#include "ChromeClient.h"
46#include "Console.h"
47#include "ContentSecurityPolicy.h"
48#include "DOMImplementation.h"
49#include "DOMWindow.h"
50#include "DatabaseManager.h"
51#include "Document.h"
52#include "DocumentLoadTiming.h"
53#include "DocumentLoader.h"
54#include "Editor.h"
55#include "EditorClient.h"
56#include "Element.h"
57#include "Event.h"
58#include "EventHandler.h"
59#include "EventNames.h"
60#include "FloatRect.h"
61#include "FormState.h"
62#include "FormSubmission.h"
63#include "Frame.h"
64#include "FrameLoadRequest.h"
65#include "FrameLoaderClient.h"
66#include "FrameNetworkingContext.h"
67#include "FrameTree.h"
68#include "FrameView.h"
69#include "HTMLAnchorElement.h"
70#include "HTMLFormElement.h"
71#include "HTMLInputElement.h"
72#include "HTMLNames.h"
73#include "HTMLObjectElement.h"
74#include "HTMLParserIdioms.h"
75#include "HTTPParsers.h"
76#include "HistoryController.h"
77#include "HistoryItem.h"
78#include "IconController.h"
79#include "InspectorController.h"
80#include "InspectorInstrumentation.h"
81#include "LoaderStrategy.h"
82#include "Logging.h"
83#include "MIMETypeRegistry.h"
84#include "MemoryCache.h"
85#include "Page.h"
86#include "PageActivityAssertionToken.h"
87#include "PageCache.h"
88#include "PageTransitionEvent.h"
89#include "PlatformStrategies.h"
90#include "PluginData.h"
91#include "PluginDatabase.h"
92#include "PluginDocument.h"
93#include "PolicyChecker.h"
94#include "ProgressTracker.h"
95#include "ResourceHandle.h"
96#include "ResourceRequest.h"
97#include "SchemeRegistry.h"
98#include "ScriptCallStack.h"
99#include "ScriptController.h"
100#include "ScriptSourceCode.h"
101#include "ScrollAnimator.h"
102#include "SecurityOrigin.h"
103#include "SecurityPolicy.h"
104#include "SegmentedString.h"
105#include "SerializedScriptValue.h"
106#include "Settings.h"
107#include "TextResourceDecoder.h"
108#include "WindowFeatures.h"
109#include "XMLDocumentParser.h"
110#include <wtf/CurrentTime.h>
111#include <wtf/StdLibExtras.h>
112#include <wtf/text/CString.h>
113#include <wtf/text/WTFString.h>
114
115#if ENABLE(SHARED_WORKERS)
116#include "SharedWorkerRepository.h"
117#endif
118
119#if ENABLE(SVG)
120#include "SVGDocument.h"
121#include "SVGLocatable.h"
122#include "SVGNames.h"
123#include "SVGPreserveAspectRatio.h"
124#include "SVGSVGElement.h"
125#include "SVGViewElement.h"
126#include "SVGViewSpec.h"
127#endif
128
129#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
130#include "Archive.h"
131#endif
132
133
134namespace WebCore {
135
136using namespace HTMLNames;
137
138#if ENABLE(SVG)
139using namespace SVGNames;
140#endif
141
142static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
143static double storedTimeOfLastCompletedLoad;
144
145bool isBackForwardLoadType(FrameLoadType type)
146{
147    switch (type) {
148        case FrameLoadTypeStandard:
149        case FrameLoadTypeReload:
150        case FrameLoadTypeReloadFromOrigin:
151        case FrameLoadTypeSame:
152        case FrameLoadTypeRedirectWithLockedBackForwardList:
153        case FrameLoadTypeReplace:
154            return false;
155        case FrameLoadTypeBack:
156        case FrameLoadTypeForward:
157        case FrameLoadTypeIndexedBackForward:
158            return true;
159    }
160    ASSERT_NOT_REACHED();
161    return false;
162}
163
164// This is not in the FrameLoader class to emphasize that it does not depend on
165// private FrameLoader data, and to avoid increasing the number of public functions
166// with access to private data.  Since only this .cpp file needs it, making it
167// non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
168// API simpler.
169//
170static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
171{
172    return frame->document() && frame->document()->isSandboxed(mask);
173}
174
175class FrameLoader::FrameProgressTracker {
176public:
177    static PassOwnPtr<FrameProgressTracker> create(Frame* frame) { return adoptPtr(new FrameProgressTracker(frame)); }
178    ~FrameProgressTracker()
179    {
180        ASSERT(!m_inProgress || m_frame->page());
181        if (m_inProgress)
182            m_frame->page()->progress()->progressCompleted(m_frame);
183    }
184
185    void progressStarted()
186    {
187        ASSERT(m_frame->page());
188        if (!m_inProgress)
189            m_frame->page()->progress()->progressStarted(m_frame);
190        m_inProgress = true;
191    }
192
193    void progressCompleted()
194    {
195        ASSERT(m_inProgress);
196        ASSERT(m_frame->page());
197        m_inProgress = false;
198        m_frame->page()->progress()->progressCompleted(m_frame);
199    }
200
201private:
202    FrameProgressTracker(Frame* frame)
203        : m_frame(frame)
204        , m_inProgress(false)
205    {
206    }
207
208    Frame* m_frame;
209    bool m_inProgress;
210};
211
212FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
213    : m_frame(frame)
214    , m_client(client)
215    , m_policyChecker(adoptPtr(new PolicyChecker(frame)))
216    , m_history(adoptPtr(new HistoryController(frame)))
217    , m_notifer(frame)
218    , m_subframeLoader(frame)
219    , m_icon(adoptPtr(new IconController(frame)))
220    , m_mixedContentChecker(frame)
221    , m_state(FrameStateProvisional)
222    , m_loadType(FrameLoadTypeStandard)
223    , m_delegateIsHandlingProvisionalLoadError(false)
224    , m_quickRedirectComing(false)
225    , m_sentRedirectNotification(false)
226    , m_inStopAllLoaders(false)
227    , m_isExecutingJavaScriptFormAction(false)
228    , m_didCallImplicitClose(true)
229    , m_wasUnloadEventEmitted(false)
230    , m_pageDismissalEventBeingDispatched(NoDismissal)
231    , m_isComplete(false)
232    , m_needsClear(false)
233    , m_checkTimer(this, &FrameLoader::checkTimerFired)
234    , m_shouldCallCheckCompleted(false)
235    , m_shouldCallCheckLoadComplete(false)
236    , m_opener(0)
237    , m_didPerformFirstNavigation(false)
238    , m_loadingFromCachedPage(false)
239    , m_suppressOpenerInNewFrame(false)
240    , m_currentNavigationHasShownBeforeUnloadConfirmPanel(false)
241    , m_forcedSandboxFlags(SandboxNone)
242{
243}
244
245FrameLoader::~FrameLoader()
246{
247    setOpener(0);
248
249    HashSet<Frame*>::iterator end = m_openedFrames.end();
250    for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
251        (*it)->loader()->m_opener = 0;
252
253    m_client->frameLoaderDestroyed();
254
255    if (m_networkingContext)
256        m_networkingContext->invalidate();
257}
258
259void FrameLoader::init()
260{
261    // This somewhat odd set of steps gives the frame an initial empty document.
262    setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, emptyString())), SubstituteData()).get());
263    setProvisionalDocumentLoader(m_policyDocumentLoader.get());
264    m_provisionalDocumentLoader->startLoadingMainResource();
265
266    RefPtr<Frame> protect(m_frame);
267    m_frame->document()->cancelParsing();
268    m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
269
270    m_networkingContext = m_client->createNetworkingContext();
271    m_progressTracker = FrameProgressTracker::create(m_frame);
272}
273
274void FrameLoader::setDefersLoading(bool defers)
275{
276    if (m_documentLoader)
277        m_documentLoader->setDefersLoading(defers);
278    if (m_provisionalDocumentLoader)
279        m_provisionalDocumentLoader->setDefersLoading(defers);
280    if (m_policyDocumentLoader)
281        m_policyDocumentLoader->setDefersLoading(defers);
282    history()->setDefersLoading(defers);
283
284    if (!defers) {
285        m_frame->navigationScheduler()->startTimer();
286        startCheckCompleteTimer();
287    }
288}
289
290void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool refresh)
291{
292    urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"),
293        0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL);
294}
295
296void FrameLoader::urlSelected(const KURL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer)
297{
298    urlSelected(FrameLoadRequest(m_frame->document()->securityOrigin(), ResourceRequest(url), passedTarget),
299        triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL);
300}
301
302// The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
303// corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
304void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
305{
306    ASSERT(!m_suppressOpenerInNewFrame);
307
308    RefPtr<Frame> protect(m_frame);
309    FrameLoadRequest frameRequest(passedRequest);
310
311    if (m_frame->script()->executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL))
312        return;
313
314    if (frameRequest.frameName().isEmpty())
315        frameRequest.setFrameName(m_frame->document()->baseTarget());
316
317    if (shouldSendReferrer == NeverSendReferrer)
318        m_suppressOpenerInNewFrame = true;
319    addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
320
321    loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer);
322
323    m_suppressOpenerInNewFrame = false;
324}
325
326void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
327{
328    ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
329
330    // FIXME: Find a good spot for these.
331    ASSERT(submission->data());
332    ASSERT(submission->state());
333    ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == m_frame);
334
335    if (!m_frame->page())
336        return;
337
338    if (submission->action().isEmpty())
339        return;
340
341    if (isDocumentSandboxed(m_frame, SandboxForms)) {
342        // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
343        m_frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set.");
344        return;
345    }
346
347    if (protocolIsJavaScript(submission->action())) {
348        if (!m_frame->document()->contentSecurityPolicy()->allowFormAction(KURL(submission->action())))
349            return;
350        m_isExecutingJavaScriptFormAction = true;
351        RefPtr<Frame> protect(m_frame);
352        m_frame->script()->executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL);
353        m_isExecutingJavaScriptFormAction = false;
354        return;
355    }
356
357    Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
358    if (!targetFrame) {
359        if (!DOMWindow::allowPopUp(m_frame) && !ScriptController::processingUserGesture())
360            return;
361
362        targetFrame = m_frame;
363    } else
364        submission->clearTarget();
365
366    if (!targetFrame->page())
367        return;
368
369    // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
370
371    // We do not want to submit more than one form from the same page, nor do we want to submit a single
372    // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
373    // The flag is reset in each time we start handle a new mouse or key down event, and
374    // also in setView since this part may get reused for a page from the back/forward cache.
375    // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
376
377    // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
378    // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
379    // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
380
381    if (m_frame->tree()->isDescendantOf(targetFrame)) {
382        if (m_submittedFormURL == submission->requestURL())
383            return;
384        m_submittedFormURL = submission->requestURL();
385    }
386
387    submission->data()->generateFiles(m_frame->document());
388    submission->setReferrer(outgoingReferrer());
389    submission->setOrigin(outgoingOrigin());
390
391    targetFrame->navigationScheduler()->scheduleFormSubmission(submission);
392}
393
394void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
395{
396    if (m_frame->document() && m_frame->document()->parser())
397        m_frame->document()->parser()->stopParsing();
398
399    if (unloadEventPolicy != UnloadEventPolicyNone) {
400        if (m_frame->document()) {
401            if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
402                Element* currentFocusedElement = m_frame->document()->focusedElement();
403                if (currentFocusedElement && currentFocusedElement->toInputElement())
404                    currentFocusedElement->toInputElement()->endEditing();
405                if (m_pageDismissalEventBeingDispatched == NoDismissal) {
406                    if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
407                        m_pageDismissalEventBeingDispatched = PageHideDismissal;
408                        m_frame->document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document());
409                    }
410
411                    // FIXME: update Page Visibility state here.
412                    // https://bugs.webkit.org/show_bug.cgi?id=116770
413
414                    if (!m_frame->document()->inPageCache()) {
415                        RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
416                        // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
417                        // while dispatching the event, so protect it to prevent writing the end
418                        // time into freed memory.
419                        RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
420                        m_pageDismissalEventBeingDispatched = UnloadDismissal;
421                        if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
422                            DocumentLoadTiming* timing = documentLoader->timing();
423                            ASSERT(timing->navigationStart());
424                            timing->markUnloadEventStart();
425                            m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
426                            timing->markUnloadEventEnd();
427                        } else
428                            m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
429                    }
430                }
431                m_pageDismissalEventBeingDispatched = NoDismissal;
432                if (m_frame->document())
433                    m_frame->document()->updateStyleIfNeeded();
434                m_wasUnloadEventEmitted = true;
435            }
436        }
437
438        // Dispatching the unload event could have made m_frame->document() null.
439        if (m_frame->document() && !m_frame->document()->inPageCache()) {
440            // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
441            bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
442                && m_frame->document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
443
444            if (!keepEventListeners)
445                m_frame->document()->removeAllEventListeners();
446        }
447    }
448
449    m_isComplete = true; // to avoid calling completed() in finishedParsing()
450    m_didCallImplicitClose = true; // don't want that one either
451
452    if (m_frame->document() && m_frame->document()->parsing()) {
453        finishedParsing();
454        m_frame->document()->setParsing(false);
455    }
456
457    if (Document* doc = m_frame->document()) {
458        // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
459        // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
460        doc->setReadyState(Document::Complete);
461
462#if ENABLE(SQL_DATABASE)
463        // FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here?
464        DatabaseManager::manager().stopDatabases(doc, 0);
465#endif
466    }
467
468    // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
469    m_frame->navigationScheduler()->cancel();
470}
471
472void FrameLoader::stop()
473{
474    // http://bugs.webkit.org/show_bug.cgi?id=10854
475    // The frame's last ref may be removed and it will be deleted by checkCompleted().
476    RefPtr<Frame> protector(m_frame);
477
478    if (DocumentParser* parser = m_frame->document()->parser()) {
479        parser->stopParsing();
480        parser->finish();
481    }
482
483    icon()->stopLoader();
484}
485
486void FrameLoader::willTransitionToCommitted()
487{
488    // This function is called when a frame is still fully in place (not cached, not detached), but will be replaced.
489
490    if (m_frame->editor().hasComposition()) {
491        // The text was already present in DOM, so it's better to confirm than to cancel the composition.
492        m_frame->editor().confirmComposition();
493        if (EditorClient* editorClient = m_frame->editor().client())
494            editorClient->respondToChangedSelection(m_frame);
495    }
496}
497
498bool FrameLoader::closeURL()
499{
500    history()->saveDocumentState();
501
502    // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
503    Document* currentDocument = m_frame->document();
504    stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly);
505
506    m_frame->editor().clearUndoRedoOperations();
507    return true;
508}
509
510bool FrameLoader::didOpenURL()
511{
512    if (m_frame->navigationScheduler()->redirectScheduledDuringLoad()) {
513        // A redirect was scheduled before the document was created.
514        // This can happen when one frame changes another frame's location.
515        return false;
516    }
517
518    m_frame->navigationScheduler()->cancel();
519    m_frame->editor().clearLastEditCommand();
520
521    m_isComplete = false;
522    m_didCallImplicitClose = false;
523
524    // If we are still in the process of initializing an empty document then
525    // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
526    // since it may cause clients to attempt to render the frame.
527    if (!m_stateMachine.creatingInitialEmptyDocument()) {
528        DOMWindow* window = m_frame->document()->domWindow();
529        window->setStatus(String());
530        window->setDefaultStatus(String());
531    }
532
533    started();
534
535    return true;
536}
537
538void FrameLoader::didExplicitOpen()
539{
540    m_isComplete = false;
541    m_didCallImplicitClose = false;
542
543    // Calling document.open counts as committing the first real document load.
544    if (!m_stateMachine.committedFirstRealDocumentLoad())
545        m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
546
547    // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
548    // from a subsequent window.document.open / window.document.write call.
549    // Canceling redirection here works for all cases because document.open
550    // implicitly precedes document.write.
551    m_frame->navigationScheduler()->cancel();
552}
553
554
555void FrameLoader::cancelAndClear()
556{
557    m_frame->navigationScheduler()->cancel();
558
559    if (!m_isComplete)
560        closeURL();
561
562    clear(m_frame->document(), false);
563    m_frame->script()->updatePlatformScriptObjects();
564}
565
566void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
567{
568    m_frame->editor().clear();
569
570    if (!m_needsClear)
571        return;
572    m_needsClear = false;
573
574    if (!m_frame->document()->inPageCache()) {
575        m_frame->document()->cancelParsing();
576        m_frame->document()->stopActiveDOMObjects();
577        if (m_frame->document()->attached()) {
578            m_frame->document()->prepareForDestruction();
579            m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
580        }
581    }
582
583    // Do this after detaching the document so that the unload event works.
584    if (clearWindowProperties) {
585        InspectorInstrumentation::frameWindowDiscarded(m_frame, m_frame->document()->domWindow());
586        m_frame->document()->domWindow()->resetUnlessSuspendedForPageCache();
587        m_frame->script()->clearWindowShell(newDocument->domWindow(), m_frame->document()->inPageCache());
588    }
589
590    m_frame->selection()->prepareForDestruction();
591    m_frame->eventHandler()->clear();
592    if (clearFrameView && m_frame->view())
593        m_frame->view()->clear();
594
595    // Do not drop the document before the ScriptController and view are cleared
596    // as some destructors might still try to access the document.
597    m_frame->setDocument(0);
598
599    m_subframeLoader.clear();
600
601    if (clearScriptObjects)
602        m_frame->script()->clearScriptObjects();
603
604    m_frame->script()->enableEval();
605
606    m_frame->navigationScheduler()->clear();
607
608    m_checkTimer.stop();
609    m_shouldCallCheckCompleted = false;
610    m_shouldCallCheckLoadComplete = false;
611
612    if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
613        m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
614}
615
616void FrameLoader::receivedFirstData()
617{
618    dispatchDidCommitLoad();
619    dispatchDidClearWindowObjectsInAllWorlds();
620    dispatchGlobalObjectAvailableInAllWorlds();
621
622    if (m_documentLoader) {
623        StringWithDirection ptitle = m_documentLoader->title();
624        // If we have a title let the WebView know about it.
625        if (!ptitle.isNull())
626            m_client->dispatchDidReceiveTitle(ptitle);
627    }
628
629    if (!m_documentLoader)
630        return;
631    if (m_frame->document()->isViewSource())
632        return;
633
634    double delay;
635    String url;
636    if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
637        return;
638    if (url.isEmpty())
639        url = m_frame->document()->url().string();
640    else
641        url = m_frame->document()->completeURL(url).string();
642
643    m_frame->navigationScheduler()->scheduleRedirect(delay, url);
644}
645
646void FrameLoader::setOutgoingReferrer(const KURL& url)
647{
648    m_outgoingReferrer = url.strippedForUseAsReferrer();
649}
650
651void FrameLoader::didBeginDocument(bool dispatch)
652{
653    m_needsClear = true;
654    m_isComplete = false;
655    m_didCallImplicitClose = false;
656    m_frame->document()->setReadyState(Document::Loading);
657
658    if (m_pendingStateObject) {
659        m_frame->document()->statePopped(m_pendingStateObject.get());
660        m_pendingStateObject.clear();
661    }
662
663    if (dispatch)
664        dispatchDidClearWindowObjectsInAllWorlds();
665
666    updateFirstPartyForCookies();
667    m_frame->document()->initContentSecurityPolicy();
668
669    Settings* settings = m_frame->document()->settings();
670    if (settings) {
671        m_frame->document()->cachedResourceLoader()->setImagesEnabled(settings->areImagesEnabled());
672        m_frame->document()->cachedResourceLoader()->setAutoLoadImages(settings->loadsImagesAutomatically());
673    }
674
675    if (m_documentLoader) {
676        String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
677        if (!dnsPrefetchControl.isEmpty())
678            m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
679
680        String policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy");
681        if (!policyValue.isEmpty())
682            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce);
683
684        policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy-Report-Only");
685        if (!policyValue.isEmpty())
686            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report);
687
688        policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP");
689        if (!policyValue.isEmpty())
690            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce);
691
692        policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP-Report-Only");
693        if (!policyValue.isEmpty())
694            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport);
695
696        String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
697        if (!headerContentLanguage.isEmpty()) {
698            size_t commaIndex = headerContentLanguage.find(',');
699            headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate
700            headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace);
701            if (!headerContentLanguage.isEmpty())
702                m_frame->document()->setContentLanguage(headerContentLanguage);
703        }
704    }
705
706    history()->restoreDocumentState();
707}
708
709void FrameLoader::finishedParsing()
710{
711    m_frame->injectUserScripts(InjectAtDocumentEnd);
712
713    if (m_stateMachine.creatingInitialEmptyDocument())
714        return;
715
716    // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
717    // because doing so will cause us to re-enter the destructor when protector goes out of scope.
718    // Null-checking the FrameView indicates whether or not we're in the destructor.
719    RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
720
721    m_client->dispatchDidFinishDocumentLoad();
722
723    checkCompleted();
724
725    if (!m_frame->view())
726        return; // We are being destroyed by something checkCompleted called.
727
728    // Check if the scrollbars are really needed for the content.
729    // If not, remove them, relayout, and repaint.
730    m_frame->view()->restoreScrollbar();
731    scrollToFragmentWithParentBoundary(m_frame->document()->url());
732}
733
734void FrameLoader::loadDone()
735{
736    checkCompleted();
737}
738
739bool FrameLoader::allChildrenAreComplete() const
740{
741    for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
742        if (!child->loader()->m_isComplete)
743            return false;
744    }
745    return true;
746}
747
748bool FrameLoader::allAncestorsAreComplete() const
749{
750    for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) {
751        if (!ancestor->loader()->m_isComplete)
752            return false;
753    }
754    return true;
755}
756
757void FrameLoader::checkCompleted()
758{
759    RefPtr<Frame> protect(m_frame);
760    m_shouldCallCheckCompleted = false;
761
762    if (m_frame->view())
763        m_frame->view()->handleLoadCompleted();
764
765    // Have we completed before?
766    if (m_isComplete)
767        return;
768
769    // Are we still parsing?
770    if (m_frame->document()->parsing())
771        return;
772
773    // Still waiting for images/scripts?
774    if (m_frame->document()->cachedResourceLoader()->requestCount())
775        return;
776
777    // Still waiting for elements that don't go through a FrameLoader?
778    if (m_frame->document()->isDelayingLoadEvent())
779        return;
780
781    // Any frame that hasn't completed yet?
782    if (!allChildrenAreComplete())
783        return;
784
785    // OK, completed.
786    m_isComplete = true;
787    m_requestedHistoryItem = 0;
788    m_frame->document()->setReadyState(Document::Complete);
789
790    checkCallImplicitClose(); // if we didn't do it before
791
792    m_frame->navigationScheduler()->startTimer();
793
794    completed();
795    if (m_frame->page())
796        checkLoadComplete();
797
798    if (m_frame->view())
799        m_frame->view()->handleLoadCompleted();
800}
801
802void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
803{
804    RefPtr<Frame> protect(m_frame);
805
806    if (Page* page = m_frame->page()) {
807        if (page->defersLoading())
808            return;
809    }
810    if (m_shouldCallCheckCompleted)
811        checkCompleted();
812    if (m_shouldCallCheckLoadComplete)
813        checkLoadComplete();
814}
815
816void FrameLoader::startCheckCompleteTimer()
817{
818    if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete))
819        return;
820    if (m_checkTimer.isActive())
821        return;
822    m_checkTimer.startOneShot(0);
823}
824
825void FrameLoader::scheduleCheckCompleted()
826{
827    m_shouldCallCheckCompleted = true;
828    startCheckCompleteTimer();
829}
830
831void FrameLoader::scheduleCheckLoadComplete()
832{
833    m_shouldCallCheckLoadComplete = true;
834    startCheckCompleteTimer();
835}
836
837void FrameLoader::checkCallImplicitClose()
838{
839    if (m_didCallImplicitClose || m_frame->document()->parsing() || m_frame->document()->isDelayingLoadEvent())
840        return;
841
842    if (!allChildrenAreComplete())
843        return; // still got a frame running -> too early
844
845    m_didCallImplicitClose = true;
846    m_wasUnloadEventEmitted = false;
847    m_frame->document()->implicitClose();
848}
849
850void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
851{
852    ASSERT(childFrame);
853
854#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
855    RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->uniqueName(), url);
856    if (subframeArchive) {
857        childFrame->loader()->loadArchive(subframeArchive.release());
858        return;
859    }
860#endif // ENABLE(WEB_ARCHIVE)
861
862    HistoryItem* parentItem = history()->currentItem();
863    // If we're moving in the back/forward list, we might want to replace the content
864    // of this child frame with whatever was there at that point.
865    if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType())
866        && !m_frame->document()->loadEventFinished()) {
867        HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree()->uniqueName());
868        if (childItem) {
869            childFrame->loader()->loadDifferentDocumentItem(childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem);
870            return;
871        }
872    }
873
874    childFrame->loader()->loadURL(url, referer, "_self", false, FrameLoadTypeRedirectWithLockedBackForwardList, 0, 0);
875}
876
877#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
878void FrameLoader::loadArchive(PassRefPtr<Archive> archive)
879{
880    ArchiveResource* mainResource = archive->mainResource();
881    ASSERT(mainResource);
882    if (!mainResource)
883        return;
884
885    SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
886
887    ResourceRequest request(mainResource->url());
888#if PLATFORM(MAC)
889    request.applyWebArchiveHackForMail();
890#endif
891
892    RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
893    documentLoader->setArchive(archive.get());
894    load(documentLoader.get());
895}
896#endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
897
898ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const String& mimeTypeIn, bool shouldPreferPlugInsForImages)
899{
900    String mimeType = mimeTypeIn;
901
902    if (mimeType.isEmpty())
903        mimeType = mimeTypeFromURL(url);
904
905#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL
906    if (mimeType.isEmpty()) {
907        String decodedPath = decodeURLEscapeSequences(url.path());
908        mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(decodedPath.substring(decodedPath.reverseFind('.') + 1));
909    }
910#endif
911
912    if (mimeType.isEmpty())
913        return ObjectContentFrame; // Go ahead and hope that we can display the content.
914
915#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL
916    bool plugInSupportsMIMEType = PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType);
917#else
918    bool plugInSupportsMIMEType = false;
919#endif
920
921    if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
922        return shouldPreferPlugInsForImages && plugInSupportsMIMEType ? WebCore::ObjectContentNetscapePlugin : WebCore::ObjectContentImage;
923
924    if (plugInSupportsMIMEType)
925        return WebCore::ObjectContentNetscapePlugin;
926
927    if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
928        return WebCore::ObjectContentFrame;
929
930    return WebCore::ObjectContentNone;
931}
932
933String FrameLoader::outgoingReferrer() const
934{
935    // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources
936    // for why we walk the parent chain for srcdoc documents.
937    Frame* frame = m_frame;
938    while (frame->document()->isSrcdocDocument()) {
939        frame = frame->tree()->parent();
940        // Srcdoc documents cannot be top-level documents, by definition,
941        // because they need to be contained in iframes with the srcdoc.
942        ASSERT(frame);
943    }
944    return frame->loader()->m_outgoingReferrer;
945}
946
947String FrameLoader::outgoingOrigin() const
948{
949    return m_frame->document()->securityOrigin()->toString();
950}
951
952bool FrameLoader::checkIfFormActionAllowedByCSP(const KURL& url) const
953{
954    if (m_submittedFormURL.isEmpty())
955        return true;
956
957    return m_frame->document()->contentSecurityPolicy()->allowFormAction(url);
958}
959
960Frame* FrameLoader::opener()
961{
962    return m_opener;
963}
964
965void FrameLoader::setOpener(Frame* opener)
966{
967    if (m_opener && !opener)
968        m_client->didDisownOpener();
969
970    if (m_opener)
971        m_opener->loader()->m_openedFrames.remove(m_frame);
972    if (opener)
973        opener->loader()->m_openedFrames.add(m_frame);
974    m_opener = opener;
975
976    if (m_frame->document())
977        m_frame->document()->initSecurityContext();
978}
979
980// FIXME: This does not belong in FrameLoader!
981void FrameLoader::handleFallbackContent()
982{
983    HTMLFrameOwnerElement* owner = m_frame->ownerElement();
984    if (!owner || !owner->hasTagName(objectTag))
985        return;
986    static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
987}
988
989void FrameLoader::provisionalLoadStarted()
990{
991    if (m_stateMachine.firstLayoutDone())
992        m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
993    m_frame->navigationScheduler()->cancel(true);
994    m_client->provisionalLoadStarted();
995}
996
997void FrameLoader::resetMultipleFormSubmissionProtection()
998{
999    m_submittedFormURL = KURL();
1000}
1001
1002void FrameLoader::updateFirstPartyForCookies()
1003{
1004    if (m_frame->tree()->parent())
1005        setFirstPartyForCookies(m_frame->tree()->parent()->document()->firstPartyForCookies());
1006    else
1007        setFirstPartyForCookies(m_frame->document()->url());
1008}
1009
1010void FrameLoader::setFirstPartyForCookies(const KURL& url)
1011{
1012    for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
1013        frame->document()->setFirstPartyForCookies(url);
1014}
1015
1016// This does the same kind of work that didOpenURL does, except it relies on the fact
1017// that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1018void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScriptValue> stateObject, bool isNewNavigation)
1019{
1020    // If we have a state object, we cannot also be a new navigation.
1021    ASSERT(!stateObject || (stateObject && !isNewNavigation));
1022
1023    // Update the data source's request with the new URL to fake the URL change
1024    KURL oldURL = m_frame->document()->url();
1025    m_frame->document()->setURL(url);
1026    setOutgoingReferrer(url);
1027    documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
1028    if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) {
1029        // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add
1030        // based on the current request. Must also happen before we openURL and displace the
1031        // scroll position, since adding the BF item will save away scroll state.
1032
1033        // NB2: If we were loading a long, slow doc, and the user fragment navigated before
1034        // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1035        // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
1036        // though its load is not yet done.  I think this all works out OK, for one because
1037        // we have already saved away the scroll and doc state for the long slow load,
1038        // but it's not an obvious case.
1039
1040        history()->updateBackForwardListForFragmentScroll();
1041    }
1042
1043    bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
1044
1045    history()->updateForSameDocumentNavigation();
1046
1047    // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
1048    if (hashChange)
1049        m_frame->eventHandler()->stopAutoscrollTimer();
1050
1051    // It's important to model this as a load that starts and immediately finishes.
1052    // Otherwise, the parent frame may think we never finished loading.
1053    started();
1054
1055    // We need to scroll to the fragment whether or not a hash change occurred, since
1056    // the user might have scrolled since the previous navigation.
1057    scrollToFragmentWithParentBoundary(url);
1058
1059    m_isComplete = false;
1060    checkCompleted();
1061
1062    if (isNewNavigation) {
1063        // This will clear previousItem from the rest of the frame tree that didn't
1064        // doing any loading. We need to make a pass on this now, since for fragment
1065        // navigation we'll not go through a real load and reach Completed state.
1066        checkLoadComplete();
1067    }
1068
1069    m_client->dispatchDidNavigateWithinPage();
1070
1071    m_frame->document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
1072    m_client->dispatchDidPopStateWithinPage();
1073
1074    if (hashChange) {
1075        m_frame->document()->enqueueHashchangeEvent(oldURL, url);
1076        m_client->dispatchDidChangeLocationWithinPage();
1077    }
1078
1079    // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
1080    m_client->didFinishLoad();
1081}
1082
1083bool FrameLoader::isComplete() const
1084{
1085    return m_isComplete;
1086}
1087
1088void FrameLoader::completed()
1089{
1090    RefPtr<Frame> protect(m_frame);
1091
1092    for (Frame* descendant = m_frame->tree()->traverseNext(m_frame); descendant; descendant = descendant->tree()->traverseNext(m_frame))
1093        descendant->navigationScheduler()->startTimer();
1094
1095    if (Frame* parent = m_frame->tree()->parent())
1096        parent->loader()->checkCompleted();
1097
1098    if (m_frame->view())
1099        m_frame->view()->maintainScrollPositionAtAnchor(0);
1100    m_activityAssertion.clear();
1101}
1102
1103void FrameLoader::started()
1104{
1105    if (m_frame && m_frame->page())
1106        m_activityAssertion = m_frame->page()->createActivityToken();
1107    for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
1108        frame->loader()->m_isComplete = false;
1109}
1110
1111void FrameLoader::prepareForHistoryNavigation()
1112{
1113    // If there is no currentItem, but we still want to engage in
1114    // history navigation we need to manufacture one, and update
1115    // the state machine of this frame to impersonate having
1116    // loaded it.
1117    RefPtr<HistoryItem> currentItem = history()->currentItem();
1118    if (!currentItem) {
1119        currentItem = HistoryItem::create();
1120        currentItem->setLastVisitWasFailure(true);
1121        history()->setCurrentItem(currentItem.get());
1122        frame()->page()->backForward()->setCurrentItem(currentItem.get());
1123
1124        ASSERT(stateMachine()->isDisplayingInitialEmptyDocument());
1125        stateMachine()->advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1126        stateMachine()->advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
1127    }
1128}
1129
1130void FrameLoader::prepareForLoadStart()
1131{
1132    m_progressTracker->progressStarted();
1133    m_client->dispatchDidStartProvisionalLoad();
1134
1135    // Notify accessibility.
1136    if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) {
1137        AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadTypeReload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
1138        cache->frameLoadingEventNotification(m_frame, loadingEvent);
1139    }
1140}
1141
1142void FrameLoader::setupForReplace()
1143{
1144    m_client->revertToProvisionalState(m_documentLoader.get());
1145    setState(FrameStateProvisional);
1146    m_provisionalDocumentLoader = m_documentLoader;
1147    m_documentLoader = 0;
1148    detachChildren();
1149}
1150
1151void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList,
1152    PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer)
1153{
1154    // Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader.
1155    RefPtr<Frame> protect(m_frame);
1156
1157    KURL url = request.resourceRequest().url();
1158
1159    ASSERT(m_frame->document());
1160    if (!request.requester()->canDisplay(url)) {
1161        reportLocalLoadFailed(m_frame, url.stringCenterEllipsizedToLength());
1162        return;
1163    }
1164
1165    String argsReferrer = request.resourceRequest().httpReferrer();
1166    if (argsReferrer.isEmpty())
1167        argsReferrer = outgoingReferrer();
1168
1169    String referrer = SecurityPolicy::generateReferrerHeader(m_frame->document()->referrerPolicy(), url, argsReferrer);
1170    if (shouldSendReferrer == NeverSendReferrer)
1171        referrer = String();
1172
1173    FrameLoadType loadType;
1174    if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1175        loadType = FrameLoadTypeReload;
1176    else if (lockBackForwardList)
1177        loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1178    else
1179        loadType = FrameLoadTypeStandard;
1180
1181    if (request.resourceRequest().httpMethod() == "POST")
1182        loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
1183    else
1184        loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
1185
1186    // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
1187    // load if frame names have changed.
1188    Frame* sourceFrame = formState ? formState->sourceDocument()->frame() : m_frame;
1189    if (!sourceFrame)
1190        sourceFrame = m_frame;
1191    Frame* targetFrame = sourceFrame->loader()->findFrameForNavigation(request.frameName());
1192    if (targetFrame && targetFrame != sourceFrame) {
1193        if (Page* page = targetFrame->page())
1194            page->chrome().focus();
1195    }
1196}
1197
1198void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
1199    PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
1200{
1201    if (m_inStopAllLoaders)
1202        return;
1203
1204    RefPtr<Frame> protect(m_frame);
1205
1206    RefPtr<FormState> formState = prpFormState;
1207    bool isFormSubmission = formState;
1208
1209    ResourceRequest request(newURL);
1210    if (!referrer.isEmpty()) {
1211        request.setHTTPReferrer(referrer);
1212        RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
1213        addHTTPOriginIfNeeded(request, referrerOrigin->toString());
1214    }
1215#if ENABLE(CACHE_PARTITIONING)
1216    if (m_frame->tree()->top() != m_frame)
1217        request.setCachePartition(m_frame->tree()->top()->document()->securityOrigin()->cachePartition());
1218#endif
1219    addExtraFieldsToRequest(request, newLoadType, true);
1220    if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
1221        request.setCachePolicy(ReloadIgnoringCacheData);
1222
1223    ASSERT(newLoadType != FrameLoadTypeSame);
1224
1225    // The search for a target frame is done earlier in the case of form submission.
1226    Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
1227    if (targetFrame && targetFrame != m_frame) {
1228        targetFrame->loader()->loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release());
1229        return;
1230    }
1231
1232    if (m_pageDismissalEventBeingDispatched != NoDismissal)
1233        return;
1234
1235    NavigationAction action(request, newLoadType, isFormSubmission, event);
1236
1237    if (!targetFrame && !frameName.isEmpty()) {
1238        policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy,
1239            request, formState.release(), frameName, this);
1240        return;
1241    }
1242
1243    RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1244
1245    bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
1246    const String& httpMethod = request.httpMethod();
1247
1248    // Make sure to do scroll to fragment processing even if the URL is
1249    // exactly the same so pages with '#' links and DHTML side effects
1250    // work properly.
1251    if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, newLoadType, newURL)) {
1252        oldDocumentLoader->setTriggeringAction(action);
1253        policyChecker()->stopCheck();
1254        policyChecker()->setLoadType(newLoadType);
1255        policyChecker()->checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(),
1256            callContinueFragmentScrollAfterNavigationPolicy, this);
1257    } else {
1258        // must grab this now, since this load may stop the previous load and clear this flag
1259        bool isRedirect = m_quickRedirectComing;
1260        loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release());
1261        if (isRedirect) {
1262            m_quickRedirectComing = false;
1263            if (m_provisionalDocumentLoader)
1264                m_provisionalDocumentLoader->setIsClientRedirect(true);
1265        } else if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin)
1266            // Example of this case are sites that reload the same URL with a different cookie
1267            // driving the generated content, or a master frame with links that drive a target
1268            // frame, where the user has clicked on the same link repeatedly.
1269            m_loadType = FrameLoadTypeSame;
1270    }
1271}
1272
1273SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url)
1274{
1275    if (!shouldTreatURLAsSrcdocDocument(url))
1276        return SubstituteData();
1277    String srcdoc = m_frame->ownerElement()->fastGetAttribute(srcdocAttr);
1278    ASSERT(!srcdoc.isNull());
1279    CString encodedSrcdoc = srcdoc.utf8();
1280    return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL());
1281}
1282
1283void FrameLoader::load(const FrameLoadRequest& passedRequest)
1284{
1285    FrameLoadRequest request(passedRequest);
1286
1287    if (m_inStopAllLoaders)
1288        return;
1289
1290    if (!request.frameName().isEmpty()) {
1291        Frame* frame = findFrameForNavigation(request.frameName());
1292        if (frame) {
1293            request.setShouldCheckNewWindowPolicy(false);
1294            if (frame->loader() != this) {
1295                frame->loader()->load(request);
1296                return;
1297            }
1298        }
1299    }
1300
1301    if (request.shouldCheckNewWindowPolicy()) {
1302        policyChecker()->checkNewWindowPolicy(NavigationAction(request.resourceRequest(), NavigationTypeOther), FrameLoader::callContinueLoadAfterNewWindowPolicy, request.resourceRequest(), 0, request.frameName(), this);
1303        return;
1304    }
1305
1306    if (!request.hasSubstituteData())
1307        request.setSubstituteData(defaultSubstituteDataForURL(request.resourceRequest().url()));
1308
1309    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request.resourceRequest(), request.substituteData());
1310    if (request.lockHistory() && m_documentLoader)
1311        loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
1312    load(loader.get());
1313}
1314
1315void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
1316{
1317    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1318    if (lockHistory && m_documentLoader)
1319        loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
1320
1321    loader->setTriggeringAction(action);
1322    if (m_documentLoader)
1323        loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1324
1325    loadWithDocumentLoader(loader.get(), type, formState);
1326}
1327
1328void FrameLoader::load(DocumentLoader* newDocumentLoader)
1329{
1330    ResourceRequest& r = newDocumentLoader->request();
1331    addExtraFieldsToMainResourceRequest(r);
1332    FrameLoadType type;
1333
1334    if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
1335        r.setCachePolicy(ReloadIgnoringCacheData);
1336        type = FrameLoadTypeSame;
1337    } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadTypeReload)
1338        type = FrameLoadTypeReload;
1339    else
1340        type = FrameLoadTypeStandard;
1341
1342    if (m_documentLoader)
1343        newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1344
1345    // When we loading alternate content for an unreachable URL that we're
1346    // visiting in the history list, we treat it as a reload so the history list
1347    // is appropriately maintained.
1348    //
1349    // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
1350    // shouldn't a more explicit type of reload be defined, that means roughly
1351    // "load without affecting history" ?
1352    if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
1353        // shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.
1354        // In this case we should save the document state now. Otherwise the state can be lost because load type is
1355        // changed and updateForBackForwardNavigation() will not be called when loading is committed.
1356        history()->saveDocumentAndScrollState();
1357
1358        ASSERT(type == FrameLoadTypeStandard);
1359        type = FrameLoadTypeReload;
1360    }
1361
1362    loadWithDocumentLoader(newDocumentLoader, type, 0);
1363}
1364
1365void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
1366{
1367    // Retain because dispatchBeforeLoadEvent may release the last reference to it.
1368    RefPtr<Frame> protect(m_frame);
1369
1370    ASSERT(m_client->hasWebView());
1371
1372    // Unfortunately the view must be non-nil, this is ultimately due
1373    // to parser requiring a FrameView.  We should fix this dependency.
1374
1375    ASSERT(m_frame->view());
1376
1377    if (m_pageDismissalEventBeingDispatched != NoDismissal)
1378        return;
1379
1380    if (m_frame->document())
1381        m_previousURL = m_frame->document()->url();
1382
1383    policyChecker()->setLoadType(type);
1384    RefPtr<FormState> formState = prpFormState;
1385    bool isFormSubmission = formState;
1386
1387    const KURL& newURL = loader->request().url();
1388    const String& httpMethod = loader->request().httpMethod();
1389
1390    if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker()->loadType(), newURL)) {
1391        RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1392        NavigationAction action(loader->request(), policyChecker()->loadType(), isFormSubmission);
1393
1394        oldDocumentLoader->setTriggeringAction(action);
1395        policyChecker()->stopCheck();
1396        policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
1397            callContinueFragmentScrollAfterNavigationPolicy, this);
1398    } else {
1399        if (Frame* parent = m_frame->tree()->parent())
1400            loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
1401
1402        policyChecker()->stopCheck();
1403        setPolicyDocumentLoader(loader);
1404        if (loader->triggeringAction().isEmpty())
1405            loader->setTriggeringAction(NavigationAction(loader->request(), policyChecker()->loadType(), isFormSubmission));
1406
1407        if (Element* ownerElement = m_frame->ownerElement()) {
1408            // We skip dispatching the beforeload event if we've already
1409            // committed a real document load because the event would leak
1410            // subsequent activity by the frame which the parent frame isn't
1411            // supposed to learn. For example, if the child frame navigated to
1412            // a new URL, the parent frame shouldn't learn the URL.
1413            if (!m_stateMachine.committedFirstRealDocumentLoad()
1414                && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
1415                continueLoadAfterNavigationPolicy(loader->request(), formState, false);
1416                return;
1417            }
1418        }
1419
1420        policyChecker()->checkNavigationPolicy(loader->request(), loader, formState,
1421            callContinueLoadAfterNavigationPolicy, this);
1422    }
1423}
1424
1425void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
1426{
1427    ASSERT(!url.isEmpty());
1428    if (!frame)
1429        return;
1430
1431    frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url);
1432}
1433
1434const ResourceRequest& FrameLoader::initialRequest() const
1435{
1436    return activeDocumentLoader()->originalRequest();
1437}
1438
1439bool FrameLoader::willLoadMediaElementURL(KURL& url)
1440{
1441    ResourceRequest request(url);
1442
1443    unsigned long identifier;
1444    ResourceError error;
1445    requestFromDelegate(request, identifier, error);
1446    notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String(), String()), 0, -1, -1, error);
1447
1448    url = request.url();
1449
1450    return error.isNull();
1451}
1452
1453bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
1454{
1455    KURL unreachableURL = docLoader->unreachableURL();
1456
1457    if (unreachableURL.isEmpty())
1458        return false;
1459
1460    if (!isBackForwardLoadType(policyChecker()->loadType()))
1461        return false;
1462
1463    // We only treat unreachableURLs specially during the delegate callbacks
1464    // for provisional load errors and navigation policy decisions. The former
1465    // case handles well-formed URLs that can't be loaded, and the latter
1466    // case handles malformed URLs and unknown schemes. Loading alternate content
1467    // at other times behaves like a standard load.
1468    DocumentLoader* compareDocumentLoader = 0;
1469    if (policyChecker()->delegateIsDecidingNavigationPolicy() || policyChecker()->delegateIsHandlingUnimplementablePolicy())
1470        compareDocumentLoader = m_policyDocumentLoader.get();
1471    else if (m_delegateIsHandlingProvisionalLoadError)
1472        compareDocumentLoader = m_provisionalDocumentLoader.get();
1473
1474    return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
1475}
1476
1477void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
1478{
1479    if (!m_documentLoader)
1480        return;
1481
1482    ResourceRequest request = m_documentLoader->request();
1483    KURL unreachableURL = m_documentLoader->unreachableURL();
1484    if (!unreachableURL.isEmpty())
1485        request.setURL(unreachableURL);
1486
1487    // FIXME: If the resource is a result of form submission and is not cached, the form will be silently resubmitted.
1488    // We should ask the user for confirmation in this case.
1489    request.setCachePolicy(ReturnCacheDataElseLoad);
1490
1491    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1492    setPolicyDocumentLoader(loader.get());
1493
1494    loader->setOverrideEncoding(encoding);
1495
1496    loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
1497}
1498
1499void FrameLoader::reloadWithOverrideURL(const KURL& overrideUrl, bool endToEndReload)
1500{
1501    if (!m_documentLoader)
1502        return;
1503
1504    if (overrideUrl.isEmpty())
1505        return;
1506
1507    ResourceRequest request = m_documentLoader->request();
1508    request.setURL(overrideUrl);
1509    reloadWithRequest(request, endToEndReload);
1510}
1511
1512void FrameLoader::reload(bool endToEndReload)
1513{
1514    if (!m_documentLoader)
1515        return;
1516
1517    // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1518    // Reloading in this case will lose the current contents (see 4151001).
1519    if (m_documentLoader->request().url().isEmpty())
1520        return;
1521
1522    // Replace error-page URL with the URL we were trying to reach.
1523    ResourceRequest initialRequest = m_documentLoader->request();
1524    KURL unreachableURL = m_documentLoader->unreachableURL();
1525    if (!unreachableURL.isEmpty())
1526        initialRequest.setURL(unreachableURL);
1527
1528    reloadWithRequest(initialRequest, endToEndReload);
1529}
1530
1531void FrameLoader::reloadWithRequest(const ResourceRequest& initialRequest, bool endToEndReload)
1532{
1533    ASSERT(m_documentLoader);
1534
1535    // Create a new document loader for the reload, this will become m_documentLoader eventually,
1536    // but first it has to be the "policy" document loader, and then the "provisional" document loader.
1537    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
1538
1539    ResourceRequest& request = loader->request();
1540
1541    // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
1542    request.setCachePolicy(ReloadIgnoringCacheData);
1543
1544    // If we're about to re-post, set up action so the application can warn the user.
1545    if (request.httpMethod() == "POST")
1546        loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted));
1547
1548    loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1549
1550    loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
1551}
1552
1553void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
1554{
1555    ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
1556    if (m_pageDismissalEventBeingDispatched != NoDismissal)
1557        return;
1558
1559    // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
1560    if (m_inStopAllLoaders)
1561        return;
1562
1563    // Calling stopLoading() on the provisional document loader can blow away
1564    // the frame from underneath.
1565    RefPtr<Frame> protect(m_frame);
1566
1567    m_inStopAllLoaders = true;
1568
1569    policyChecker()->stopCheck();
1570
1571    // If no new load is in progress, we should clear the provisional item from history
1572    // before we call stopLoading.
1573    if (clearProvisionalItemPolicy == ShouldClearProvisionalItem)
1574        history()->setProvisionalItem(0);
1575
1576    for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1577        child->loader()->stopAllLoaders(clearProvisionalItemPolicy);
1578    if (m_provisionalDocumentLoader)
1579        m_provisionalDocumentLoader->stopLoading();
1580    if (m_documentLoader)
1581        m_documentLoader->stopLoading();
1582
1583    setProvisionalDocumentLoader(0);
1584
1585    m_checkTimer.stop();
1586
1587    m_inStopAllLoaders = false;
1588}
1589
1590void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
1591{
1592    stopAllLoaders();
1593
1594    if (deferCheckLoadComplete)
1595        scheduleCheckLoadComplete();
1596    else if (m_frame->page())
1597        checkLoadComplete();
1598}
1599
1600DocumentLoader* FrameLoader::activeDocumentLoader() const
1601{
1602    if (m_state == FrameStateProvisional)
1603        return m_provisionalDocumentLoader.get();
1604    return m_documentLoader.get();
1605}
1606
1607bool FrameLoader::isLoading() const
1608{
1609    DocumentLoader* docLoader = activeDocumentLoader();
1610    if (!docLoader)
1611        return false;
1612    return docLoader->isLoading();
1613}
1614
1615bool FrameLoader::frameHasLoaded() const
1616{
1617    return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument());
1618}
1619
1620void FrameLoader::setDocumentLoader(DocumentLoader* loader)
1621{
1622    if (!loader && !m_documentLoader)
1623        return;
1624
1625    ASSERT(loader != m_documentLoader);
1626    ASSERT(!loader || loader->frameLoader() == this);
1627
1628    m_client->prepareForDataSourceReplacement();
1629    detachChildren();
1630
1631    // detachChildren() can trigger this frame's unload event, and therefore
1632    // script can run and do just about anything. For example, an unload event that calls
1633    // document.write("") on its parent frame can lead to a recursive detachChildren()
1634    // invocation for this frame. In that case, we can end up at this point with a
1635    // loader that hasn't been deleted but has been detached from its frame. Such a
1636    // DocumentLoader has been sufficiently detached that we'll end up in an inconsistent
1637    // state if we try to use it.
1638    if (loader && !loader->frame())
1639        return;
1640
1641    if (m_documentLoader)
1642        m_documentLoader->detachFromFrame();
1643
1644    m_documentLoader = loader;
1645}
1646
1647void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
1648{
1649    if (m_policyDocumentLoader == loader)
1650        return;
1651
1652    ASSERT(m_frame);
1653    if (loader)
1654        loader->setFrame(m_frame);
1655    if (m_policyDocumentLoader
1656            && m_policyDocumentLoader != m_provisionalDocumentLoader
1657            && m_policyDocumentLoader != m_documentLoader)
1658        m_policyDocumentLoader->detachFromFrame();
1659
1660    m_policyDocumentLoader = loader;
1661}
1662
1663void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
1664{
1665    ASSERT(!loader || !m_provisionalDocumentLoader);
1666    ASSERT(!loader || loader->frameLoader() == this);
1667
1668    if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
1669        m_provisionalDocumentLoader->detachFromFrame();
1670
1671    m_provisionalDocumentLoader = loader;
1672}
1673
1674double FrameLoader::timeOfLastCompletedLoad()
1675{
1676    return storedTimeOfLastCompletedLoad;
1677}
1678
1679void FrameLoader::setState(FrameState newState)
1680{
1681    m_state = newState;
1682
1683    if (newState == FrameStateProvisional)
1684        provisionalLoadStarted();
1685    else if (newState == FrameStateComplete) {
1686        frameLoadCompleted();
1687        storedTimeOfLastCompletedLoad = currentTime();
1688        if (m_documentLoader)
1689            m_documentLoader->stopRecordingResponses();
1690    }
1691}
1692
1693void FrameLoader::clearProvisionalLoad()
1694{
1695    setProvisionalDocumentLoader(0);
1696    m_progressTracker->progressCompleted();
1697    setState(FrameStateComplete);
1698}
1699
1700void FrameLoader::commitProvisionalLoad()
1701{
1702    RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : 0;
1703    RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
1704    RefPtr<Frame> protect(m_frame);
1705
1706    LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(),
1707        m_frame->document() ? m_frame->document()->url().stringCenterEllipsizedToLength().utf8().data() : "",
1708        pdl ? pdl->url().stringCenterEllipsizedToLength().utf8().data() : "<no provisional DocumentLoader>");
1709
1710    willTransitionToCommitted();
1711
1712    // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
1713    // We are doing this here because we know for sure that a new page is about to be loaded.
1714    HistoryItem* item = history()->currentItem();
1715    if (!m_frame->tree()->parent() && pageCache()->canCache(m_frame->page()) && !item->isInPageCache())
1716        pageCache()->add(item, m_frame->page());
1717
1718    if (m_loadType != FrameLoadTypeReplace)
1719        closeOldDataSources();
1720
1721    if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
1722        m_client->makeRepresentation(pdl.get());
1723
1724    transitionToCommitted(cachedPage);
1725
1726    if (pdl && m_documentLoader) {
1727        // Check if the destination page is allowed to access the previous page's timing information.
1728        RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
1729        m_documentLoader->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_previousURL));
1730    }
1731
1732    // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
1733    // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
1734    // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
1735    // just about to commit a new page, there cannot possibly be a pending redirect at this point.
1736    if (m_sentRedirectNotification)
1737        clientRedirectCancelledOrFinished(false);
1738
1739    if (cachedPage && cachedPage->document()) {
1740        prepareForCachedPageRestore();
1741        cachedPage->restore(m_frame->page());
1742
1743        // The page should be removed from the cache immediately after a restoration in order for the PageCache to be consistent.
1744        pageCache()->remove(history()->currentItem());
1745
1746        dispatchDidCommitLoad();
1747
1748        // If we have a title let the WebView know about it.
1749        StringWithDirection title = m_documentLoader->title();
1750        if (!title.isNull())
1751            m_client->dispatchDidReceiveTitle(title);
1752
1753        checkCompleted();
1754    } else {
1755        if (cachedPage)
1756            pageCache()->remove(history()->currentItem());
1757        didOpenURL();
1758    }
1759
1760    LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(),
1761        m_frame->document() ? m_frame->document()->url().stringCenterEllipsizedToLength().utf8().data() : "");
1762
1763    if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
1764        history()->updateForClientRedirect();
1765
1766    if (m_loadingFromCachedPage) {
1767        m_frame->document()->documentDidResumeFromPageCache();
1768
1769        // Force a layout to update view size and thereby update scrollbars.
1770        m_frame->view()->forceLayout();
1771
1772        const ResponseVector& responses = m_documentLoader->responses();
1773        size_t count = responses.size();
1774        for (size_t i = 0; i < count; i++) {
1775            const ResourceResponse& response = responses[i];
1776            // FIXME: If the WebKit client changes or cancels the request, this is not respected.
1777            ResourceError error;
1778            unsigned long identifier;
1779            ResourceRequest request(response.url());
1780            requestFromDelegate(request, identifier, error);
1781            // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
1782            // However, with today's computers and networking speeds, this won't happen in practice.
1783            // Could be an issue with a giant local file.
1784            notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, 0, static_cast<int>(response.expectedContentLength()), 0, error);
1785        }
1786
1787        // FIXME: Why only this frame and not parent frames?
1788        checkLoadCompleteForThisFrame();
1789    }
1790}
1791
1792void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
1793{
1794    ASSERT(m_client->hasWebView());
1795    ASSERT(m_state == FrameStateProvisional);
1796
1797    if (m_state != FrameStateProvisional)
1798        return;
1799
1800    if (FrameView* view = m_frame->view()) {
1801        if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
1802            scrollAnimator->cancelAnimations();
1803    }
1804
1805    m_client->setCopiesOnScroll();
1806    history()->updateForCommit();
1807
1808    // The call to closeURL() invokes the unload event handler, which can execute arbitrary
1809    // JavaScript. If the script initiates a new load, we need to abandon the current load,
1810    // or the two will stomp each other.
1811    DocumentLoader* pdl = m_provisionalDocumentLoader.get();
1812    if (m_documentLoader)
1813        closeURL();
1814    if (pdl != m_provisionalDocumentLoader)
1815        return;
1816
1817    // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
1818    if (m_documentLoader)
1819        m_documentLoader->stopLoadingSubresources();
1820    if (m_documentLoader)
1821        m_documentLoader->stopLoadingPlugIns();
1822
1823    setDocumentLoader(m_provisionalDocumentLoader.get());
1824    setProvisionalDocumentLoader(0);
1825
1826    if (pdl != m_documentLoader) {
1827        ASSERT(m_state == FrameStateComplete);
1828        return;
1829    }
1830
1831    setState(FrameStateCommittedPage);
1832
1833#if ENABLE(TOUCH_EVENTS)
1834    if (isLoadingMainFrame())
1835        m_frame->page()->chrome().client()->needTouchEvents(false);
1836#endif
1837
1838    // Handle adding the URL to the back/forward list.
1839    DocumentLoader* dl = m_documentLoader.get();
1840
1841    switch (m_loadType) {
1842        case FrameLoadTypeForward:
1843        case FrameLoadTypeBack:
1844        case FrameLoadTypeIndexedBackForward:
1845            if (m_frame->page()) {
1846                // If the first load within a frame is a navigation within a back/forward list that was attached
1847                // without any of the items being loaded then we need to update the history in a similar manner as
1848                // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
1849                if (!m_stateMachine.committedFirstRealDocumentLoad() && isLoadingMainFrame())
1850                    history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
1851
1852                history()->updateForBackForwardNavigation();
1853
1854                // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
1855                if (history()->currentItem() && !cachedPage)
1856                    m_pendingStateObject = history()->currentItem()->stateObject();
1857
1858                // Create a document view for this document, or used the cached view.
1859                if (cachedPage) {
1860                    DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
1861                    ASSERT(cachedDocumentLoader);
1862                    cachedDocumentLoader->setFrame(m_frame);
1863                    m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
1864
1865                } else
1866                    m_client->transitionToCommittedForNewPage();
1867            }
1868            break;
1869
1870        case FrameLoadTypeReload:
1871        case FrameLoadTypeReloadFromOrigin:
1872        case FrameLoadTypeSame:
1873        case FrameLoadTypeReplace:
1874            history()->updateForReload();
1875            m_client->transitionToCommittedForNewPage();
1876            break;
1877
1878        case FrameLoadTypeStandard:
1879            history()->updateForStandardLoad();
1880            if (m_frame->view())
1881                m_frame->view()->setScrollbarsSuppressed(true);
1882            m_client->transitionToCommittedForNewPage();
1883            break;
1884
1885        case FrameLoadTypeRedirectWithLockedBackForwardList:
1886            history()->updateForRedirectWithLockedBackForwardList();
1887            m_client->transitionToCommittedForNewPage();
1888            break;
1889
1890        // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1891        // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
1892        default:
1893            ASSERT_NOT_REACHED();
1894    }
1895
1896    m_documentLoader->writer()->setMIMEType(dl->responseMIMEType());
1897
1898    // Tell the client we've committed this URL.
1899    ASSERT(m_frame->view());
1900
1901    if (m_stateMachine.creatingInitialEmptyDocument())
1902        return;
1903
1904    if (!m_stateMachine.committedFirstRealDocumentLoad())
1905        m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1906}
1907
1908void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
1909{
1910    // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1911    // the redirect succeeded.  We should either rename this API, or add a new method, like
1912    // -webView:didFinishClientRedirectForFrame:
1913    m_client->dispatchDidCancelClientRedirect();
1914
1915    if (!cancelWithLoadInProgress)
1916        m_quickRedirectComing = false;
1917
1918    m_sentRedirectNotification = false;
1919}
1920
1921void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList)
1922{
1923    m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
1924
1925    // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1926    // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1927    m_sentRedirectNotification = true;
1928
1929    // If a "quick" redirect comes in, we set a special mode so we treat the next
1930    // load as part of the original navigation. If we don't have a document loader, we have
1931    // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
1932    // Loads triggered by JavaScript form submissions never count as quick redirects.
1933    m_quickRedirectComing = (lockBackForwardList || history()->currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
1934}
1935
1936bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
1937{
1938    // This function implements the rule: "Don't reload if navigating by fragment within
1939    // the same URL, but do reload if going to a new URL or to the same URL with no
1940    // fragment identifier at all."
1941    if (!destinationURL.hasFragmentIdentifier())
1942        return true;
1943    return !equalIgnoringFragmentIdentifier(currentURL, destinationURL);
1944}
1945
1946void FrameLoader::closeOldDataSources()
1947{
1948    // FIXME: Is it important for this traversal to be postorder instead of preorder?
1949    // If so, add helpers for postorder traversal, and use them. If not, then lets not
1950    // use a recursive algorithm here.
1951    for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1952        child->loader()->closeOldDataSources();
1953
1954    if (m_documentLoader)
1955        m_client->dispatchWillClose();
1956
1957    m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
1958}
1959
1960void FrameLoader::prepareForCachedPageRestore()
1961{
1962    ASSERT(!m_frame->tree()->parent());
1963    ASSERT(m_frame->page());
1964    ASSERT(m_frame->page()->mainFrame() == m_frame);
1965
1966    m_frame->navigationScheduler()->cancel();
1967
1968    // We still have to close the previous part page.
1969    closeURL();
1970
1971    // Delete old status bar messages (if it _was_ activated on last URL).
1972    if (m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)) {
1973        DOMWindow* window = m_frame->document()->domWindow();
1974        window->setStatus(String());
1975        window->setDefaultStatus(String());
1976    }
1977}
1978
1979void FrameLoader::open(CachedFrameBase& cachedFrame)
1980{
1981    m_isComplete = false;
1982
1983    // Don't re-emit the load event.
1984    m_didCallImplicitClose = true;
1985
1986    KURL url = cachedFrame.url();
1987
1988    // FIXME: I suspect this block of code doesn't do anything.
1989    if (url.protocolIsInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty())
1990        url.setPath("/");
1991
1992    started();
1993    Document* document = cachedFrame.document();
1994    ASSERT(document);
1995    ASSERT(document->domWindow());
1996
1997    clear(document, true, true, cachedFrame.isMainFrame());
1998
1999    document->setInPageCache(false);
2000
2001    m_needsClear = true;
2002    m_isComplete = false;
2003    m_didCallImplicitClose = false;
2004    m_outgoingReferrer = url.string();
2005
2006    FrameView* view = cachedFrame.view();
2007
2008    // When navigating to a CachedFrame its FrameView should never be null.  If it is we'll crash in creative ways downstream.
2009    ASSERT(view);
2010    view->setWasScrolledByUser(false);
2011
2012    // Use the current ScrollView's frame rect.
2013    if (m_frame->view())
2014        view->setFrameRect(m_frame->view()->frameRect());
2015    m_frame->setView(view);
2016
2017    m_frame->setDocument(document);
2018    document->domWindow()->resumeFromPageCache();
2019
2020    updateFirstPartyForCookies();
2021
2022    cachedFrame.restore();
2023}
2024
2025bool FrameLoader::isHostedByObjectElement() const
2026{
2027    HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2028    return owner && owner->hasTagName(objectTag);
2029}
2030
2031bool FrameLoader::isLoadingMainFrame() const
2032{
2033    Page* page = m_frame->page();
2034    return page && m_frame == page->mainFrame();
2035}
2036
2037bool FrameLoader::isReplacing() const
2038{
2039    return m_loadType == FrameLoadTypeReplace;
2040}
2041
2042void FrameLoader::setReplacing()
2043{
2044    m_loadType = FrameLoadTypeReplace;
2045}
2046
2047bool FrameLoader::subframeIsLoading() const
2048{
2049    // It's most likely that the last added frame is the last to load so we walk backwards.
2050    for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
2051        FrameLoader* childLoader = child->loader();
2052        DocumentLoader* documentLoader = childLoader->documentLoader();
2053        if (documentLoader && documentLoader->isLoadingInAPISense())
2054            return true;
2055        documentLoader = childLoader->provisionalDocumentLoader();
2056        if (documentLoader && documentLoader->isLoadingInAPISense())
2057            return true;
2058        documentLoader = childLoader->policyDocumentLoader();
2059        if (documentLoader)
2060            return true;
2061    }
2062    return false;
2063}
2064
2065void FrameLoader::willChangeTitle(DocumentLoader* loader)
2066{
2067    m_client->willChangeTitle(loader);
2068}
2069
2070FrameLoadType FrameLoader::loadType() const
2071{
2072    return m_loadType;
2073}
2074
2075CachePolicy FrameLoader::subresourceCachePolicy() const
2076{
2077    if (m_isComplete)
2078        return CachePolicyVerify;
2079
2080    if (m_loadType == FrameLoadTypeReloadFromOrigin)
2081        return CachePolicyReload;
2082
2083    if (Frame* parentFrame = m_frame->tree()->parent()) {
2084        CachePolicy parentCachePolicy = parentFrame->loader()->subresourceCachePolicy();
2085        if (parentCachePolicy != CachePolicyVerify)
2086            return parentCachePolicy;
2087    }
2088
2089    if (m_loadType == FrameLoadTypeReload)
2090        return CachePolicyRevalidate;
2091
2092    const ResourceRequest& request(documentLoader()->request());
2093#if PLATFORM(MAC)
2094    if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post") && ResourceRequest::useQuickLookResourceCachingQuirks())
2095        return CachePolicyRevalidate;
2096#endif
2097
2098    if (request.cachePolicy() == ReturnCacheDataElseLoad)
2099        return CachePolicyHistoryBuffer;
2100
2101    return CachePolicyVerify;
2102}
2103
2104void FrameLoader::checkLoadCompleteForThisFrame()
2105{
2106    ASSERT(m_client->hasWebView());
2107
2108    Settings* settings = m_frame->settings();
2109
2110    switch (m_state) {
2111        case FrameStateProvisional: {
2112            if (m_delegateIsHandlingProvisionalLoadError)
2113                return;
2114
2115            RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2116            if (!pdl)
2117                return;
2118
2119            // If we've received any errors we may be stuck in the provisional state and actually complete.
2120            const ResourceError& error = pdl->mainDocumentError();
2121            if (error.isNull())
2122                return;
2123
2124            // Check all children first.
2125            RefPtr<HistoryItem> item;
2126            if (Page* page = m_frame->page())
2127                if (isBackForwardLoadType(loadType()))
2128                    // Reset the back forward list to the last committed history item at the top level.
2129                    item = page->mainFrame()->loader()->history()->currentItem();
2130
2131            // Only reset if we aren't already going to a new provisional item.
2132            bool shouldReset = !history()->provisionalItem();
2133            if (!pdl->isLoadingInAPISense() || pdl->isStopping()) {
2134                m_delegateIsHandlingProvisionalLoadError = true;
2135                m_client->dispatchDidFailProvisionalLoad(error);
2136                m_delegateIsHandlingProvisionalLoadError = false;
2137
2138                ASSERT(!pdl->isLoading());
2139
2140                // If we're in the middle of loading multipart data, we need to restore the document loader.
2141                if (isReplacing() && !m_documentLoader.get())
2142                    setDocumentLoader(m_provisionalDocumentLoader.get());
2143
2144                // Finish resetting the load state, but only if another load hasn't been started by the
2145                // delegate callback.
2146                if (pdl == m_provisionalDocumentLoader)
2147                    clearProvisionalLoad();
2148                else if (activeDocumentLoader()) {
2149                    KURL unreachableURL = activeDocumentLoader()->unreachableURL();
2150                    if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2151                        shouldReset = false;
2152                }
2153            }
2154            if (shouldReset && item)
2155                if (Page* page = m_frame->page()) {
2156                    page->backForward()->setCurrentItem(item.get());
2157                    m_frame->loader()->client()->updateGlobalHistoryItemForPage();
2158                }
2159            return;
2160        }
2161
2162        case FrameStateCommittedPage: {
2163            DocumentLoader* dl = m_documentLoader.get();
2164            if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
2165                return;
2166
2167            setState(FrameStateComplete);
2168
2169            // FIXME: Is this subsequent work important if we already navigated away?
2170            // Maybe there are bugs because of that, or extra work we can skip because
2171            // the new page is ready.
2172
2173            m_client->forceLayoutForNonHTML();
2174
2175            // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2176            if (m_frame->page()) {
2177                if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin)
2178                    history()->restoreScrollPositionAndViewState();
2179            }
2180
2181            if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
2182                return;
2183
2184            if (!settings->needsDidFinishLoadOrderQuirk()) {
2185                m_progressTracker->progressCompleted();
2186                if (Page* page = m_frame->page()) {
2187                    if (m_frame == page->mainFrame())
2188                        page->resetRelevantPaintedObjectCounter();
2189                }
2190            }
2191
2192            const ResourceError& error = dl->mainDocumentError();
2193
2194            AXObjectCache::AXLoadingEvent loadingEvent;
2195            if (!error.isNull()) {
2196                m_client->dispatchDidFailLoad(error);
2197                loadingEvent = AXObjectCache::AXLoadingFailed;
2198            } else {
2199                m_client->dispatchDidFinishLoad();
2200                loadingEvent = AXObjectCache::AXLoadingFinished;
2201            }
2202
2203            if (settings->needsDidFinishLoadOrderQuirk()) {
2204                m_progressTracker->progressCompleted();
2205                if (Page* page = m_frame->page()) {
2206                    if (m_frame == page->mainFrame())
2207                        page->resetRelevantPaintedObjectCounter();
2208                }
2209            }
2210
2211            // Notify accessibility.
2212            if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
2213                cache->frameLoadingEventNotification(m_frame, loadingEvent);
2214
2215            return;
2216        }
2217
2218        case FrameStateComplete:
2219            m_loadType = FrameLoadTypeStandard;
2220            frameLoadCompleted();
2221            return;
2222    }
2223
2224    ASSERT_NOT_REACHED();
2225}
2226
2227void FrameLoader::continueLoadAfterWillSubmitForm()
2228{
2229    if (!m_provisionalDocumentLoader)
2230        return;
2231
2232    prepareForLoadStart();
2233
2234    // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
2235    // so we need to null check it again.
2236    if (!m_provisionalDocumentLoader)
2237        return;
2238
2239    DocumentLoader* activeDocLoader = activeDocumentLoader();
2240    if (activeDocLoader && activeDocLoader->isLoadingMainResource())
2241        return;
2242
2243    m_loadingFromCachedPage = false;
2244    m_provisionalDocumentLoader->startLoadingMainResource();
2245}
2246
2247static KURL originatingURLFromBackForwardList(Page* page)
2248{
2249    // FIXME: Can this logic be replaced with m_frame->document()->firstPartyForCookies()?
2250    // It has the same meaning of "page a user thinks is the current one".
2251
2252    KURL originalURL;
2253    int backCount = page->backForward()->backCount();
2254    for (int backIndex = 0; backIndex <= backCount; backIndex++) {
2255        // FIXME: At one point we had code here to check a "was user gesture" flag.
2256        // Do we need to restore that logic?
2257        HistoryItem* historyItem = page->backForward()->itemAtIndex(-backIndex);
2258        if (!historyItem)
2259            continue;
2260
2261        originalURL = historyItem->originalURL();
2262        if (!originalURL.isNull())
2263            return originalURL;
2264    }
2265
2266    return KURL();
2267}
2268
2269void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request)
2270{
2271    KURL originalURL;
2272
2273    // If there is no referrer, assume that the download was initiated directly, so current document is
2274    // completely unrelated to it. See <rdar://problem/5294691>.
2275    // FIXME: Referrer is not sent in many other cases, so we will often miss this important information.
2276    // Find a better way to decide whether the download was unrelated to current document.
2277    if (!request.httpReferrer().isNull()) {
2278        // find the first item in the history that was originated by the user
2279        originalURL = originatingURLFromBackForwardList(m_frame->page());
2280    }
2281
2282    if (originalURL.isNull())
2283        originalURL = request.url();
2284
2285    if (!originalURL.protocol().isEmpty() && !originalURL.host().isEmpty()) {
2286        unsigned port = originalURL.port();
2287
2288        // Original URL is needed to show the user where a file was downloaded from. We should make a URL that won't result in downloading the file again.
2289        // FIXME: Using host-only URL is a very heavy-handed approach. We should attempt to provide the actual page where the download was initiated from, as a reminder to the user.
2290        String hostOnlyURLString;
2291        if (port)
2292            hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ":", String::number(port));
2293        else
2294            hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host());
2295
2296        // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies.
2297        request.setFirstPartyForCookies(KURL(KURL(), hostOnlyURLString));
2298    }
2299}
2300
2301void FrameLoader::didLayout(LayoutMilestones milestones)
2302{
2303    m_client->dispatchDidLayout(milestones);
2304}
2305
2306void FrameLoader::didFirstLayout()
2307{
2308    if (m_frame->page() && isBackForwardLoadType(m_loadType))
2309        history()->restoreScrollPositionAndViewState();
2310
2311    if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2312        m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2313}
2314
2315void FrameLoader::frameLoadCompleted()
2316{
2317    // Note: Can be called multiple times.
2318
2319    m_client->frameLoadCompleted();
2320
2321    history()->updateForFrameLoadCompleted();
2322
2323    // After a canceled provisional load, firstLayoutDone is false.
2324    // Reset it to true if we're displaying a page.
2325    if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2326        m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2327}
2328
2329void FrameLoader::detachChildren()
2330{
2331    typedef Vector<RefPtr<Frame> > FrameVector;
2332    FrameVector childrenToDetach;
2333    childrenToDetach.reserveCapacity(m_frame->tree()->childCount());
2334    for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling())
2335        childrenToDetach.append(child);
2336    FrameVector::iterator end = childrenToDetach.end();
2337    for (FrameVector::iterator it = childrenToDetach.begin(); it != end; ++it)
2338        (*it)->loader()->detachFromParent();
2339}
2340
2341void FrameLoader::closeAndRemoveChild(Frame* child)
2342{
2343    child->tree()->detachFromParent();
2344
2345    child->setView(0);
2346    if (child->ownerElement() && child->page())
2347        child->page()->decrementSubframeCount();
2348    child->willDetachPage();
2349    child->detachFromPage();
2350
2351    m_frame->tree()->removeChild(child);
2352}
2353
2354// Called every time a resource is completely loaded or an error is received.
2355void FrameLoader::checkLoadComplete()
2356{
2357    ASSERT(m_client->hasWebView());
2358
2359    m_shouldCallCheckLoadComplete = false;
2360
2361    // FIXME: Always traversing the entire frame tree is a bit inefficient, but
2362    // is currently needed in order to null out the previous history item for all frames.
2363    if (Page* page = m_frame->page()) {
2364        Vector<RefPtr<Frame>, 10> frames;
2365        for (RefPtr<Frame> frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
2366            frames.append(frame);
2367        // To process children before their parents, iterate the vector backwards.
2368        for (size_t i = frames.size(); i; --i)
2369            frames[i - 1]->loader()->checkLoadCompleteForThisFrame();
2370    }
2371}
2372
2373int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
2374{
2375    if (!recurse)
2376        return m_frame->document()->cachedResourceLoader()->requestCount();
2377
2378    int count = 0;
2379    for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
2380        count += frame->document()->cachedResourceLoader()->requestCount();
2381    return count;
2382}
2383
2384String FrameLoader::userAgent(const KURL& url) const
2385{
2386    String userAgent = m_client->userAgent(url);
2387    InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent);
2388    return userAgent;
2389}
2390
2391void FrameLoader::handledOnloadEvents()
2392{
2393    m_client->dispatchDidHandleOnloadEvents();
2394
2395    if (documentLoader())
2396        documentLoader()->handledOnloadEvents();
2397}
2398
2399void FrameLoader::frameDetached()
2400{
2401    stopAllLoaders();
2402    m_frame->document()->stopActiveDOMObjects();
2403    detachFromParent();
2404}
2405
2406void FrameLoader::detachFromParent()
2407{
2408    RefPtr<Frame> protect(m_frame);
2409
2410    closeURL();
2411    history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
2412    detachChildren();
2413    // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
2414    // will trigger the unload event handlers of any child frames, and those event
2415    // handlers might start a new subresource load in this frame.
2416    stopAllLoaders();
2417
2418    InspectorInstrumentation::frameDetachedFromParent(m_frame);
2419
2420    detachViewsAndDocumentLoader();
2421
2422    m_progressTracker.clear();
2423
2424    if (Frame* parent = m_frame->tree()->parent()) {
2425        parent->loader()->closeAndRemoveChild(m_frame);
2426        parent->loader()->scheduleCheckCompleted();
2427    } else {
2428        m_frame->setView(0);
2429        m_frame->willDetachPage();
2430        m_frame->detachFromPage();
2431    }
2432}
2433
2434void FrameLoader::detachViewsAndDocumentLoader()
2435{
2436    m_client->detachedFromParent2();
2437    setDocumentLoader(0);
2438    m_client->detachedFromParent3();
2439}
2440
2441void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
2442{
2443    addExtraFieldsToRequest(request, m_loadType, false);
2444}
2445
2446void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
2447{
2448    // FIXME: Using m_loadType seems wrong for some callers.
2449    // If we are only preparing to load the main resource, that is previous load's load type!
2450    addExtraFieldsToRequest(request, m_loadType, true);
2451}
2452
2453void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource)
2454{
2455    // Don't set the cookie policy URL if it's already been set.
2456    // But make sure to set it on all requests regardless of protocol, as it has significance beyond the cookie policy (<rdar://problem/6616664>).
2457    if (request.firstPartyForCookies().isEmpty()) {
2458        if (mainResource && isLoadingMainFrame())
2459            request.setFirstPartyForCookies(request.url());
2460        else if (Document* document = m_frame->document())
2461            request.setFirstPartyForCookies(document->firstPartyForCookies());
2462    }
2463
2464    // The remaining modifications are only necessary for HTTP and HTTPS.
2465    if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
2466        return;
2467
2468    applyUserAgent(request);
2469
2470    if (!mainResource) {
2471        if (request.isConditional())
2472            request.setCachePolicy(ReloadIgnoringCacheData);
2473        else if (documentLoader()->isLoadingInAPISense()) {
2474            // If we inherit cache policy from a main resource, we use the DocumentLoader's
2475            // original request cache policy for two reasons:
2476            // 1. For POST requests, we mutate the cache policy for the main resource,
2477            //    but we do not want this to apply to subresources
2478            // 2. Delegates that modify the cache policy using willSendRequest: should
2479            //    not affect any other resources. Such changes need to be done
2480            //    per request.
2481            ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy();
2482            // Back-forward navigations try to load main resource from cache only to avoid re-submitting form data, and start over (with a warning dialog) if that fails.
2483            // This policy is set on initial request too, but should not be inherited.
2484            ResourceRequestCachePolicy subresourceCachePolicy = (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
2485            request.setCachePolicy(subresourceCachePolicy);
2486        } else
2487            request.setCachePolicy(UseProtocolCachePolicy);
2488
2489    // FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading.
2490    // It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest().
2491    } else if (loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadFromOrigin || request.isConditional())
2492        request.setCachePolicy(ReloadIgnoringCacheData);
2493
2494    if (request.cachePolicy() == ReloadIgnoringCacheData) {
2495        if (loadType == FrameLoadTypeReload)
2496            request.setHTTPHeaderField("Cache-Control", "max-age=0");
2497        else if (loadType == FrameLoadTypeReloadFromOrigin) {
2498            request.setHTTPHeaderField("Cache-Control", "no-cache");
2499            request.setHTTPHeaderField("Pragma", "no-cache");
2500        }
2501    }
2502
2503    if (mainResource)
2504        request.setHTTPAccept(defaultAcceptHeader);
2505
2506    // Make sure we send the Origin header.
2507    addHTTPOriginIfNeeded(request, String());
2508
2509    // Only set fallback array if it's still empty (later attempts may be incorrect, see bug 117818).
2510    if (request.responseContentDispositionEncodingFallbackArray().isEmpty()) {
2511        // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
2512        Settings* settings = m_frame->settings();
2513        request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_frame->document()->encoding(), settings ? settings->defaultTextEncodingName() : String());
2514    }
2515}
2516
2517void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String& origin)
2518{
2519    if (!request.httpOrigin().isEmpty())
2520        return;  // Request already has an Origin header.
2521
2522    // Don't send an Origin header for GET or HEAD to avoid privacy issues.
2523    // For example, if an intranet page has a hyperlink to an external web
2524    // site, we don't want to include the Origin of the request because it
2525    // will leak the internal host name. Similar privacy concerns have lead
2526    // to the widespread suppression of the Referer header at the network
2527    // layer.
2528    if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
2529        return;
2530
2531    // For non-GET and non-HEAD methods, always send an Origin header so the
2532    // server knows we support this feature.
2533
2534    if (origin.isEmpty()) {
2535        // If we don't know what origin header to attach, we attach the value
2536        // for an empty origin.
2537        request.setHTTPOrigin(SecurityOrigin::createUnique()->toString());
2538        return;
2539    }
2540
2541    request.setHTTPOrigin(origin);
2542}
2543
2544void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
2545{
2546    RefPtr<FormState> formState = prpFormState;
2547
2548    // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
2549    // bunch of parameters that would come in here and then be built back up to a ResourceRequest.  In case
2550    // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
2551    // from scratch as it did all along.
2552    const KURL& url = inRequest.url();
2553    RefPtr<FormData> formData = inRequest.httpBody();
2554    const String& contentType = inRequest.httpContentType();
2555    String origin = inRequest.httpOrigin();
2556
2557    ResourceRequest workingResourceRequest(url);
2558
2559    if (!referrer.isEmpty())
2560        workingResourceRequest.setHTTPReferrer(referrer);
2561    workingResourceRequest.setHTTPOrigin(origin);
2562    workingResourceRequest.setHTTPMethod("POST");
2563    workingResourceRequest.setHTTPBody(formData);
2564    workingResourceRequest.setHTTPContentType(contentType);
2565    addExtraFieldsToRequest(workingResourceRequest, loadType, true);
2566
2567    NavigationAction action(workingResourceRequest, loadType, true, event);
2568
2569    if (!frameName.isEmpty()) {
2570        // The search for a target frame is done earlier in the case of form submission.
2571        if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName))
2572            targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
2573        else
2574            policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy, workingResourceRequest, formState.release(), frameName, this);
2575    } else {
2576        // must grab this now, since this load may stop the previous load and clear this flag
2577        bool isRedirect = m_quickRedirectComing;
2578        loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
2579        if (isRedirect) {
2580            m_quickRedirectComing = false;
2581            if (m_provisionalDocumentLoader)
2582                m_provisionalDocumentLoader->setIsClientRedirect(true);
2583        }
2584    }
2585}
2586
2587unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
2588{
2589    ASSERT(m_frame->document());
2590    String referrer = SecurityPolicy::generateReferrerHeader(m_frame->document()->referrerPolicy(), request.url(), outgoingReferrer());
2591
2592    ResourceRequest initialRequest = request;
2593    initialRequest.setTimeoutInterval(10);
2594
2595    if (!referrer.isEmpty())
2596        initialRequest.setHTTPReferrer(referrer);
2597    addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
2598
2599    if (Page* page = m_frame->page())
2600        initialRequest.setFirstPartyForCookies(page->mainFrame()->loader()->documentLoader()->request().url());
2601
2602    addExtraFieldsToSubresourceRequest(initialRequest);
2603
2604    unsigned long identifier = 0;
2605    ResourceRequest newRequest(initialRequest);
2606    requestFromDelegate(newRequest, identifier, error);
2607
2608    if (error.isNull()) {
2609        ASSERT(!newRequest.isNull());
2610
2611        if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
2612            platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, data);
2613            documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
2614        }
2615    }
2616    notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data.data(), data.size(), -1, error);
2617    return identifier;
2618}
2619
2620const ResourceRequest& FrameLoader::originalRequest() const
2621{
2622    return activeDocumentLoader()->originalRequestCopy();
2623}
2624
2625void FrameLoader::receivedMainResourceError(const ResourceError& error)
2626{
2627    // Retain because the stop may release the last reference to it.
2628    RefPtr<Frame> protect(m_frame);
2629
2630    RefPtr<DocumentLoader> loader = activeDocumentLoader();
2631    // FIXME: Don't want to do this if an entirely new load is going, so should check
2632    // that both data sources on the frame are either this or nil.
2633    stop();
2634    if (m_client->shouldFallBack(error))
2635        handleFallbackContent();
2636
2637    if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
2638        if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url())
2639            m_submittedFormURL = KURL();
2640
2641        // We might have made a page cache item, but now we're bailing out due to an error before we ever
2642        // transitioned to the new page (before WebFrameState == commit).  The goal here is to restore any state
2643        // so that the existing view (that wenever got far enough to replace) can continue being used.
2644        history()->invalidateCurrentItemCachedPage();
2645
2646        // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
2647        // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2648        // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
2649        // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
2650        // has ended.
2651        if (m_sentRedirectNotification)
2652            clientRedirectCancelledOrFinished(false);
2653    }
2654
2655    checkCompleted();
2656    if (m_frame->page())
2657        checkLoadComplete();
2658}
2659
2660void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
2661    const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
2662{
2663    FrameLoader* loader = static_cast<FrameLoader*>(argument);
2664    loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
2665}
2666
2667void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
2668{
2669    m_quickRedirectComing = false;
2670
2671    if (!shouldContinue)
2672        return;
2673
2674    // If we have a provisional request for a different document, a fragment scroll should cancel it.
2675    if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) {
2676        m_provisionalDocumentLoader->stopLoading();
2677        setProvisionalDocumentLoader(0);
2678    }
2679
2680    bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList;
2681    loadInSameDocument(request.url(), 0, !isRedirect);
2682}
2683
2684bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url)
2685{
2686    // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
2687    // currently displaying a frameset, or if the URL does not have a fragment.
2688    // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
2689
2690    // FIXME: What about load types other than Standard and Reload?
2691
2692    return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
2693        && loadType != FrameLoadTypeReload
2694        && loadType != FrameLoadTypeReloadFromOrigin
2695        && loadType != FrameLoadTypeSame
2696        && !shouldReload(m_frame->document()->url(), url)
2697        // We don't want to just scroll if a link from within a
2698        // frameset is trying to reload the frameset into _top.
2699        && !m_frame->document()->isFrameSet();
2700}
2701
2702void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
2703{
2704    FrameView* view = m_frame->view();
2705    if (!view)
2706        return;
2707
2708    // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
2709    RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0);
2710
2711    if (boundaryFrame)
2712        boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
2713
2714    view->scrollToFragment(url);
2715
2716    if (boundaryFrame)
2717        boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
2718}
2719
2720void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
2721    const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
2722{
2723    FrameLoader* loader = static_cast<FrameLoader*>(argument);
2724    loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
2725}
2726
2727bool FrameLoader::shouldClose()
2728{
2729    Page* page = m_frame->page();
2730    if (!page)
2731        return true;
2732    if (!page->chrome().canRunBeforeUnloadConfirmPanel())
2733        return true;
2734
2735    // Store all references to each subframe in advance since beforeunload's event handler may modify frame
2736    Vector<RefPtr<Frame> > targetFrames;
2737    targetFrames.append(m_frame);
2738    for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->traverseNext(m_frame))
2739        targetFrames.append(child);
2740
2741    bool shouldClose = false;
2742    {
2743        NavigationDisablerForBeforeUnload navigationDisabler;
2744        size_t i;
2745
2746        for (i = 0; i < targetFrames.size(); i++) {
2747            if (!targetFrames[i]->tree()->isDescendantOf(m_frame))
2748                continue;
2749            if (!targetFrames[i]->loader()->handleBeforeUnloadEvent(page->chrome(), this))
2750                break;
2751        }
2752
2753        if (i == targetFrames.size())
2754            shouldClose = true;
2755    }
2756
2757    if (!shouldClose)
2758        m_submittedFormURL = KURL();
2759
2760    m_currentNavigationHasShownBeforeUnloadConfirmPanel = false;
2761    return shouldClose;
2762}
2763
2764bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated)
2765{
2766    DOMWindow* domWindow = m_frame->document()->domWindow();
2767    if (!domWindow)
2768        return true;
2769
2770    RefPtr<Document> document = m_frame->document();
2771    if (!document->body())
2772        return true;
2773
2774    RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
2775    m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal;
2776
2777    // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent.
2778    Page* page = m_frame->page();
2779    page->incrementFrameHandlingBeforeUnloadEventCount();
2780    domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
2781    page->decrementFrameHandlingBeforeUnloadEventCount();
2782
2783    m_pageDismissalEventBeingDispatched = NoDismissal;
2784
2785    if (!beforeUnloadEvent->defaultPrevented())
2786        document->defaultEventHandler(beforeUnloadEvent.get());
2787    if (beforeUnloadEvent->result().isNull())
2788        return true;
2789
2790    // If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt,
2791    // this frame is not allowed to cause another one to be shown.
2792    if (frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel) {
2793        document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation.");
2794        return true;
2795    }
2796
2797    // We should only display the beforeunload dialog for an iframe if its SecurityOrigin matches all
2798    // ancestor frame SecurityOrigins up through the navigating FrameLoader.
2799    if (frameLoaderBeingNavigated != this) {
2800        Frame* parentFrame = m_frame->tree()->parent();
2801        while (parentFrame) {
2802            Document* parentDocument = parentFrame->document();
2803            if (!parentDocument)
2804                return true;
2805            if (!m_frame->document() || !m_frame->document()->securityOrigin()->canAccess(parentDocument->securityOrigin())) {
2806                document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match.");
2807                return true;
2808            }
2809
2810            if (parentFrame->loader() == frameLoaderBeingNavigated)
2811                break;
2812
2813            parentFrame = parentFrame->tree()->parent();
2814        }
2815
2816        // The navigatingFrameLoader should always be in our ancestory.
2817        ASSERT(parentFrame);
2818        ASSERT(parentFrame->loader() == frameLoaderBeingNavigated);
2819    }
2820
2821    frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel = true;
2822
2823    String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->result());
2824    return chrome.runBeforeUnloadConfirmPanel(text, m_frame);
2825}
2826
2827void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
2828{
2829    // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2830    // nil policyDataSource because loading the alternate page will have passed
2831    // through this method already, nested; otherwise, policyDataSource should still be set.
2832    ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
2833
2834    bool isTargetItem = history()->provisionalItem() ? history()->provisionalItem()->isTargetItem() : false;
2835
2836    // Two reasons we can't continue:
2837    //    1) Navigation policy delegate said we can't so request is nil. A primary case of this
2838    //       is the user responding Cancel to the form repost nag sheet.
2839    //    2) User responded Cancel to an alert popped up by the before unload event handler.
2840    bool canContinue = shouldContinue && shouldClose();
2841
2842    if (!canContinue) {
2843        // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
2844        // need to report that the client redirect was cancelled.
2845        if (m_quickRedirectComing)
2846            clientRedirectCancelledOrFinished(false);
2847
2848        setPolicyDocumentLoader(0);
2849
2850        // If the navigation request came from the back/forward menu, and we punt on it, we have the
2851        // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity,
2852        // we only do this when punting a navigation for the target frame or top-level frame.
2853        if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(policyChecker()->loadType())) {
2854            if (Page* page = m_frame->page()) {
2855                Frame* mainFrame = page->mainFrame();
2856                if (HistoryItem* resetItem = mainFrame->loader()->history()->currentItem()) {
2857                    page->backForward()->setCurrentItem(resetItem);
2858                    m_frame->loader()->client()->updateGlobalHistoryItemForPage();
2859                }
2860            }
2861        }
2862        return;
2863    }
2864
2865    FrameLoadType type = policyChecker()->loadType();
2866    // A new navigation is in progress, so don't clear the history's provisional item.
2867    stopAllLoaders(ShouldNotClearProvisionalItem);
2868
2869    // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
2870    // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
2871    if (!m_frame->page())
2872        return;
2873
2874#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
2875    if (Page* page = m_frame->page()) {
2876        if (page->mainFrame() == m_frame)
2877            m_frame->page()->inspectorController()->resume();
2878    }
2879#endif
2880
2881    setProvisionalDocumentLoader(m_policyDocumentLoader.get());
2882    m_loadType = type;
2883    setState(FrameStateProvisional);
2884
2885    setPolicyDocumentLoader(0);
2886
2887    if (isBackForwardLoadType(type) && history()->provisionalItem()->isInPageCache()) {
2888        loadProvisionalItemFromCachedPage();
2889        return;
2890    }
2891
2892    if (formState)
2893        m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState);
2894    else
2895        continueLoadAfterWillSubmitForm();
2896}
2897
2898void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
2899    const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue)
2900{
2901    FrameLoader* loader = static_cast<FrameLoader*>(argument);
2902    loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue);
2903}
2904
2905void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
2906    PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue)
2907{
2908    if (!shouldContinue)
2909        return;
2910
2911    RefPtr<Frame> frame = m_frame;
2912    RefPtr<Frame> mainFrame = m_client->dispatchCreatePage(action);
2913    if (!mainFrame)
2914        return;
2915
2916    if (frameName != "_blank")
2917        mainFrame->tree()->setName(frameName);
2918
2919    mainFrame->page()->setOpenedByDOM();
2920    mainFrame->loader()->m_client->dispatchShow();
2921    if (!m_suppressOpenerInNewFrame) {
2922        mainFrame->loader()->setOpener(frame.get());
2923        mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy());
2924    }
2925    mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(request), false, FrameLoadTypeStandard, formState);
2926}
2927
2928void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
2929{
2930    ASSERT(!request.isNull());
2931
2932    identifier = 0;
2933    if (Page* page = m_frame->page()) {
2934        identifier = page->progress()->createUniqueIdentifier();
2935        notifier()->assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
2936    }
2937
2938    ResourceRequest newRequest(request);
2939    notifier()->dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
2940
2941    if (newRequest.isNull())
2942        error = cancelledError(request);
2943    else
2944        error = ResourceError();
2945
2946    request = newRequest;
2947}
2948
2949void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, ResourceRequest& newRequest)
2950{
2951    Page* page = m_frame->page();
2952    if (!page)
2953        return;
2954
2955    if (!resource->shouldSendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
2956        return;
2957
2958    // Main resource delegate messages are synthesized in MainResourceLoader, so we must not send them here.
2959    if (resource->type() == CachedResource::MainResource)
2960        return;
2961
2962    if (!page->areMemoryCacheClientCallsEnabled()) {
2963        InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
2964        m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->resourceRequest());
2965        m_documentLoader->didTellClientAboutLoad(resource->url());
2966        return;
2967    }
2968
2969    if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), newRequest, resource->response(), resource->encodedSize())) {
2970        InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
2971        m_documentLoader->didTellClientAboutLoad(resource->url());
2972        return;
2973    }
2974
2975    unsigned long identifier;
2976    ResourceError error;
2977    requestFromDelegate(newRequest, identifier, error);
2978    InspectorInstrumentation::markResourceAsCached(page, identifier);
2979    notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error);
2980}
2981
2982void FrameLoader::applyUserAgent(ResourceRequest& request)
2983{
2984    String userAgent = this->userAgent(request.url());
2985    ASSERT(!userAgent.isNull());
2986    request.setHTTPUserAgent(userAgent);
2987}
2988
2989bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url, unsigned long requestIdentifier)
2990{
2991    FeatureObserver::observe(m_frame->document(), FeatureObserver::XFrameOptions);
2992
2993    Frame* topFrame = m_frame->tree()->top();
2994    if (m_frame == topFrame)
2995        return false;
2996
2997    XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
2998
2999    switch (disposition) {
3000    case XFrameOptionsSameOrigin: {
3001        FeatureObserver::observe(m_frame->document(), FeatureObserver::XFrameOptionsSameOrigin);
3002        RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
3003        if (!origin->isSameSchemeHostPort(topFrame->document()->securityOrigin()))
3004            return true;
3005        for (Frame* frame = m_frame->tree()->parent(); frame; frame = frame->tree()->parent()) {
3006            if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin())) {
3007                FeatureObserver::observe(m_frame->document(), FeatureObserver::XFrameOptionsSameOriginWithBadAncestorChain);
3008                break;
3009            }
3010        }
3011        return false;
3012    }
3013    case XFrameOptionsDeny:
3014        return true;
3015    case XFrameOptionsAllowAll:
3016        return false;
3017    case XFrameOptionsConflict:
3018        m_frame->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier);
3019        return true;
3020    case XFrameOptionsInvalid:
3021        m_frame->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier);
3022        return false;
3023    default:
3024        ASSERT_NOT_REACHED();
3025        return false;
3026    }
3027}
3028
3029void FrameLoader::loadProvisionalItemFromCachedPage()
3030{
3031    DocumentLoader* provisionalLoader = provisionalDocumentLoader();
3032    LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().stringCenterEllipsizedToLength().utf8().data());
3033
3034    prepareForLoadStart();
3035
3036    m_loadingFromCachedPage = true;
3037
3038    // Should have timing data from previous time(s) the page was shown.
3039    ASSERT(provisionalLoader->timing()->navigationStart());
3040    provisionalLoader->resetTiming();
3041    provisionalLoader->timing()->markNavigationStart();
3042
3043    provisionalLoader->setCommitted(true);
3044    commitProvisionalLoad();
3045}
3046
3047bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
3048{
3049    if (!history()->currentItem())
3050        return false;
3051    return url == history()->currentItem()->url() || url == history()->currentItem()->originalURL();
3052}
3053
3054bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const
3055{
3056    if (!equalIgnoringCase(url.string(), "about:srcdoc"))
3057        return false;
3058    HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement();
3059    if (!ownerElement)
3060        return false;
3061    if (!ownerElement->hasTagName(iframeTag))
3062        return false;
3063    return ownerElement->fastHasAttribute(srcdocAttr);
3064}
3065
3066void FrameLoader::checkDidPerformFirstNavigation()
3067{
3068    Page* page = m_frame->page();
3069    if (!page)
3070        return;
3071
3072    if (!m_didPerformFirstNavigation && page->backForward()->currentItem() && !page->backForward()->backItem() && !page->backForward()->forwardItem()) {
3073        m_didPerformFirstNavigation = true;
3074        m_client->didPerformFirstNavigation();
3075    }
3076}
3077
3078Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
3079{
3080    Frame* frame = m_frame->tree()->find(name);
3081
3082    // From http://www.whatwg.org/specs/web-apps/current-work/#seamlessLinks:
3083    //
3084    // If the source browsing context is the same as the browsing context
3085    // being navigated, and this browsing context has its seamless browsing
3086    // context flag set, and the browsing context being navigated was not
3087    // chosen using an explicit self-navigation override, then find the
3088    // nearest ancestor browsing context that does not have its seamless
3089    // browsing context flag set, and continue these steps as if that
3090    // browsing context was the one that was going to be navigated instead.
3091    if (frame == m_frame && name != "_self" && m_frame->document()->shouldDisplaySeamlesslyWithParent()) {
3092        for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) {
3093            if (!ancestor->document()->shouldDisplaySeamlesslyWithParent()) {
3094                frame = ancestor;
3095                break;
3096            }
3097        }
3098        ASSERT(frame != m_frame);
3099    }
3100
3101    if (activeDocument) {
3102        if (!activeDocument->canNavigate(frame))
3103            return 0;
3104    } else {
3105        // FIXME: Eventually all callers should supply the actual activeDocument
3106        // so we can call canNavigate with the right document.
3107        if (!m_frame->document()->canNavigate(frame))
3108            return 0;
3109    }
3110
3111    return frame;
3112}
3113
3114void FrameLoader::loadSameDocumentItem(HistoryItem* item)
3115{
3116    ASSERT(item->documentSequenceNumber() == history()->currentItem()->documentSequenceNumber());
3117
3118    // Save user view state to the current history item here since we don't do a normal load.
3119    // FIXME: Does form state need to be saved here too?
3120    history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
3121    if (FrameView* view = m_frame->view())
3122        view->setWasScrolledByUser(false);
3123
3124    history()->setCurrentItem(item);
3125
3126    // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
3127    loadInSameDocument(item->url(), item->stateObject(), false);
3128
3129    // Restore user view state from the current history item here since we don't do a normal load.
3130    history()->restoreScrollPositionAndViewState();
3131}
3132
3133// FIXME: This function should really be split into a couple pieces, some of
3134// which should be methods of HistoryController and some of which should be
3135// methods of FrameLoader.
3136void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy)
3137{
3138    // Remember this item so we can traverse any child items as child frames load
3139    history()->setProvisionalItem(item);
3140
3141    if (CachedPage* cachedPage = pageCache()->get(item)) {
3142        loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
3143        return;
3144    }
3145
3146    KURL itemURL = item->url();
3147    KURL itemOriginalURL = item->originalURL();
3148    KURL currentURL;
3149    if (documentLoader())
3150        currentURL = documentLoader()->url();
3151    RefPtr<FormData> formData = item->formData();
3152
3153    ResourceRequest request(itemURL);
3154
3155    if (!item->referrer().isNull())
3156        request.setHTTPReferrer(item->referrer());
3157
3158    // If this was a repost that failed the page cache, we might try to repost the form.
3159    NavigationAction action;
3160    if (formData) {
3161        formData->generateFiles(m_frame->document());
3162
3163        request.setHTTPMethod("POST");
3164        request.setHTTPBody(formData);
3165        request.setHTTPContentType(item->formContentType());
3166        RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
3167        addHTTPOriginIfNeeded(request, securityOrigin->toString());
3168
3169        // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
3170        // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
3171        addExtraFieldsToRequest(request, loadType, true);
3172
3173        // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
3174        // We want to know this before talking to the policy delegate, since it affects whether
3175        // we show the DoYouReallyWantToRepost nag.
3176        //
3177        // This trick has a small bug (3123893) where we might find a cache hit, but then
3178        // have the item vanish when we try to use it in the ensuing nav.  This should be
3179        // extremely rare, but in that case the user will get an error on the navigation.
3180
3181        if (cacheLoadPolicy == MayAttemptCacheOnlyLoadForFormSubmissionItem) {
3182            request.setCachePolicy(ReturnCacheDataDontLoad);
3183            action = NavigationAction(request, loadType, false);
3184        } else {
3185            request.setCachePolicy(ReturnCacheDataElseLoad);
3186            action = NavigationAction(request, NavigationTypeFormResubmitted);
3187        }
3188    } else {
3189        switch (loadType) {
3190            case FrameLoadTypeReload:
3191            case FrameLoadTypeReloadFromOrigin:
3192                request.setCachePolicy(ReloadIgnoringCacheData);
3193                break;
3194            case FrameLoadTypeBack:
3195            case FrameLoadTypeForward:
3196            case FrameLoadTypeIndexedBackForward:
3197                // If the first load within a frame is a navigation within a back/forward list that was attached
3198                // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
3199                if (m_stateMachine.committedFirstRealDocumentLoad())
3200                    request.setCachePolicy(ReturnCacheDataElseLoad);
3201                break;
3202            case FrameLoadTypeStandard:
3203            case FrameLoadTypeRedirectWithLockedBackForwardList:
3204                break;
3205            case FrameLoadTypeSame:
3206            default:
3207                ASSERT_NOT_REACHED();
3208        }
3209
3210        addExtraFieldsToRequest(request, loadType, true);
3211
3212        ResourceRequest requestForOriginalURL(request);
3213        requestForOriginalURL.setURL(itemOriginalURL);
3214        action = NavigationAction(requestForOriginalURL, loadType, false);
3215    }
3216
3217    loadWithNavigationAction(request, action, false, loadType, 0);
3218}
3219
3220// Loads content into this frame, as specified by history item
3221void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
3222{
3223    m_requestedHistoryItem = item;
3224    HistoryItem* currentItem = history()->currentItem();
3225    bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem);
3226
3227    if (sameDocumentNavigation)
3228        loadSameDocumentItem(item);
3229    else
3230        loadDifferentDocumentItem(item, loadType, MayAttemptCacheOnlyLoadForFormSubmissionItem);
3231}
3232
3233void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad()
3234{
3235    ASSERT(m_state == FrameStateProvisional);
3236    ASSERT(!m_loadingFromCachedPage);
3237    // We only use cache-only loads to avoid resubmitting forms.
3238    ASSERT(isBackForwardLoadType(m_loadType));
3239    ASSERT(m_history->provisionalItem()->formData());
3240    ASSERT(m_history->provisionalItem() == m_requestedHistoryItem.get());
3241
3242    FrameLoadType loadType = m_loadType;
3243    HistoryItem* item = m_history->provisionalItem();
3244
3245    stopAllLoaders(ShouldNotClearProvisionalItem);
3246    loadDifferentDocumentItem(item, loadType, MayNotAttemptCacheOnlyLoadForFormSubmissionItem);
3247}
3248
3249ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
3250{
3251    ResourceError error = m_client->cancelledError(request);
3252    error.setIsCancellation(true);
3253    return error;
3254}
3255
3256void FrameLoader::setTitle(const StringWithDirection& title)
3257{
3258    documentLoader()->setTitle(title);
3259}
3260
3261String FrameLoader::referrer() const
3262{
3263    return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
3264}
3265
3266void FrameLoader::dispatchDocumentElementAvailable()
3267{
3268    m_frame->injectUserScripts(InjectAtDocumentStart);
3269    m_client->documentElementAvailable();
3270}
3271
3272void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
3273{
3274    if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript))
3275        return;
3276
3277    Vector<RefPtr<DOMWrapperWorld> > worlds;
3278    ScriptController::getAllWorlds(worlds);
3279    for (size_t i = 0; i < worlds.size(); ++i)
3280        dispatchDidClearWindowObjectInWorld(worlds[i].get());
3281}
3282
3283void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
3284{
3285    if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript) || !m_frame->script()->existingWindowShell(world))
3286        return;
3287
3288    m_client->dispatchDidClearWindowObjectInWorld(world);
3289
3290#if ENABLE(INSPECTOR)
3291    if (Page* page = m_frame->page())
3292        page->inspectorController()->didClearWindowObjectInWorld(m_frame, world);
3293#endif
3294
3295    InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world);
3296}
3297
3298void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds()
3299{
3300    Vector<RefPtr<DOMWrapperWorld> > worlds;
3301    ScriptController::getAllWorlds(worlds);
3302    for (size_t i = 0; i < worlds.size(); ++i)
3303        m_client->dispatchGlobalObjectAvailable(worlds[i].get());
3304}
3305
3306SandboxFlags FrameLoader::effectiveSandboxFlags() const
3307{
3308    SandboxFlags flags = m_forcedSandboxFlags;
3309    if (Frame* parentFrame = m_frame->tree()->parent())
3310        flags |= parentFrame->document()->sandboxFlags();
3311    if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement())
3312        flags |= ownerElement->sandboxFlags();
3313    return flags;
3314}
3315
3316void FrameLoader::didChangeTitle(DocumentLoader* loader)
3317{
3318    m_client->didChangeTitle(loader);
3319
3320    if (loader == m_documentLoader) {
3321        // Must update the entries in the back-forward list too.
3322        history()->setCurrentItemTitle(loader->title());
3323        // This must go through the WebFrame because it has the right notion of the current b/f item.
3324        m_client->setTitle(loader->title(), loader->urlForHistory());
3325        m_client->setMainFrameDocumentReady(true); // update observers with new DOMDocument
3326        m_client->dispatchDidReceiveTitle(loader->title());
3327    }
3328}
3329
3330void FrameLoader::didChangeIcons(IconType type)
3331{
3332    m_client->dispatchDidChangeIcons(type);
3333}
3334
3335void FrameLoader::dispatchDidCommitLoad()
3336{
3337    if (m_stateMachine.creatingInitialEmptyDocument())
3338        return;
3339
3340    m_client->dispatchDidCommitLoad();
3341
3342    if (isLoadingMainFrame()) {
3343        m_frame->page()->resetSeenPlugins();
3344        m_frame->page()->resetSeenMediaEngines();
3345    }
3346
3347    InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
3348
3349    if (m_frame->page()->mainFrame() == m_frame)
3350        m_frame->page()->featureObserver()->didCommitLoad();
3351
3352}
3353
3354void FrameLoader::tellClientAboutPastMemoryCacheLoads()
3355{
3356    ASSERT(m_frame->page());
3357    ASSERT(m_frame->page()->areMemoryCacheClientCallsEnabled());
3358
3359    if (!m_documentLoader)
3360        return;
3361
3362    Vector<ResourceRequest> pastLoads;
3363    m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
3364
3365    size_t size = pastLoads.size();
3366    for (size_t i = 0; i < size; ++i) {
3367        CachedResource* resource = memoryCache()->resourceForRequest(pastLoads[i]);
3368
3369        // FIXME: These loads, loaded from cache, but now gone from the cache by the time
3370        // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
3371        // Consider if there's some efficient way of remembering enough to deliver this client call.
3372        // We have the URL, but not the rest of the response or the length.
3373        if (!resource)
3374            continue;
3375
3376        ResourceRequest request(resource->url());
3377        m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
3378    }
3379}
3380
3381NetworkingContext* FrameLoader::networkingContext() const
3382{
3383    return m_networkingContext.get();
3384}
3385
3386void FrameLoader::loadProgressingStatusChanged()
3387{
3388    FrameView* view = m_frame->page()->mainFrame()->view();
3389    if (!view)
3390        return;
3391
3392    view->updateLayerFlushThrottlingInAllFrames();
3393    view->adjustTiledBackingCoverage();
3394}
3395
3396void FrameLoader::forcePageTransitionIfNeeded()
3397{
3398    m_client->forcePageTransitionIfNeeded();
3399}
3400
3401bool FrameLoaderClient::hasHTMLView() const
3402{
3403    return true;
3404}
3405
3406PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
3407{
3408    ASSERT(!features.dialog || request.frameName().isEmpty());
3409
3410    created = false;
3411
3412    if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
3413        if (RefPtr<Frame> frame = lookupFrame->loader()->findFrameForNavigation(request.frameName(), openerFrame->document())) {
3414            if (request.frameName() != "_self") {
3415                if (Page* page = frame->page())
3416                    page->chrome().focus();
3417            }
3418            return frame.release();
3419        }
3420    }
3421
3422    // Sandboxed frames cannot open new auxiliary browsing contexts.
3423    if (isDocumentSandboxed(openerFrame, SandboxPopups)) {
3424        // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
3425        openerFrame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.");
3426        return nullptr;
3427    }
3428
3429    // FIXME: Setting the referrer should be the caller's responsibility.
3430    FrameLoadRequest requestWithReferrer = request;
3431    String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader()->outgoingReferrer());
3432    if (!referrer.isEmpty())
3433        requestWithReferrer.resourceRequest().setHTTPReferrer(referrer);
3434    FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader()->outgoingOrigin());
3435
3436    if (openerFrame->settings() && !openerFrame->settings()->supportsMultipleWindows()) {
3437        created = false;
3438        return openerFrame;
3439    }
3440
3441    Page* oldPage = openerFrame->page();
3442    if (!oldPage)
3443        return nullptr;
3444
3445    Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest()));
3446    if (!page)
3447        return nullptr;
3448
3449    RefPtr<Frame> frame = page->mainFrame();
3450
3451    frame->loader()->forceSandboxFlags(openerFrame->document()->sandboxFlags());
3452
3453    if (request.frameName() != "_blank")
3454        frame->tree()->setName(request.frameName());
3455
3456    page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
3457
3458    if (!frame->page())
3459        return nullptr;
3460    page->chrome().setStatusbarVisible(features.statusBarVisible);
3461
3462    if (!frame->page())
3463        return nullptr;
3464    page->chrome().setScrollbarsVisible(features.scrollbarsVisible);
3465
3466    if (!frame->page())
3467        return nullptr;
3468    page->chrome().setMenubarVisible(features.menuBarVisible);
3469
3470    if (!frame->page())
3471        return nullptr;
3472    page->chrome().setResizable(features.resizable);
3473
3474    // 'x' and 'y' specify the location of the window, while 'width' and 'height'
3475    // specify the size of the viewport. We can only resize the window, so adjust
3476    // for the difference between the window size and the viewport size.
3477
3478    FloatRect windowRect = page->chrome().windowRect();
3479    FloatSize viewportSize = page->chrome().pageRect().size();
3480
3481    if (features.xSet)
3482        windowRect.setX(features.x);
3483    if (features.ySet)
3484        windowRect.setY(features.y);
3485    // Zero width and height mean using default size, not minumum one.
3486    if (features.widthSet && features.width)
3487        windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width()));
3488    if (features.heightSet && features.height)
3489        windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height()));
3490
3491    // Ensure non-NaN values, minimum size as well as being within valid screen area.
3492    FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect);
3493
3494    if (!frame->page())
3495        return nullptr;
3496    page->chrome().setWindowRect(newWindowRect);
3497
3498    if (!frame->page())
3499        return nullptr;
3500    page->chrome().show();
3501
3502    created = true;
3503    return frame;
3504}
3505
3506} // namespace WebCore
3507