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