| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. | |
| 3 * Copyright (C) 2007 Trolltech ASA | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions | |
| 7 * are met: | |
| 8 * | |
| 9 * 1. Redistributions of source code must retain the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer. | |
| 11 * 2. Redistributions in binary form must reproduce the above copyright | |
| 12 * notice, this list of conditions and the following disclaimer in the | |
| 13 * documentation and/or other materials provided with the distribution. | |
| 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
| 15 * its contributors may be used to endorse or promote products derived | |
| 16 * from this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
| 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
| 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 28 */ | |
| 29 | |
| 30 #include "config.h" | |
| 31 #include "FrameLoader.h" | |
| 32 | |
| 33 #include "Archive.h" | |
| 34 #include "ArchiveFactory.h" | |
| 35 #include "CString.h" | |
| 36 #include "Cache.h" | |
| 37 #include "CachedPage.h" | |
| 38 #include "Chrome.h" | |
| 39 #include "DOMImplementation.h" | |
| 40 #include "DOMWindow.h" | |
| 41 #include "DocLoader.h" | |
| 42 #include "Document.h" | |
| 43 #include "DocumentLoader.h" | |
| 44 #include "Editor.h" | |
| 45 #include "EditorClient.h" | |
| 46 #include "Element.h" | |
| 47 #include "Event.h" | |
| 48 #include "EventNames.h" | |
| 49 #include "FloatRect.h" | |
| 50 #include "FormState.h" | |
| 51 #include "Frame.h" | |
| 52 #include "FrameLoadRequest.h" | |
| 53 #include "FrameLoaderClient.h" | |
| 54 #include "FramePrivate.h" | |
| 55 #include "FrameTree.h" | |
| 56 #include "FrameView.h" | |
| 57 #include "HTMLFormElement.h" | |
| 58 #include "HTMLFrameElement.h" | |
| 59 #include "HTMLNames.h" | |
| 60 #include "HTMLObjectElement.h" | |
| 61 #include "HTTPParsers.h" | |
| 62 #include "HistoryItem.h" | |
| 63 #include "IconDatabase.h" | |
| 64 #include "IconLoader.h" | |
| 65 #include "InspectorController.h" | |
| 66 #include "Logging.h" | |
| 67 #include "MIMETypeRegistry.h" | |
| 68 #include "MainResourceLoader.h" | |
| 69 #include "Page.h" | |
| 70 #include "PageCache.h" | |
| 71 #include "PageGroup.h" | |
| 72 #include "PluginData.h" | |
| 73 #include "ProgressTracker.h" | |
| 74 #include "RenderPart.h" | |
| 75 #include "RenderWidget.h" | |
| 76 #include "RenderView.h" | |
| 77 #include "ResourceHandle.h" | |
| 78 #include "ResourceRequest.h" | |
| 79 #include "SecurityOrigin.h" | |
| 80 #include "SegmentedString.h" | |
| 81 #include "Settings.h" | |
| 82 #include "SystemTime.h" | |
| 83 #include "TextResourceDecoder.h" | |
| 84 #include "WindowFeatures.h" | |
| 85 #include "XMLHttpRequest.h" | |
| 86 #include "XMLTokenizer.h" | |
| 87 #include "ScriptController.h" | |
| 88 | |
| 89 #if USE(JSC) | |
| 90 #include "JSDOMBinding.h" | |
| 91 #include <kjs/JSObject.h> | |
| 92 #endif | |
| 93 | |
| 94 #if ENABLE(OFFLINE_WEB_APPLICATIONS) | |
| 95 #include "ApplicationCache.h" | |
| 96 #include "ApplicationCacheResource.h" | |
| 97 #endif | |
| 98 | |
| 99 #if ENABLE(SVG) | |
| 100 #include "SVGDocument.h" | |
| 101 #include "SVGLocatable.h" | |
| 102 #include "SVGNames.h" | |
| 103 #include "SVGPreserveAspectRatio.h" | |
| 104 #include "SVGSVGElement.h" | |
| 105 #include "SVGViewElement.h" | |
| 106 #include "SVGViewSpec.h" | |
| 107 #endif | |
| 108 | |
| 109 namespace WebCore { | |
| 110 | |
| 111 #if ENABLE(SVG) | |
| 112 using namespace SVGNames; | |
| 113 #endif | |
| 114 using namespace HTMLNames; | |
| 115 using namespace EventNames; | |
| 116 | |
| 117 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 118 const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024; | |
| 119 #endif | |
| 120 | |
| 121 struct FormSubmission { | |
| 122 const char* action; | |
| 123 String url; | |
| 124 RefPtr<FormData> data; | |
| 125 String target; | |
| 126 String contentType; | |
| 127 String boundary; | |
| 128 RefPtr<Event> event; | |
| 129 | |
| 130 FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const
String& t, | |
| 131 const String& ct, const String& b, PassRefPtr<Event> e) | |
| 132 : action(a) | |
| 133 , url(u) | |
| 134 , data(d) | |
| 135 , target(t) | |
| 136 , contentType(ct) | |
| 137 , boundary(b) | |
| 138 , event(e) | |
| 139 { | |
| 140 } | |
| 141 }; | |
| 142 | |
| 143 struct ScheduledRedirection { | |
| 144 enum Type { redirection, locationChange, historyNavigation, locationChangeDu
ringLoad, reload }; | |
| 145 Type type; | |
| 146 double delay; | |
| 147 String url; | |
| 148 String referrer; | |
| 149 bool lockHistory; | |
| 150 bool wasUserGesture; | |
| 151 RefPtr<HistoryItem> historyItem; | |
| 152 | |
| 153 ScheduledRedirection(double redirectDelay, const String& redirectURL, bool r
edirectLockHistory, bool userGesture) | |
| 154 : type(redirection) | |
| 155 , delay(redirectDelay) | |
| 156 , url(redirectURL) | |
| 157 , lockHistory(redirectLockHistory) | |
| 158 , wasUserGesture(userGesture) | |
| 159 { | |
| 160 } | |
| 161 | |
| 162 ScheduledRedirection(Type locationChangeType, | |
| 163 const String& locationChangeURL, const String& locationChangeReferre
r, | |
| 164 bool locationChangeLockHistory, bool locationChangeWasUserGesture) | |
| 165 : type(locationChangeType) | |
| 166 , delay(0) | |
| 167 , url(locationChangeURL) | |
| 168 , referrer(locationChangeReferrer) | |
| 169 , lockHistory(locationChangeLockHistory) | |
| 170 , wasUserGesture(locationChangeWasUserGesture) | |
| 171 { | |
| 172 } | |
| 173 | |
| 174 explicit ScheduledRedirection(HistoryItem* item) | |
| 175 : type(historyNavigation) | |
| 176 , delay(0) | |
| 177 , lockHistory(false) | |
| 178 , wasUserGesture(false) | |
| 179 , historyItem(item) | |
| 180 { | |
| 181 } | |
| 182 }; | |
| 183 | |
| 184 static double storedTimeOfLastCompletedLoad; | |
| 185 static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoa
dsForLocalOnly; | |
| 186 | |
| 187 bool isBackForwardLoadType(FrameLoadType type) | |
| 188 { | |
| 189 switch (type) { | |
| 190 case FrameLoadTypeStandard: | |
| 191 case FrameLoadTypeReload: | |
| 192 case FrameLoadTypeReloadAllowingStaleData: | |
| 193 case FrameLoadTypeSame: | |
| 194 case FrameLoadTypeRedirectWithLockedHistory: | |
| 195 case FrameLoadTypeReplace: | |
| 196 return false; | |
| 197 case FrameLoadTypeBack: | |
| 198 case FrameLoadTypeForward: | |
| 199 case FrameLoadTypeIndexedBackForward: | |
| 200 return true; | |
| 201 } | |
| 202 ASSERT_NOT_REACHED(); | |
| 203 return false; | |
| 204 } | |
| 205 | |
| 206 static int numRequests(Document* document) | |
| 207 { | |
| 208 if (!document) | |
| 209 return 0; | |
| 210 | |
| 211 return document->docLoader()->requestCount(); | |
| 212 } | |
| 213 | |
| 214 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) | |
| 215 : m_frame(frame) | |
| 216 , m_client(client) | |
| 217 , m_state(FrameStateCommittedPage) | |
| 218 , m_loadType(FrameLoadTypeStandard) | |
| 219 , m_policyLoadType(FrameLoadTypeStandard) | |
| 220 , m_delegateIsHandlingProvisionalLoadError(false) | |
| 221 , m_delegateIsDecidingNavigationPolicy(false) | |
| 222 , m_delegateIsHandlingUnimplementablePolicy(false) | |
| 223 , m_firstLayoutDone(false) | |
| 224 , m_quickRedirectComing(false) | |
| 225 , m_sentRedirectNotification(false) | |
| 226 , m_inStopAllLoaders(false) | |
| 227 , m_navigationDuringLoad(false) | |
| 228 , m_cachePolicy(CachePolicyVerify) | |
| 229 , m_isExecutingJavaScriptFormAction(false) | |
| 230 , m_isRunningScript(false) | |
| 231 , m_didCallImplicitClose(false) | |
| 232 , m_wasUnloadEventEmitted(false) | |
| 233 , m_isComplete(false) | |
| 234 , m_isLoadingMainResource(false) | |
| 235 , m_firingUnloadEvents(false) | |
| 236 , m_cancellingWithLoadInProgress(false) | |
| 237 , m_needsClear(false) | |
| 238 , m_receivedData(false) | |
| 239 , m_encodingWasChosenByUser(false) | |
| 240 , m_containsPlugIns(false) | |
| 241 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired) | |
| 242 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired) | |
| 243 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired) | |
| 244 , m_opener(0) | |
| 245 , m_openedByDOM(false) | |
| 246 , m_creatingInitialEmptyDocument(false) | |
| 247 , m_isDisplayingInitialEmptyDocument(false) | |
| 248 , m_committedFirstRealDocumentLoad(false) | |
| 249 , m_didPerformFirstNavigation(false) | |
| 250 #ifndef NDEBUG | |
| 251 , m_didDispatchDidCommitLoad(false) | |
| 252 #endif | |
| 253 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 254 , m_useLowBandwidthDisplay(true) | |
| 255 , m_finishedParsingDuringLowBandwidthDisplay(false) | |
| 256 , m_needToSwitchOutLowBandwidthDisplay(false) | |
| 257 #endif | |
| 258 { | |
| 259 } | |
| 260 | |
| 261 FrameLoader::~FrameLoader() | |
| 262 { | |
| 263 setOpener(0); | |
| 264 | |
| 265 HashSet<Frame*>::iterator end = m_openedFrames.end(); | |
| 266 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it) | |
| 267 (*it)->loader()->m_opener = 0; | |
| 268 | |
| 269 m_client->frameLoaderDestroyed(); | |
| 270 } | |
| 271 | |
| 272 void FrameLoader::init() | |
| 273 { | |
| 274 // this somewhat odd set of steps is needed to give the frame an initial emp
ty document | |
| 275 m_isDisplayingInitialEmptyDocument = false; | |
| 276 m_creatingInitialEmptyDocument = true; | |
| 277 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(Strin
g("")), SubstituteData()).get()); | |
| 278 setProvisionalDocumentLoader(m_policyDocumentLoader.get()); | |
| 279 setState(FrameStateProvisional); | |
| 280 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html
", 0, String(), String())); | |
| 281 m_provisionalDocumentLoader->finishedLoading(); | |
| 282 begin(KURL(), false); | |
| 283 end(); | |
| 284 m_frame->document()->cancelParsing(); | |
| 285 m_creatingInitialEmptyDocument = false; | |
| 286 m_didCallImplicitClose = true; | |
| 287 } | |
| 288 | |
| 289 void FrameLoader::setDefersLoading(bool defers) | |
| 290 { | |
| 291 if (m_documentLoader) | |
| 292 m_documentLoader->setDefersLoading(defers); | |
| 293 if (m_provisionalDocumentLoader) | |
| 294 m_provisionalDocumentLoader->setDefersLoading(defers); | |
| 295 if (m_policyDocumentLoader) | |
| 296 m_policyDocumentLoader->setDefersLoading(defers); | |
| 297 } | |
| 298 | |
| 299 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const F
rameLoadRequest& request, const WindowFeatures& features, bool& created) | |
| 300 { | |
| 301 ASSERT(!features.dialog || request.frameName().isEmpty()); | |
| 302 | |
| 303 if (!request.frameName().isEmpty() && request.frameName() != "_blank") { | |
| 304 Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.
frameName()); | |
| 305 if (frame && shouldAllowNavigation(frame)) { | |
| 306 if (!request.resourceRequest().url().isEmpty()) | |
| 307 frame->loader()->loadFrameRequestWithFormAndValues(request, fals
e, 0, 0, HashMap<String, String>()); | |
| 308 if (Page* page = frame->page()) | |
| 309 page->chrome()->focus(); | |
| 310 created = false; | |
| 311 return frame; | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 // FIXME: Setting the referrer should be the caller's responsibility. | |
| 316 FrameLoadRequest requestWithReferrer = request; | |
| 317 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer); | |
| 318 | |
| 319 Page* oldPage = m_frame->page(); | |
| 320 if (!oldPage) | |
| 321 return 0; | |
| 322 | |
| 323 Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, f
eatures); | |
| 324 if (!page) | |
| 325 return 0; | |
| 326 | |
| 327 Frame* frame = page->mainFrame(); | |
| 328 if (request.frameName() != "_blank") | |
| 329 frame->tree()->setName(request.frameName()); | |
| 330 | |
| 331 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locat
ionBarVisible); | |
| 332 page->chrome()->setStatusbarVisible(features.statusBarVisible); | |
| 333 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible); | |
| 334 page->chrome()->setMenubarVisible(features.menuBarVisible); | |
| 335 page->chrome()->setResizable(features.resizable); | |
| 336 | |
| 337 // 'x' and 'y' specify the location of the window, while 'width' and 'height
' | |
| 338 // specify the size of the page. We can only resize the window, so | |
| 339 // adjust for the difference between the window size and the page size. | |
| 340 | |
| 341 FloatRect windowRect = page->chrome()->windowRect(); | |
| 342 FloatSize pageSize = page->chrome()->pageRect().size(); | |
| 343 if (features.xSet) | |
| 344 windowRect.setX(features.x); | |
| 345 if (features.ySet) | |
| 346 windowRect.setY(features.y); | |
| 347 if (features.widthSet) | |
| 348 windowRect.setWidth(features.width + (windowRect.width() - pageSize.widt
h())); | |
| 349 if (features.heightSet) | |
| 350 windowRect.setHeight(features.height + (windowRect.height() - pageSize.h
eight())); | |
| 351 page->chrome()->setWindowRect(windowRect); | |
| 352 | |
| 353 page->chrome()->show(); | |
| 354 | |
| 355 created = true; | |
| 356 return frame; | |
| 357 } | |
| 358 | |
| 359 bool FrameLoader::canHandleRequest(const ResourceRequest& request) | |
| 360 { | |
| 361 return m_client->canHandleRequest(request); | |
| 362 } | |
| 363 | |
| 364 void FrameLoader::changeLocation(const String& url, const String& referrer, bool
lockHistory, bool userGesture) | |
| 365 { | |
| 366 // http://b/1082089 | |
| 367 // Hack to prevent FMW in WebCore::FrameLoader::checkNavigationPolicy. | |
| 368 // Without this, if the frame's javascript onload handler removes the frame, | |
| 369 // then once control returns into FrameLoader::checkNavigationPolicy (from | |
| 370 // the call to m_client->dispatchDecidePolicyForNavigationAction()), | |
| 371 // 'this' has been deallocated and we trash memory. | |
| 372 RefPtr<Frame> protector(m_frame); | |
| 373 | |
| 374 changeLocation(completeURL(url), referrer, lockHistory, userGesture); | |
| 375 } | |
| 376 | |
| 377 | |
| 378 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool l
ockHistory, bool userGesture) | |
| 379 { | |
| 380 ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) ||
(m_cachePolicy == CachePolicyRefresh) | |
| 381 ? ReloadIgnoringCacheData : UseProtocolCachePolicy; | |
| 382 ResourceRequest request(url, referrer, policy); | |
| 383 | |
| 384 if (executeIfJavaScriptURL(request.url(), userGesture)) | |
| 385 return; | |
| 386 | |
| 387 urlSelected(request, "_self", 0, lockHistory, userGesture); | |
| 388 } | |
| 389 | |
| 390 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, boo
l lockHistory) | |
| 391 { | |
| 392 FrameLoadRequest copy = request; | |
| 393 if (copy.resourceRequest().httpReferrer().isEmpty()) | |
| 394 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer); | |
| 395 | |
| 396 loadFrameRequestWithFormAndValues(copy, lockHistory, event, 0, HashMap<Strin
g, String>()); | |
| 397 } | |
| 398 | |
| 399 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _tar
get, Event* triggeringEvent, bool lockHistory, bool userGesture) | |
| 400 { | |
| 401 if (executeIfJavaScriptURL(request.url(), userGesture, false)) | |
| 402 return; | |
| 403 | |
| 404 String target = _target; | |
| 405 if (target.isEmpty() && m_frame->document()) | |
| 406 target = m_frame->document()->baseTarget(); | |
| 407 | |
| 408 FrameLoadRequest frameRequest(request, target); | |
| 409 | |
| 410 urlSelected(frameRequest, triggeringEvent, lockHistory); | |
| 411 } | |
| 412 | |
| 413 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String
& urlString, const AtomicString& frameName) | |
| 414 { | |
| 415 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 416 // don't create sub-frame during low bandwidth display | |
| 417 if (frame()->document()->inLowBandwidthDisplay()) { | |
| 418 m_needToSwitchOutLowBandwidthDisplay = true; | |
| 419 return false; | |
| 420 } | |
| 421 #endif | |
| 422 | |
| 423 // Support for <frame src="javascript:string"> | |
| 424 KURL scriptURL; | |
| 425 KURL url; | |
| 426 if (protocolIs(urlString, "javascript")) { | |
| 427 scriptURL = KURL(urlString); | |
| 428 url = blankURL(); | |
| 429 } else | |
| 430 url = completeURL(urlString); | |
| 431 | |
| 432 Frame* frame = ownerElement->contentFrame(); | |
| 433 if (frame) | |
| 434 frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer
, true, userGestureHint()); | |
| 435 else | |
| 436 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer); | |
| 437 | |
| 438 if (!frame) | |
| 439 return false; | |
| 440 | |
| 441 if (!scriptURL.isEmpty()) | |
| 442 frame->loader()->executeIfJavaScriptURL(scriptURL); | |
| 443 | |
| 444 return true; | |
| 445 } | |
| 446 | |
| 447 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL
& url, const String& name, const String& referrer) | |
| 448 { | |
| 449 bool allowsScrolling = true; | |
| 450 int marginWidth = -1; | |
| 451 int marginHeight = -1; | |
| 452 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag
)) { | |
| 453 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElemen
t); | |
| 454 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff; | |
| 455 marginWidth = o->getMarginWidth(); | |
| 456 marginHeight = o->getMarginHeight(); | |
| 457 } | |
| 458 | |
| 459 if (!canLoad(url, referrer)) { | |
| 460 FrameLoader::reportLocalLoadFailed(m_frame, url.string()); | |
| 461 return 0; | |
| 462 } | |
| 463 | |
| 464 bool hideReferrer = shouldHideReferrer(url, referrer); | |
| 465 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideRef
errer ? String() : referrer, | |
| 466 allowsScrolling, marginWidth, marginHei
ght); | |
| 467 | |
| 468 if (!frame) { | |
| 469 checkCallImplicitClose(); | |
| 470 return 0; | |
| 471 } | |
| 472 | |
| 473 frame->loader()->m_isComplete = false; | |
| 474 | |
| 475 RenderObject* renderer = ownerElement->renderer(); | |
| 476 FrameView* view = frame->view(); | |
| 477 if (renderer && renderer->isWidget() && view) | |
| 478 static_cast<RenderWidget*>(renderer)->setWidget(view); | |
| 479 | |
| 480 checkCallImplicitClose(); | |
| 481 | |
| 482 // In these cases, the synchronous load would have finished | |
| 483 // before we could connect the signals, so make sure to send the | |
| 484 // completed() signal for the child by hand | |
| 485 // FIXME: In this case the Frame will have finished loading before | |
| 486 // it's being added to the child list. It would be a good idea to | |
| 487 // create the child first, then invoke the loader separately. | |
| 488 if (url.isEmpty() || url == blankURL()) { | |
| 489 frame->loader()->completed(); | |
| 490 frame->loader()->checkCompleted(); | |
| 491 } | |
| 492 | |
| 493 return frame.get(); | |
| 494 } | |
| 495 | |
| 496 void FrameLoader::submitFormAgain() | |
| 497 { | |
| 498 if (m_isRunningScript) | |
| 499 return; | |
| 500 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release()); | |
| 501 if (form) | |
| 502 submitForm(form->action, form->url, form->data, form->target, | |
| 503 form->contentType, form->boundary, form->event.get()); | |
| 504 } | |
| 505 | |
| 506 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<F
ormData> formData, | |
| 507 const String& target, const String& contentType, const String& boundary, Eve
nt* event) | |
| 508 { | |
| 509 ASSERT(formData); | |
| 510 | |
| 511 if (!m_frame->page()) | |
| 512 return; | |
| 513 | |
| 514 KURL u = completeURL(url.isNull() ? "" : url); | |
| 515 // FIXME: Do we really need to special-case an empty URL? | |
| 516 // Would it be better to just go on with the form submisson and let the I/O
fail? | |
| 517 if (u.isEmpty()) | |
| 518 return; | |
| 519 | |
| 520 if (u.protocolIs("javascript")) { | |
| 521 m_isExecutingJavaScriptFormAction = true; | |
| 522 executeIfJavaScriptURL(u, false, false); | |
| 523 m_isExecutingJavaScriptFormAction = false; | |
| 524 return; | |
| 525 } | |
| 526 | |
| 527 if (m_isRunningScript) { | |
| 528 if (m_deferredFormSubmission) | |
| 529 return; | |
| 530 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, t
arget, | |
| 531 contentType, boundary, event)); | |
| 532 return; | |
| 533 } | |
| 534 | |
| 535 formData->generateFiles(m_frame->page()->chrome()->client()); | |
| 536 | |
| 537 FrameLoadRequest frameRequest; | |
| 538 | |
| 539 if (!m_outgoingReferrer.isEmpty()) | |
| 540 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer); | |
| 541 | |
| 542 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget
() : target); | |
| 543 | |
| 544 // Handle mailto: forms | |
| 545 bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto"); | |
| 546 if (isMailtoForm && strcmp(action, "GET") != 0) { | |
| 547 // Append body= for POST mailto, replace the whole query string for GET
one. | |
| 548 String body = formData->flattenToString(); | |
| 549 String query = u.query(); | |
| 550 if (!query.isEmpty()) | |
| 551 query.append('&'); | |
| 552 u.setQuery(query + body); | |
| 553 } | |
| 554 | |
| 555 if (strcmp(action, "GET") == 0) { | |
| 556 u.setQuery(formData->flattenToString()); | |
| 557 } else { | |
| 558 if (!isMailtoForm) | |
| 559 frameRequest.resourceRequest().setHTTPBody(formData.get()); | |
| 560 frameRequest.resourceRequest().setHTTPMethod("POST"); | |
| 561 | |
| 562 // construct some user headers if necessary | |
| 563 if (contentType.isNull() || contentType == "application/x-www-form-urlen
coded") | |
| 564 frameRequest.resourceRequest().setHTTPContentType(contentType); | |
| 565 else // contentType must be "multipart/form-data" | |
| 566 frameRequest.resourceRequest().setHTTPContentType(contentType + "; b
oundary=" + boundary); | |
| 567 } | |
| 568 | |
| 569 frameRequest.resourceRequest().setURL(u); | |
| 570 | |
| 571 submitForm(frameRequest, event); | |
| 572 } | |
| 573 | |
| 574 void FrameLoader::stopLoading(bool sendUnload) | |
| 575 { | |
| 576 if (m_frame->document() && m_frame->document()->tokenizer()) | |
| 577 m_frame->document()->tokenizer()->stopParsing(); | |
| 578 | |
| 579 if (sendUnload) { | |
| 580 if (m_frame->document()) { | |
| 581 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { | |
| 582 Node* currentFocusedNode = m_frame->document()->focusedNode(); | |
| 583 if (currentFocusedNode) | |
| 584 currentFocusedNode->aboutToUnload(); | |
| 585 setFiringUnloadEvents(true); | |
| 586 m_frame->document()->dispatchWindowEvent(unloadEvent, false, fal
se); | |
| 587 setFiringUnloadEvents(false); | |
| 588 if (m_frame->document()) | |
| 589 m_frame->document()->updateRendering(); | |
| 590 m_wasUnloadEventEmitted = true; | |
| 591 if (m_frame->eventHandler()->pendingFrameUnloadEventCount()) | |
| 592 m_frame->eventHandler()->clearPendingFrameUnloadEventCount()
; | |
| 593 if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount(
)) | |
| 594 m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventC
ount(); | |
| 595 } | |
| 596 } | |
| 597 if (m_frame->document() && !m_frame->document()->inPageCache()) | |
| 598 m_frame->document()->removeAllEventListenersFromAllNodes(); | |
| 599 } | |
| 600 | |
| 601 m_isComplete = true; // to avoid calling completed() in finishedParsing() (D
avid) | |
| 602 m_isLoadingMainResource = false; | |
| 603 m_didCallImplicitClose = true; // don't want that one either | |
| 604 m_cachePolicy = CachePolicyVerify; // Why here? | |
| 605 | |
| 606 if (m_frame->document() && m_frame->document()->parsing()) { | |
| 607 finishedParsing(); | |
| 608 m_frame->document()->setParsing(false); | |
| 609 } | |
| 610 | |
| 611 m_workingURL = KURL(); | |
| 612 | |
| 613 if (Document* doc = m_frame->document()) { | |
| 614 if (DocLoader* docLoader = doc->docLoader()) | |
| 615 cache()->loader()->cancelRequests(docLoader); | |
| 616 XMLHttpRequest::cancelRequests(doc); | |
| 617 #if ENABLE(DATABASE) | |
| 618 #endif | |
| 619 } | |
| 620 | |
| 621 // tell all subframes to stop as well | |
| 622 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
| 623 child->loader()->stopLoading(sendUnload); | |
| 624 | |
| 625 cancelRedirection(); | |
| 626 | |
| 627 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 628 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) { | |
| 629 // Since loading is forced to stop, reset the state without really switc
hing. | |
| 630 m_needToSwitchOutLowBandwidthDisplay = false; | |
| 631 switchOutLowBandwidthDisplayIfReady(); | |
| 632 } | |
| 633 #endif | |
| 634 } | |
| 635 | |
| 636 void FrameLoader::stop() | |
| 637 { | |
| 638 // http://bugs.webkit.org/show_bug.cgi?id=10854 | |
| 639 // The frame's last ref may be removed and it will be deleted by checkComple
ted(). | |
| 640 RefPtr<Frame> protector(m_frame); | |
| 641 | |
| 642 if (m_frame->document()) { | |
| 643 if (m_frame->document()->tokenizer()) | |
| 644 m_frame->document()->tokenizer()->stopParsing(); | |
| 645 m_frame->document()->finishParsing(); | |
| 646 } else | |
| 647 // WebKit partially uses WebCore when loading non-HTML docs. In these c
ases doc==nil, but | |
| 648 // WebCore is enough involved that we need to checkCompleted() in order
for m_bComplete to | |
| 649 // become true. An example is when a subframe is a pure text doc, and th
at subframe is the | |
| 650 // last one to complete. | |
| 651 checkCompleted(); | |
| 652 if (m_iconLoader) | |
| 653 m_iconLoader->stopLoading(); | |
| 654 } | |
| 655 | |
| 656 bool FrameLoader::closeURL() | |
| 657 { | |
| 658 saveDocumentState(); | |
| 659 stopLoading(true); | |
| 660 m_frame->editor()->clearUndoRedoOperations(); | |
| 661 return true; | |
| 662 } | |
| 663 | |
| 664 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress) | |
| 665 { | |
| 666 m_cancellingWithLoadInProgress = cancelWithLoadInProgress; | |
| 667 | |
| 668 stopRedirectionTimer(); | |
| 669 | |
| 670 m_scheduledRedirection.clear(); | |
| 671 } | |
| 672 | |
| 673 KURL FrameLoader::iconURL() | |
| 674 { | |
| 675 // If this isn't a top level frame, return nothing | |
| 676 if (m_frame->tree() && m_frame->tree()->parent()) | |
| 677 return KURL(); | |
| 678 | |
| 679 // If we have an iconURL from a Link element, return that | |
| 680 if (m_frame->document() && !m_frame->document()->iconURL().isEmpty()) | |
| 681 return KURL(m_frame->document()->iconURL()); | |
| 682 | |
| 683 // Don't return a favicon iconURL unless we're http or https | |
| 684 if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https")) | |
| 685 return KURL(); | |
| 686 | |
| 687 KURL url; | |
| 688 url.setProtocol(m_URL.protocol()); | |
| 689 url.setHost(m_URL.host()); | |
| 690 if (int port = m_URL.port()) | |
| 691 url.setPort(port); | |
| 692 url.setPath("/favicon.ico"); | |
| 693 return url; | |
| 694 } | |
| 695 | |
| 696 bool FrameLoader::didOpenURL(const KURL& url) | |
| 697 { | |
| 698 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedir
ection::locationChangeDuringLoad) | |
| 699 // A redirect was scheduled before the document was created. | |
| 700 // This can happen when one frame changes another frame's location. | |
| 701 return false; | |
| 702 | |
| 703 cancelRedirection(); | |
| 704 m_frame->editor()->clearLastEditCommand(); | |
| 705 closeURL(); | |
| 706 | |
| 707 m_isComplete = false; | |
| 708 m_isLoadingMainResource = true; | |
| 709 m_didCallImplicitClose = false; | |
| 710 | |
| 711 m_frame->setJSStatusBarText(String()); | |
| 712 m_frame->setJSDefaultStatusBarText(String()); | |
| 713 | |
| 714 m_URL = url; | |
| 715 if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host()
.isEmpty() && m_URL.path().isEmpty()) | |
| 716 m_URL.setPath("/"); | |
| 717 m_workingURL = m_URL; | |
| 718 | |
| 719 started(); | |
| 720 | |
| 721 return true; | |
| 722 } | |
| 723 | |
| 724 void FrameLoader::didExplicitOpen() | |
| 725 { | |
| 726 m_isComplete = false; | |
| 727 m_didCallImplicitClose = false; | |
| 728 | |
| 729 // Calling document.open counts as committing the first real document load. | |
| 730 m_committedFirstRealDocumentLoad = true; | |
| 731 | |
| 732 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing
away results | |
| 733 // from a subsequent window.document.open / window.document.write call. | |
| 734 // Cancelling redirection here works for all cases because document.open | |
| 735 // implicitly precedes document.write. | |
| 736 cancelRedirection(); | |
| 737 if (m_frame->document()->url() != blankURL()) | |
| 738 m_URL = m_frame->document()->url(); | |
| 739 } | |
| 740 | |
| 741 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool
replaceDocument) | |
| 742 { | |
| 743 if (!url.protocolIs("javascript")) | |
| 744 return false; | |
| 745 | |
| 746 String script = decodeURLEscapeSequences(url.string().substring(strlen("java
script:"))); | |
| 747 | |
| 748 bool succ; | |
| 749 String scriptResult = executeScript(script, &succ, userGesture); | |
| 750 if (!succ) return true; | |
| 751 | |
| 752 SecurityOrigin* currentSecurityOrigin = 0; | |
| 753 if (m_frame->document()) | |
| 754 currentSecurityOrigin = m_frame->document()->securityOrigin(); | |
| 755 | |
| 756 // FIXME: We should always replace the document, but doing so | |
| 757 // synchronously can cause crashes: | |
| 758 // http://bugs.webkit.org/show_bug.cgi?id=16782 | |
| 759 if (replaceDocument) { | |
| 760 begin(m_URL, true, currentSecurityOrigin); | |
| 761 write(scriptResult); | |
| 762 end(); | |
| 763 } | |
| 764 | |
| 765 return true; | |
| 766 } | |
| 767 | |
| 768 void FrameLoader::executeScript(const String& url, int baseLine, const String& s
cript) { | |
| 769 bool succ; | |
| 770 executeScript(url, baseLine, script, &succ); | |
| 771 } | |
| 772 | |
| 773 void FrameLoader::executeScript(const String& script, bool forceUserGesture) | |
| 774 { | |
| 775 bool succ; | |
| 776 executeScript(forceUserGesture ? String() : m_URL.string(), 0, script, &succ
); | |
| 777 } | |
| 778 | |
| 779 String FrameLoader::executeScript(const String& script, bool* succ, bool forceUs
erGesture) | |
| 780 { | |
| 781 return executeScript(forceUserGesture ? String() : m_URL.string(), 1, script
, succ); | |
| 782 } | |
| 783 | |
| 784 String FrameLoader::executeScript(const String& url, int baseLine, const String&
script, bool* succ) | |
| 785 { | |
| 786 *succ = false; | |
| 787 if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused()) | |
| 788 return String(); | |
| 789 | |
| 790 bool wasRunningScript = m_isRunningScript; | |
| 791 m_isRunningScript = true; | |
| 792 | |
| 793 String result = m_frame->script()->evaluate(url, baseLine, script, 0, succ); | |
| 794 | |
| 795 if (!wasRunningScript) { | |
| 796 m_isRunningScript = false; | |
| 797 submitFormAgain(); | |
| 798 Document::updateDocumentsRendering(); | |
| 799 } | |
| 800 | |
| 801 return result; | |
| 802 } | |
| 803 | |
| 804 void FrameLoader::cancelAndClear() | |
| 805 { | |
| 806 cancelRedirection(); | |
| 807 | |
| 808 if (!m_isComplete) | |
| 809 closeURL(); | |
| 810 | |
| 811 clear(false); | |
| 812 } | |
| 813 | |
| 814 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects) | |
| 815 { | |
| 816 // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_
bug.cgi?id=11212>, but putting it | |
| 817 // back causes a measurable performance regression which we will need to fix
to restore the correct behavior | |
| 818 // urlsBridgeKnowsAbout.clear(); | |
| 819 | |
| 820 m_frame->editor()->clear(); | |
| 821 | |
| 822 if (!m_needsClear) | |
| 823 return; | |
| 824 m_needsClear = false; | |
| 825 | |
| 826 if (m_frame->document() && !m_frame->document()->inPageCache()) { | |
| 827 m_frame->document()->cancelParsing(); | |
| 828 if (m_frame->document()->attached()) { | |
| 829 m_frame->document()->willRemove(); | |
| 830 m_frame->document()->detach(); | |
| 831 | |
| 832 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document())
; | |
| 833 } | |
| 834 } | |
| 835 | |
| 836 // Do this after detaching the document so that the unload event works. | |
| 837 if (clearWindowProperties) { | |
| 838 m_frame->clearDOMWindow(); | |
| 839 m_frame->script()->clearWindowShell(); | |
| 840 } | |
| 841 | |
| 842 m_frame->selection()->clear(); | |
| 843 m_frame->eventHandler()->clear(); | |
| 844 if (m_frame->view()) | |
| 845 m_frame->view()->clear(); | |
| 846 | |
| 847 m_frame->setSelectionGranularity(CharacterGranularity); | |
| 848 | |
| 849 // Do not drop the document before the ScriptController and view are cleared | |
| 850 // as some destructors might still try to access the document. | |
| 851 m_frame->setDocument(0); | |
| 852 m_decoder = 0; | |
| 853 | |
| 854 m_containsPlugIns = false; | |
| 855 | |
| 856 if (clearScriptObjects) | |
| 857 m_frame->script()->clearScriptObjects(); | |
| 858 | |
| 859 m_redirectionTimer.stop(); | |
| 860 m_scheduledRedirection.clear(); | |
| 861 | |
| 862 m_checkCompletedTimer.stop(); | |
| 863 m_checkLoadCompleteTimer.stop(); | |
| 864 | |
| 865 m_receivedData = false; | |
| 866 m_isDisplayingInitialEmptyDocument = false; | |
| 867 | |
| 868 if (!m_encodingWasChosenByUser) | |
| 869 m_encoding = String(); | |
| 870 } | |
| 871 | |
| 872 void FrameLoader::receivedFirstData() | |
| 873 { | |
| 874 begin(m_workingURL, false); | |
| 875 | |
| 876 dispatchDidCommitLoad(); | |
| 877 dispatchWindowObjectAvailable(); | |
| 878 | |
| 879 String ptitle = m_documentLoader->title(); | |
| 880 // If we have a title let the WebView know about it. | |
| 881 if (!ptitle.isNull()) | |
| 882 m_client->dispatchDidReceiveTitle(ptitle); | |
| 883 | |
| 884 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); | |
| 885 m_workingURL = KURL(); | |
| 886 | |
| 887 double delay; | |
| 888 String url; | |
| 889 if (!m_documentLoader) | |
| 890 return; | |
| 891 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"
), false, delay, url)) | |
| 892 return; | |
| 893 | |
| 894 if (url.isEmpty()) | |
| 895 url = m_URL.string(); | |
| 896 else | |
| 897 url = m_frame->document()->completeURL(url).string(); | |
| 898 | |
| 899 scheduleHTTPRedirection(delay, url); | |
| 900 } | |
| 901 | |
| 902 const String& FrameLoader::responseMIMEType() const | |
| 903 { | |
| 904 return m_responseMIMEType; | |
| 905 } | |
| 906 | |
| 907 void FrameLoader::setResponseMIMEType(const String& type) | |
| 908 { | |
| 909 m_responseMIMEType = type; | |
| 910 } | |
| 911 | |
| 912 void FrameLoader::begin() | |
| 913 { | |
| 914 begin(KURL()); | |
| 915 } | |
| 916 | |
| 917 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) | |
| 918 { | |
| 919 // We need to take a reference to the security origin because |clear| | |
| 920 // might destroy the document that owns it. | |
| 921 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin; | |
| 922 | |
| 923 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->docum
ent() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url)); | |
| 924 clear(resetScripting, resetScripting); | |
| 925 if (dispatch) | |
| 926 dispatchWindowObjectAvailable(); | |
| 927 | |
| 928 m_needsClear = true; | |
| 929 m_isComplete = false; | |
| 930 m_didCallImplicitClose = false; | |
| 931 m_isLoadingMainResource = true; | |
| 932 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument; | |
| 933 | |
| 934 KURL ref(url); | |
| 935 ref.setUser(String()); | |
| 936 ref.setPass(String()); | |
| 937 ref.setRef(String()); | |
| 938 m_outgoingReferrer = ref.string(); | |
| 939 m_URL = url; | |
| 940 | |
| 941 RefPtr<Document> document = DOMImplementation::createDocument(m_responseMIME
Type, m_frame, m_frame->inViewSourceMode()); | |
| 942 m_frame->setDocument(document); | |
| 943 | |
| 944 document->setURL(m_URL); | |
| 945 if (m_decoder) | |
| 946 document->setDecoder(m_decoder.get()); | |
| 947 if (forcedSecurityOrigin) | |
| 948 document->setSecurityOrigin(forcedSecurityOrigin.get()); | |
| 949 | |
| 950 m_frame->domWindow()->setURL(document->url()); | |
| 951 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); | |
| 952 | |
| 953 updatePolicyBaseURL(); | |
| 954 | |
| 955 Settings* settings = document->settings(); | |
| 956 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAu
tomatically()); | |
| 957 | |
| 958 if (m_documentLoader) { | |
| 959 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField
("X-DNS-Prefetch-Control"); | |
| 960 if (!dnsPrefetchControl.isEmpty()) | |
| 961 document->setDNSPrefetchControl(dnsPrefetchControl); | |
| 962 } | |
| 963 | |
| 964 #if FRAME_LOADS_USER_STYLESHEET | |
| 965 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL()
; | |
| 966 if (!userStyleSheet.isEmpty()) | |
| 967 m_frame->setUserStyleSheetLocation(userStyleSheet); | |
| 968 #endif | |
| 969 | |
| 970 restoreDocumentState(); | |
| 971 | |
| 972 document->implicitOpen(); | |
| 973 | |
| 974 if (m_frame->view()) | |
| 975 m_frame->view()->resizeContents(0, 0); | |
| 976 | |
| 977 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 978 // Low bandwidth display is a first pass display without external resources | |
| 979 // used to give an instant visual feedback. We currently only enable it for | |
| 980 // HTML documents in the top frame. | |
| 981 if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBand
widthDisplay) { | |
| 982 m_pendingSourceInLowBandwidthDisplay = String(); | |
| 983 m_finishedParsingDuringLowBandwidthDisplay = false; | |
| 984 m_needToSwitchOutLowBandwidthDisplay = false; | |
| 985 document->setLowBandwidthDisplay(true); | |
| 986 } | |
| 987 #endif | |
| 988 } | |
| 989 | |
| 990 void FrameLoader::write(const char* str, int len, bool flush) | |
| 991 { | |
| 992 if (len == 0 && !flush) | |
| 993 return; | |
| 994 | |
| 995 if (len == -1) | |
| 996 len = strlen(str); | |
| 997 | |
| 998 Tokenizer* tokenizer = m_frame->document()->tokenizer(); | |
| 999 if (tokenizer && tokenizer->wantsRawData()) { | |
| 1000 if (len > 0) | |
| 1001 tokenizer->writeRawData(str, len); | |
| 1002 return; | |
| 1003 } | |
| 1004 | |
| 1005 if (!m_decoder) { | |
| 1006 Settings* settings = m_frame->settings(); | |
| 1007 if (settings) { | |
| 1008 TextResourceDecoder* hintDecoder = NULL; | |
| 1009 Frame* parentFrame = m_frame->tree()->parent(); | |
| 1010 if (parentFrame && parentFrame->document()) | |
| 1011 hintDecoder = parentFrame->document()->decoder(); | |
| 1012 m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings
->defaultTextEncodingName(), settings->usesEncodingDetector(), hintDecoder); | |
| 1013 } else | |
| 1014 m_decoder = TextResourceDecoder::create(m_responseMIMEType, String()
); | |
| 1015 if (m_encoding.isEmpty()) { | |
| 1016 Frame* parentFrame = m_frame->tree()->parent(); | |
| 1017 // TODO(jungshik) : We might as well consider allowing inheriting ch
arset | |
| 1018 // from parent even if canAccess returns false as long as the parent
charset | |
| 1019 // is regarded as safe (that is, it's not UTF-7/ISO-2022-XX/HZ), of
which | |
| 1020 // we're not yet sure. | |
| 1021 if (parentFrame && parentFrame->document()->securityOrigin()->canAcc
ess(m_frame->document()->securityOrigin())) | |
| 1022 m_decoder->setEncoding(parentFrame->document()->inputEncoding(),
TextResourceDecoder::EncodingFromParentFrame); | |
| 1023 } else { | |
| 1024 m_decoder->setEncoding(m_encoding, | |
| 1025 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncod
ing : TextResourceDecoder::EncodingFromHTTPHeader); | |
| 1026 } | |
| 1027 m_frame->document()->setDecoder(m_decoder.get()); | |
| 1028 } | |
| 1029 | |
| 1030 String decoded = m_decoder->decode(str, len); | |
| 1031 if (flush) | |
| 1032 decoded += m_decoder->flush(); | |
| 1033 if (decoded.isEmpty()) | |
| 1034 return; | |
| 1035 | |
| 1036 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 1037 if (m_frame->document()->inLowBandwidthDisplay()) | |
| 1038 m_pendingSourceInLowBandwidthDisplay.append(decoded); | |
| 1039 else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady
() | |
| 1040 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); | |
| 1041 #endif | |
| 1042 | |
| 1043 if (!m_receivedData) { | |
| 1044 m_receivedData = true; | |
| 1045 if (m_decoder->encoding().usesVisualOrdering()) | |
| 1046 m_frame->document()->setVisuallyOrdered(); | |
| 1047 m_frame->document()->recalcStyle(Node::Force); | |
| 1048 } | |
| 1049 | |
| 1050 if (tokenizer) { | |
| 1051 ASSERT(!tokenizer->wantsRawData()); | |
| 1052 tokenizer->write(decoded, true); | |
| 1053 } | |
| 1054 } | |
| 1055 | |
| 1056 void FrameLoader::write(const String& str) | |
| 1057 { | |
| 1058 if (str.isNull()) | |
| 1059 return; | |
| 1060 | |
| 1061 if (!m_receivedData) { | |
| 1062 m_receivedData = true; | |
| 1063 m_frame->document()->setParseMode(Document::Strict); | |
| 1064 } | |
| 1065 | |
| 1066 if (Tokenizer* tokenizer = m_frame->document()->tokenizer()) | |
| 1067 tokenizer->write(str, true); | |
| 1068 } | |
| 1069 | |
| 1070 void FrameLoader::end() | |
| 1071 { | |
| 1072 m_isLoadingMainResource = false; | |
| 1073 endIfNotLoadingMainResource(); | |
| 1074 } | |
| 1075 | |
| 1076 void FrameLoader::endIfNotLoadingMainResource() | |
| 1077 { | |
| 1078 if (m_isLoadingMainResource || !m_frame->page()) | |
| 1079 return; | |
| 1080 | |
| 1081 // http://bugs.webkit.org/show_bug.cgi?id=10854 | |
| 1082 // The frame's last ref may be removed and it can be deleted by checkComplet
ed(), | |
| 1083 // so we'll add a protective refcount | |
| 1084 RefPtr<Frame> protector(m_frame); | |
| 1085 | |
| 1086 // make sure nothing's left in there | |
| 1087 if (m_frame->document()) { | |
| 1088 write(0, 0, true); | |
| 1089 m_frame->document()->finishParsing(); | |
| 1090 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 1091 if (m_frame->document()->inLowBandwidthDisplay()) { | |
| 1092 m_finishedParsingDuringLowBandwidthDisplay = true; | |
| 1093 switchOutLowBandwidthDisplayIfReady(); | |
| 1094 } | |
| 1095 #endif | |
| 1096 } else | |
| 1097 // WebKit partially uses WebCore when loading non-HTML docs. In these c
ases doc==nil, but | |
| 1098 // WebCore is enough involved that we need to checkCompleted() in order
for m_bComplete to | |
| 1099 // become true. An example is when a subframe is a pure text doc, and t
hat subframe is the | |
| 1100 // last one to complete. | |
| 1101 checkCompleted(); | |
| 1102 } | |
| 1103 | |
| 1104 void FrameLoader::iconLoadDecisionAvailable() | |
| 1105 { | |
| 1106 if (!m_mayLoadIconLater) | |
| 1107 return; | |
| 1108 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for
its icon", this); | |
| 1109 startIconLoader(); | |
| 1110 m_mayLoadIconLater = false; | |
| 1111 } | |
| 1112 | |
| 1113 void FrameLoader::startIconLoader() | |
| 1114 { | |
| 1115 // FIXME: We kick off the icon loader when the frame is done receiving its m
ain resource. | |
| 1116 // But we should instead do it when we're done parsing the head element. | |
| 1117 if (!isLoadingMainFrame()) | |
| 1118 return; | |
| 1119 | |
| 1120 if (!iconDatabase() || !iconDatabase()->isEnabled()) | |
| 1121 return; | |
| 1122 | |
| 1123 KURL url(iconURL()); | |
| 1124 String urlString(url.string()); | |
| 1125 if (urlString.isEmpty()) | |
| 1126 return; | |
| 1127 | |
| 1128 // If we're not reloading and the icon database doesn't say to load now then
bail before we actually start the load | |
| 1129 if (loadType() != FrameLoadTypeReload) { | |
| 1130 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlSt
ring, m_documentLoader.get()); | |
| 1131 if (decision == IconLoadNo) { | |
| 1132 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load
this icon, committing iconURL %s to database for pageURL mapping", urlString.as
cii().data()); | |
| 1133 commitIconURLToIconDatabase(url); | |
| 1134 | |
| 1135 // We were told not to load this icon - that means this icon is alre
ady known by the database | |
| 1136 // If the icon data hasn't been read in from disk yet, kick off the
read of the icon from the database to make sure someone | |
| 1137 // has done it. This is after registering for the notification so t
he WebView can call the appropriate delegate method. | |
| 1138 // Otherwise if the icon data *is* available, notify the delegate | |
| 1139 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) { | |
| 1140 LOG(IconDatabase, "Told not to load icon %s but icon data is not
yet available - registering for notification and requesting load from disk", ur
lString.ascii().data()); | |
| 1141 m_client->registerForIconNotification(); | |
| 1142 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0)); | |
| 1143 iconDatabase()->iconForPageURL(originalRequestURL().string(), In
tSize(0, 0)); | |
| 1144 } else | |
| 1145 m_client->dispatchDidReceiveIcon(); | |
| 1146 | |
| 1147 return; | |
| 1148 } | |
| 1149 | |
| 1150 if (decision == IconLoadUnknown) { | |
| 1151 // In this case, we may end up loading the icon later, but we still
want to commit the icon url mapping to the database | |
| 1152 // just in case we don't end up loading later - if we commit the map
ping a second time after the load, that's no big deal | |
| 1153 // We also tell the client to register for the notification that the
icon is received now so it isn't missed in case the | |
| 1154 // icon is later read in from disk | |
| 1155 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, u
rlString.ascii().data()); | |
| 1156 m_mayLoadIconLater = true; | |
| 1157 m_client->registerForIconNotification(); | |
| 1158 commitIconURLToIconDatabase(url); | |
| 1159 return; | |
| 1160 } | |
| 1161 } | |
| 1162 | |
| 1163 // This is either a reload or the icon database said "yes, load the icon", s
o kick off the load! | |
| 1164 if (!m_iconLoader) | |
| 1165 m_iconLoader.set(IconLoader::create(m_frame).release()); | |
| 1166 | |
| 1167 m_iconLoader->startLoading(); | |
| 1168 } | |
| 1169 | |
| 1170 void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy) | |
| 1171 { | |
| 1172 localLoadPolicy = policy; | |
| 1173 } | |
| 1174 | |
| 1175 bool FrameLoader::restrictAccessToLocal() | |
| 1176 { | |
| 1177 return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll; | |
| 1178 } | |
| 1179 | |
| 1180 bool FrameLoader::allowSubstituteDataAccessToLocal() | |
| 1181 { | |
| 1182 return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly; | |
| 1183 } | |
| 1184 | |
| 1185 static HashSet<String, CaseFoldingHash>& localSchemes() | |
| 1186 { | |
| 1187 static HashSet<String, CaseFoldingHash> localSchemes; | |
| 1188 | |
| 1189 if (localSchemes.isEmpty()) { | |
| 1190 localSchemes.add("file"); | |
| 1191 localSchemes.add("chrome-resource"); | |
| 1192 #if PLATFORM(MAC) | |
| 1193 localSchemes.add("applewebdata"); | |
| 1194 #endif | |
| 1195 #if PLATFORM(QT) | |
| 1196 localSchemes.add("qrc"); | |
| 1197 #endif | |
| 1198 } | |
| 1199 | |
| 1200 return localSchemes; | |
| 1201 } | |
| 1202 | |
| 1203 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon) | |
| 1204 { | |
| 1205 ASSERT(iconDatabase()); | |
| 1206 LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s"
, icon.string().ascii().data(), m_URL.string().ascii().data(), originalRequestUR
L().string().ascii().data()); | |
| 1207 iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string()); | |
| 1208 iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().str
ing()); | |
| 1209 } | |
| 1210 | |
| 1211 void FrameLoader::restoreDocumentState() | |
| 1212 { | |
| 1213 Document* doc = m_frame->document(); | |
| 1214 if (!doc) | |
| 1215 return; | |
| 1216 | |
| 1217 HistoryItem* itemToRestore = 0; | |
| 1218 | |
| 1219 switch (loadType()) { | |
| 1220 case FrameLoadTypeReload: | |
| 1221 case FrameLoadTypeReloadAllowingStaleData: | |
| 1222 case FrameLoadTypeSame: | |
| 1223 case FrameLoadTypeReplace: | |
| 1224 break; | |
| 1225 case FrameLoadTypeBack: | |
| 1226 case FrameLoadTypeForward: | |
| 1227 case FrameLoadTypeIndexedBackForward: | |
| 1228 case FrameLoadTypeRedirectWithLockedHistory: | |
| 1229 case FrameLoadTypeStandard: | |
| 1230 itemToRestore = m_currentHistoryItem.get(); | |
| 1231 } | |
| 1232 | |
| 1233 if (!itemToRestore) | |
| 1234 return; | |
| 1235 | |
| 1236 doc->setStateForNewFormElements(itemToRestore->documentState()); | |
| 1237 } | |
| 1238 | |
| 1239 void FrameLoader::gotoAnchor() | |
| 1240 { | |
| 1241 // If our URL has no ref, then we have no place we need to jump to. | |
| 1242 // OTOH If CSS target was set previously, we want to set it to 0, recalc | |
| 1243 // and possibly repaint because :target pseudo class may have been | |
| 1244 // set (see bug 11321). | |
| 1245 if (!m_URL.hasRef() && !(m_frame->document() && m_frame->document()->getCSST
arget())) | |
| 1246 return; | |
| 1247 | |
| 1248 String ref = m_URL.ref(); | |
| 1249 if (gotoAnchor(ref)) | |
| 1250 return; | |
| 1251 | |
| 1252 // Try again after decoding the ref, based on the document's encoding. | |
| 1253 if (m_decoder) | |
| 1254 gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding())); | |
| 1255 } | |
| 1256 | |
| 1257 void FrameLoader::finishedParsing() | |
| 1258 { | |
| 1259 if (m_creatingInitialEmptyDocument) | |
| 1260 return; | |
| 1261 | |
| 1262 // This can be called from the Frame's destructor, in which case we shouldn'
t protect ourselves | |
| 1263 // because doing so will cause us to re-enter the destructor when protector
goes out of scope. | |
| 1264 // Null-checking the FrameView indicates whether or not we're in the destruc
tor. | |
| 1265 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0; | |
| 1266 | |
| 1267 checkCompleted(); | |
| 1268 | |
| 1269 if (!m_frame->view()) | |
| 1270 return; // We are being destroyed by something checkCompleted called. | |
| 1271 | |
| 1272 // Check if the scrollbars are really needed for the content. | |
| 1273 // If not, remove them, relayout, and repaint. | |
| 1274 m_frame->view()->restoreScrollbar(); | |
| 1275 | |
| 1276 m_client->dispatchDidFinishDocumentLoad(); | |
| 1277 | |
| 1278 gotoAnchor(); | |
| 1279 } | |
| 1280 | |
| 1281 void FrameLoader::loadDone() | |
| 1282 { | |
| 1283 if (m_frame->document()) | |
| 1284 checkCompleted(); | |
| 1285 } | |
| 1286 | |
| 1287 void FrameLoader::checkCompleted() | |
| 1288 { | |
| 1289 // Any frame that hasn't completed yet? | |
| 1290 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
| 1291 if (!child->loader()->m_isComplete) | |
| 1292 return; | |
| 1293 | |
| 1294 // Have we completed before? | |
| 1295 if (m_isComplete) | |
| 1296 return; | |
| 1297 | |
| 1298 // Are we still parsing? | |
| 1299 if (m_frame->document() && m_frame->document()->parsing()) | |
| 1300 return; | |
| 1301 | |
| 1302 // Still waiting for images/scripts? | |
| 1303 if (m_frame->document()) | |
| 1304 if (numRequests(m_frame->document())) | |
| 1305 return; | |
| 1306 | |
| 1307 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 1308 // as switch will be called, don't complete yet | |
| 1309 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay() && m
_needToSwitchOutLowBandwidthDisplay) | |
| 1310 return; | |
| 1311 #endif | |
| 1312 | |
| 1313 // OK, completed. | |
| 1314 m_isComplete = true; | |
| 1315 | |
| 1316 RefPtr<Frame> protect(m_frame); | |
| 1317 checkCallImplicitClose(); // if we didn't do it before | |
| 1318 | |
| 1319 // Do not start a redirection timer for subframes here. | |
| 1320 // That is deferred until the parent is completed. | |
| 1321 if (m_scheduledRedirection && !m_frame->tree()->parent()) | |
| 1322 startRedirectionTimer(); | |
| 1323 | |
| 1324 completed(); | |
| 1325 if (m_frame->page()) | |
| 1326 checkLoadComplete(); | |
| 1327 } | |
| 1328 | |
| 1329 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*) | |
| 1330 { | |
| 1331 checkCompleted(); | |
| 1332 } | |
| 1333 | |
| 1334 void FrameLoader::scheduleCheckCompleted() | |
| 1335 { | |
| 1336 if (!m_checkCompletedTimer.isActive()) | |
| 1337 m_checkCompletedTimer.startOneShot(0); | |
| 1338 } | |
| 1339 | |
| 1340 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*) | |
| 1341 { | |
| 1342 if (!m_frame->page()) | |
| 1343 return; | |
| 1344 checkLoadComplete(); | |
| 1345 } | |
| 1346 | |
| 1347 void FrameLoader::scheduleCheckLoadComplete() | |
| 1348 { | |
| 1349 if (!m_checkLoadCompleteTimer.isActive()) | |
| 1350 m_checkLoadCompleteTimer.startOneShot(0); | |
| 1351 } | |
| 1352 | |
| 1353 void FrameLoader::checkCallImplicitClose() | |
| 1354 { | |
| 1355 if (m_didCallImplicitClose || !m_frame->document() || m_frame->document()->p
arsing()) | |
| 1356 return; | |
| 1357 | |
| 1358 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
| 1359 if (!child->loader()->m_isComplete) // still got a frame running -> too
early | |
| 1360 return; | |
| 1361 | |
| 1362 m_didCallImplicitClose = true; | |
| 1363 m_wasUnloadEventEmitted = false; | |
| 1364 if (m_frame->document()) | |
| 1365 m_frame->document()->implicitClose(); | |
| 1366 } | |
| 1367 | |
| 1368 KURL FrameLoader::baseURL() const | |
| 1369 { | |
| 1370 ASSERT(m_frame->document()); | |
| 1371 return m_frame->document()->baseURL(); | |
| 1372 } | |
| 1373 | |
| 1374 String FrameLoader::baseTarget() const | |
| 1375 { | |
| 1376 ASSERT(m_frame->document()); | |
| 1377 return m_frame->document()->baseTarget(); | |
| 1378 } | |
| 1379 | |
| 1380 KURL FrameLoader::completeURL(const String& url) | |
| 1381 { | |
| 1382 ASSERT(m_frame->document()); | |
| 1383 return m_frame->document()->completeURL(url); | |
| 1384 } | |
| 1385 | |
| 1386 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url) | |
| 1387 { | |
| 1388 if (delay < 0 || delay > INT_MAX / 1000) | |
| 1389 return; | |
| 1390 | |
| 1391 if (!m_frame->page()) | |
| 1392 return; | |
| 1393 | |
| 1394 // We want a new history item if the refresh timeout is > 1 second. | |
| 1395 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay) | |
| 1396 scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, fal
se)); | |
| 1397 } | |
| 1398 | |
| 1399 void FrameLoader::scheduleLocationChange(const String& url, const String& referr
er, bool lockHistory, bool wasUserGesture) | |
| 1400 { | |
| 1401 if (!m_frame->page()) | |
| 1402 return; | |
| 1403 | |
| 1404 // If the URL we're going to navigate to is the same as the current one, exc
ept for the | |
| 1405 // fragment part, we don't need to schedule the location change. | |
| 1406 KURL parsedURL(url); | |
| 1407 if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) { | |
| 1408 changeLocation(url, referrer, lockHistory, wasUserGesture); | |
| 1409 return; | |
| 1410 } | |
| 1411 | |
| 1412 // Handle a location change of a page with no document as a special case. | |
| 1413 // This may happen when a frame changes the location of another frame. | |
| 1414 bool duringLoad = !m_committedFirstRealDocumentLoad; | |
| 1415 | |
| 1416 // If a redirect was scheduled during a load, then stop the current load. | |
| 1417 // Otherwise when the current load transitions from a provisional to a | |
| 1418 // committed state, pending redirects may be cancelled. | |
| 1419 if (duringLoad) { | |
| 1420 if (m_provisionalDocumentLoader) | |
| 1421 m_provisionalDocumentLoader->stopLoading(); | |
| 1422 stopLoading(true); | |
| 1423 } | |
| 1424 | |
| 1425 ScheduledRedirection::Type type = duringLoad | |
| 1426 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection:
:locationChange; | |
| 1427 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistor
y, wasUserGesture)); | |
| 1428 } | |
| 1429 | |
| 1430 void FrameLoader::scheduleRefresh(bool wasUserGesture) | |
| 1431 { | |
| 1432 if (!m_frame->page()) | |
| 1433 return; | |
| 1434 | |
| 1435 // Handle a location change of a page with no document as a special case. | |
| 1436 // This may happen when a frame requests a refresh of another frame. | |
| 1437 bool duringLoad = !m_frame->document(); | |
| 1438 | |
| 1439 // If a refresh was scheduled during a load, then stop the current load. | |
| 1440 // Otherwise when the current load transitions from a provisional to a | |
| 1441 // committed state, pending redirects may be cancelled. | |
| 1442 if (duringLoad) | |
| 1443 stopLoading(true); | |
| 1444 | |
| 1445 ScheduledRedirection::Type type = duringLoad | |
| 1446 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection:
:locationChange; | |
| 1447 scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoin
gReferrer, true, wasUserGesture)); | |
| 1448 m_cachePolicy = CachePolicyRefresh; | |
| 1449 } | |
| 1450 | |
| 1451 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection) | |
| 1452 { | |
| 1453 switch (redirection.type) { | |
| 1454 case ScheduledRedirection::redirection: | |
| 1455 return false; | |
| 1456 case ScheduledRedirection::reload: | |
| 1457 case ScheduledRedirection::historyNavigation: | |
| 1458 case ScheduledRedirection::locationChange: | |
| 1459 case ScheduledRedirection::locationChangeDuringLoad: | |
| 1460 return true; | |
| 1461 } | |
| 1462 ASSERT_NOT_REACHED(); | |
| 1463 return false; | |
| 1464 } | |
| 1465 | |
| 1466 void FrameLoader::scheduleHistoryNavigation(int steps) | |
| 1467 { | |
| 1468 if (!m_frame->page()) | |
| 1469 return; | |
| 1470 | |
| 1471 // navigation will always be allowed in the 0 steps case, which is OK becaus
e that's supposed to force a reload. | |
| 1472 if (!canGoBackOrForward(steps)) { | |
| 1473 cancelRedirection(); | |
| 1474 return; | |
| 1475 } | |
| 1476 | |
| 1477 if (steps == 0) { | |
| 1478 // Special case for go(0) from a frame -> reload only the frame | |
| 1479 scheduleRedirection(new ScheduledRedirection(ScheduledRedirection::reloa
d, String(), String(), false, false)); | |
| 1480 return; | |
| 1481 } | |
| 1482 | |
| 1483 Page* page = m_frame->page(); | |
| 1484 if (!page) | |
| 1485 return; | |
| 1486 BackForwardList* list = page->backForwardList(); | |
| 1487 if (!list) | |
| 1488 return; | |
| 1489 | |
| 1490 // Asynchronously loads the item at the given offset in the history. | |
| 1491 list->goToItemAtIndexAsync(steps); | |
| 1492 | |
| 1493 // The redirection will be handled elsewhere. | |
| 1494 cancelRedirection(); | |
| 1495 } | |
| 1496 | |
| 1497 // This is called by ContextMenuController, which is only used in test shell | |
| 1498 // and not Chrome. | |
| 1499 void FrameLoader::goBackOrForward(int distance) | |
| 1500 { | |
| 1501 if (distance == 0) | |
| 1502 return; | |
| 1503 | |
| 1504 Page* page = m_frame->page(); | |
| 1505 if (!page) | |
| 1506 return; | |
| 1507 BackForwardList* list = page->backForwardList(); | |
| 1508 if (!list) | |
| 1509 return; | |
| 1510 | |
| 1511 HistoryItem* item = list->itemAtIndex(distance); | |
| 1512 if (!item) { | |
| 1513 if (distance > 0) { | |
| 1514 int forwardListCount = list->forwardListCount(); | |
| 1515 if (forwardListCount > 0) | |
| 1516 item = list->itemAtIndex(forwardListCount); | |
| 1517 } else { | |
| 1518 int backListCount = list->backListCount(); | |
| 1519 if (backListCount > 0) | |
| 1520 item = list->itemAtIndex(-backListCount); | |
| 1521 } | |
| 1522 } | |
| 1523 | |
| 1524 ASSERT(item); // we should not reach this line with an empty back/forward li
st | |
| 1525 if (item) | |
| 1526 page->goToItem(item, FrameLoadTypeIndexedBackForward); | |
| 1527 } | |
| 1528 | |
| 1529 void FrameLoader::goToHistoryItem(HistoryItem* item) | |
| 1530 { | |
| 1531 Page* page = m_frame->page(); | |
| 1532 if (!page) | |
| 1533 return; | |
| 1534 | |
| 1535 page->goToItem(item, FrameLoadTypeIndexedBackForward); | |
| 1536 } | |
| 1537 | |
| 1538 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*) | |
| 1539 { | |
| 1540 ASSERT(m_frame->page()); | |
| 1541 | |
| 1542 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release()); | |
| 1543 | |
| 1544 switch (redirection->type) { | |
| 1545 case ScheduledRedirection::redirection: | |
| 1546 case ScheduledRedirection::locationChange: | |
| 1547 case ScheduledRedirection::locationChangeDuringLoad: | |
| 1548 changeLocation(redirection->url, redirection->referrer, | |
| 1549 redirection->lockHistory, redirection->wasUserGesture); | |
| 1550 return; | |
| 1551 case ScheduledRedirection::reload: | |
| 1552 urlSelected(m_URL, "", 0, false, false); | |
| 1553 return; | |
| 1554 case ScheduledRedirection::historyNavigation: | |
| 1555 goToHistoryItem(redirection->historyItem.get()); | |
| 1556 return; | |
| 1557 } | |
| 1558 | |
| 1559 ASSERT_NOT_REACHED(); | |
| 1560 } | |
| 1561 | |
| 1562 /* | |
| 1563 In the case of saving state about a page with frames, we store a tree of ite
ms that mirrors the frame tree. | |
| 1564 The item that was the target of the user's navigation is designated as the "
targetItem". | |
| 1565 When this method is called with doClip=YES we're able to create the whole tr
ee except for the target's children, | |
| 1566 which will be loaded in the future. That part of the tree will be filled ou
t as the child loads are committed. | |
| 1567 */ | |
| 1568 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
Frame* childFrame) | |
| 1569 { | |
| 1570 ASSERT(childFrame); | |
| 1571 HistoryItem* parentItem = currentHistoryItem(); | |
| 1572 FrameLoadType loadType = this->loadType(); | |
| 1573 FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory; | |
| 1574 | |
| 1575 KURL workingURL = url; | |
| 1576 | |
| 1577 // If we're moving in the backforward list, we might want to replace the con
tent | |
| 1578 // of this child frame with whatever was there at that point. | |
| 1579 // Reload will maintain the frame contents, LoadSame will not. | |
| 1580 if (parentItem && parentItem->children().size() && | |
| 1581 (isBackForwardLoadType(loadType) || loadType == FrameLoadTypeReloadAllow
ingStaleData)) | |
| 1582 { | |
| 1583 HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree(
)->name()); | |
| 1584 if (childItem) { | |
| 1585 // Use the original URL to ensure we get all the side-effects, such
as | |
| 1586 // onLoad handlers, of any redirects that happened. An example of wh
ere | |
| 1587 // this is needed is Radar 3213556. | |
| 1588 workingURL = KURL(childItem->originalURLString()); | |
| 1589 // These behaviors implied by these loadTypes should apply to the ch
ild frames | |
| 1590 childLoadType = loadType; | |
| 1591 | |
| 1592 if (isBackForwardLoadType(loadType)) { | |
| 1593 // For back/forward, remember this item so we can traverse any c
hild items as child frames load | |
| 1594 childFrame->loader()->setProvisionalHistoryItem(childItem); | |
| 1595 } else { | |
| 1596 // For reload, just reinstall the current item, since a new chil
d frame was created but we won't be creating a new BF item | |
| 1597 childFrame->loader()->setCurrentHistoryItem(childItem); | |
| 1598 } | |
| 1599 } | |
| 1600 } | |
| 1601 | |
| 1602 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubfr
ame(childFrame->tree()->name()); | |
| 1603 | |
| 1604 if (subframeArchive) | |
| 1605 childFrame->loader()->loadArchive(subframeArchive.release()); | |
| 1606 else | |
| 1607 childFrame->loader()->loadURL(workingURL, referer, String(), childLoadTy
pe, 0, 0); | |
| 1608 } | |
| 1609 | |
| 1610 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive) | |
| 1611 { | |
| 1612 RefPtr<Archive> archive = prpArchive; | |
| 1613 | |
| 1614 ArchiveResource* mainResource = archive->mainResource(); | |
| 1615 ASSERT(mainResource); | |
| 1616 if (!mainResource) | |
| 1617 return; | |
| 1618 | |
| 1619 SubstituteData substituteData(mainResource->data(), mainResource->mimeType()
, mainResource->textEncoding(), KURL()); | |
| 1620 | |
| 1621 ResourceRequest request(mainResource->url()); | |
| 1622 #if PLATFORM(MAC) | |
| 1623 request.applyWebArchiveHackForMail(); | |
| 1624 #endif | |
| 1625 | |
| 1626 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(reque
st, substituteData); | |
| 1627 documentLoader->addAllArchiveResources(archive.get()); | |
| 1628 load(documentLoader.get()); | |
| 1629 } | |
| 1630 | |
| 1631 String FrameLoader::encoding() const | |
| 1632 { | |
| 1633 if (m_encodingWasChosenByUser && !m_encoding.isEmpty()) | |
| 1634 return m_encoding; | |
| 1635 if (m_decoder && m_decoder->encoding().isValid()) | |
| 1636 return m_decoder->encoding().name(); | |
| 1637 Settings* settings = m_frame->settings(); | |
| 1638 return settings ? settings->defaultTextEncodingName() : String(); | |
| 1639 } | |
| 1640 | |
| 1641 bool FrameLoader::gotoAnchor(const String& name) | |
| 1642 { | |
| 1643 ASSERT(m_frame->document()); | |
| 1644 | |
| 1645 if (!m_frame->document()->haveStylesheetsLoaded()) { | |
| 1646 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true); | |
| 1647 return false; | |
| 1648 } | |
| 1649 | |
| 1650 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); | |
| 1651 | |
| 1652 Node* anchorNode = m_frame->document()->getElementById(AtomicString(name)); | |
| 1653 if (!anchorNode && !name.isEmpty()) | |
| 1654 anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->d
ocument()->inCompatMode()); | |
| 1655 | |
| 1656 #if ENABLE(SVG) | |
| 1657 if (m_frame->document()->isSVGDocument()) { | |
| 1658 if (name.startsWith("xpointer(")) { | |
| 1659 // We need to parse the xpointer reference here | |
| 1660 } else if (name.startsWith("svgView(")) { | |
| 1661 RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->docum
ent())->rootElement(); | |
| 1662 if (!svg->currentView()->parseViewSpec(name)) | |
| 1663 return false; | |
| 1664 svg->setUseCurrentView(true); | |
| 1665 } else { | |
| 1666 if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) { | |
| 1667 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGN
ames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0; | |
| 1668 if (viewElement.get()) { | |
| 1669 RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGL
ocatable::nearestViewportElement(viewElement.get())); | |
| 1670 svg->inheritViewAttributes(viewElement.get()); | |
| 1671 } | |
| 1672 } | |
| 1673 } | |
| 1674 // FIXME: need to decide which <svg> to focus on, and zoom to that one | |
| 1675 // FIXME: need to actually "highlight" the viewTarget(s) | |
| 1676 } | |
| 1677 #endif | |
| 1678 | |
| 1679 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear
the current target. | |
| 1680 | |
| 1681 // Implement the rule that "" and "top" both mean top of page as in other br
owsers. | |
| 1682 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) | |
| 1683 return false; | |
| 1684 | |
| 1685 // We need to update the layout before scrolling, otherwise we could | |
| 1686 // really mess things up if an anchor scroll comes at a bad moment. | |
| 1687 if (m_frame->document()) { | |
| 1688 m_frame->document()->updateRendering(); | |
| 1689 // Only do a layout if changes have occurred that make it necessary. | |
| 1690 if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRen
derer()->needsLayout()) | |
| 1691 m_frame->view()->layout(); | |
| 1692 } | |
| 1693 | |
| 1694 // Scroll nested layers and frames to reveal the anchor. | |
| 1695 // Align to the top and to the closest side (this matches other browsers). | |
| 1696 RenderObject* renderer; | |
| 1697 IntRect rect; | |
| 1698 if (!anchorNode) | |
| 1699 renderer = m_frame->document()->renderer(); // top of document | |
| 1700 else { | |
| 1701 renderer = anchorNode->renderer(); | |
| 1702 rect = anchorNode->getRect(); | |
| 1703 } | |
| 1704 if (renderer) | |
| 1705 renderer->enclosingLayer()->scrollRectToVisible(rect, true, RenderLayer:
:gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways); | |
| 1706 | |
| 1707 return true; | |
| 1708 } | |
| 1709 | |
| 1710 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const A
tomicString& frameName, | |
| 1711 const String& mimeType, const Vector<String>& paramNames, const Vector<Strin
g>& paramValues) | |
| 1712 { | |
| 1713 if (url.isEmpty() && mimeType.isEmpty()) | |
| 1714 return false; | |
| 1715 | |
| 1716 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 1717 // don't care object during low bandwidth display | |
| 1718 if (frame()->document()->inLowBandwidthDisplay()) { | |
| 1719 m_needToSwitchOutLowBandwidthDisplay = true; | |
| 1720 return false; | |
| 1721 } | |
| 1722 #endif | |
| 1723 | |
| 1724 KURL completedURL; | |
| 1725 if (!url.isEmpty()) | |
| 1726 completedURL = completeURL(url); | |
| 1727 | |
| 1728 bool useFallback; | |
| 1729 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(),
useFallback)) { | |
| 1730 Settings* settings = m_frame->settings(); | |
| 1731 if (!settings || !settings->arePluginsEnabled() || | |
| 1732 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMETyp
e(mimeType))) | |
| 1733 return false; | |
| 1734 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramVal
ues, useFallback); | |
| 1735 } | |
| 1736 | |
| 1737 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagNa
me(embedTag)); | |
| 1738 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node(
)); | |
| 1739 | |
| 1740 // FIXME: OK to always make a new frame? When does the old frame get removed
? | |
| 1741 return loadSubframe(element, completedURL, frameName, m_outgoingReferrer); | |
| 1742 } | |
| 1743 | |
| 1744 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool
hasFallback, bool& useFallback) | |
| 1745 { | |
| 1746 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif"
|| mimeType == "image/x-tiff")) { | |
| 1747 String pluginName = m_frame->page()->pluginData()->pluginNameForMimeType
(mimeType); | |
| 1748 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false)) | |
| 1749 return true; | |
| 1750 } | |
| 1751 | |
| 1752 ObjectContentType objectType = m_client->objectContentType(url, mimeType); | |
| 1753 // If an object's content can't be handled and it has no fallback, let | |
| 1754 // it be handled as a plugin to show the broken plugin icon. | |
| 1755 useFallback = objectType == ObjectContentNone && hasFallback; | |
| 1756 return objectType == ObjectContentNone || objectType == ObjectContentNetscap
ePlugin || objectType == ObjectContentOtherPlugin; | |
| 1757 } | |
| 1758 | |
| 1759 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String
& mimeType, | |
| 1760 const Vector<String>& paramNames, const Vector<String>& paramValues, bool us
eFallback) | |
| 1761 { | |
| 1762 Widget* widget = 0; | |
| 1763 | |
| 1764 if (renderer && !useFallback) { | |
| 1765 Element* pluginElement = 0; | |
| 1766 if (renderer->node() && renderer->node()->isElementNode()) | |
| 1767 pluginElement = static_cast<Element*>(renderer->node()); | |
| 1768 | |
| 1769 if (!canLoad(url, String(), frame()->document())) { | |
| 1770 FrameLoader::reportLocalLoadFailed(m_frame, url.string()); | |
| 1771 return false; | |
| 1772 } | |
| 1773 | |
| 1774 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), render
er->contentHeight()), | |
| 1775 pluginElement, url, paramNames, paramVal
ues, mimeType, | |
| 1776 m_frame->document()->isPluginDocument())
; | |
| 1777 if (widget) { | |
| 1778 renderer->setWidget(widget); | |
| 1779 m_containsPlugIns = true; | |
| 1780 } | |
| 1781 } | |
| 1782 | |
| 1783 return widget != 0; | |
| 1784 } | |
| 1785 | |
| 1786 void FrameLoader::clearRecordedFormValues() | |
| 1787 { | |
| 1788 m_formAboutToBeSubmitted = 0; | |
| 1789 m_formValuesAboutToBeSubmitted.clear(); | |
| 1790 } | |
| 1791 | |
| 1792 void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element) | |
| 1793 { | |
| 1794 m_formAboutToBeSubmitted = element; | |
| 1795 } | |
| 1796 | |
| 1797 void FrameLoader::recordFormValue(const String& name, const String& value) | |
| 1798 { | |
| 1799 m_formValuesAboutToBeSubmitted.set(name, value); | |
| 1800 } | |
| 1801 | |
| 1802 void FrameLoader::parentCompleted() | |
| 1803 { | |
| 1804 if (m_scheduledRedirection && !m_redirectionTimer.isActive()) | |
| 1805 startRedirectionTimer(); | |
| 1806 } | |
| 1807 | |
| 1808 String FrameLoader::outgoingReferrer() const | |
| 1809 { | |
| 1810 return m_outgoingReferrer; | |
| 1811 } | |
| 1812 | |
| 1813 Frame* FrameLoader::opener() | |
| 1814 { | |
| 1815 return m_opener; | |
| 1816 } | |
| 1817 | |
| 1818 void FrameLoader::setOpener(Frame* opener) | |
| 1819 { | |
| 1820 if (m_opener) | |
| 1821 m_opener->loader()->m_openedFrames.remove(m_frame); | |
| 1822 if (opener) | |
| 1823 opener->loader()->m_openedFrames.add(m_frame); | |
| 1824 m_opener = opener; | |
| 1825 | |
| 1826 if (m_frame->document()) { | |
| 1827 m_frame->document()->initSecurityContext(); | |
| 1828 m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOri
gin()); | |
| 1829 } | |
| 1830 } | |
| 1831 | |
| 1832 bool FrameLoader::openedByDOM() const | |
| 1833 { | |
| 1834 return m_openedByDOM; | |
| 1835 } | |
| 1836 | |
| 1837 void FrameLoader::setOpenedByDOM() | |
| 1838 { | |
| 1839 m_openedByDOM = true; | |
| 1840 } | |
| 1841 | |
| 1842 void FrameLoader::handleFallbackContent() | |
| 1843 { | |
| 1844 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); | |
| 1845 if (!owner || !owner->hasTagName(objectTag)) | |
| 1846 return; | |
| 1847 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent(); | |
| 1848 } | |
| 1849 | |
| 1850 void FrameLoader::provisionalLoadStarted() | |
| 1851 { | |
| 1852 Page* page = m_frame->page(); | |
| 1853 | |
| 1854 // this is used to update the current history item | |
| 1855 // in the event of a navigation aytime during loading | |
| 1856 m_navigationDuringLoad = false; | |
| 1857 if (page) { | |
| 1858 Document *document = page->mainFrame()->document(); | |
| 1859 m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (
document && document->processingLoadEvent()); | |
| 1860 } | |
| 1861 | |
| 1862 m_firstLayoutDone = false; | |
| 1863 cancelRedirection(true); | |
| 1864 m_client->provisionalLoadStarted(); | |
| 1865 } | |
| 1866 | |
| 1867 bool FrameLoader::userGestureHint() | |
| 1868 { | |
| 1869 Frame* rootFrame = m_frame; | |
| 1870 while (rootFrame->tree()->parent()) | |
| 1871 rootFrame = rootFrame->tree()->parent(); | |
| 1872 | |
| 1873 if (rootFrame->script()->isEnabled()) | |
| 1874 return rootFrame->script()->processingUserGesture(); | |
| 1875 | |
| 1876 return true; // If JavaScript is disabled, a user gesture must have initiate
d the navigation | |
| 1877 } | |
| 1878 | |
| 1879 void FrameLoader::didNotOpenURL(const KURL& url) | |
| 1880 { | |
| 1881 if (m_submittedFormURL == url) | |
| 1882 m_submittedFormURL = KURL(); | |
| 1883 } | |
| 1884 | |
| 1885 void FrameLoader::resetMultipleFormSubmissionProtection() | |
| 1886 { | |
| 1887 m_submittedFormURL = KURL(); | |
| 1888 } | |
| 1889 | |
| 1890 void FrameLoader::setEncoding(const String& name, bool userChosen) | |
| 1891 { | |
| 1892 if (!m_workingURL.isEmpty()) | |
| 1893 receivedFirstData(); | |
| 1894 m_encoding = name; | |
| 1895 m_encodingWasChosenByUser = userChosen; | |
| 1896 } | |
| 1897 | |
| 1898 void FrameLoader::addData(const char* bytes, int length) | |
| 1899 { | |
| 1900 ASSERT(m_workingURL.isEmpty()); | |
| 1901 ASSERT(m_frame->document()); | |
| 1902 ASSERT(m_frame->document()->parsing()); | |
| 1903 write(bytes, length); | |
| 1904 } | |
| 1905 | |
| 1906 bool FrameLoader::canCachePage() | |
| 1907 { | |
| 1908 // Cache the page, if possible. | |
| 1909 // Don't write to the cache if in the middle of a redirect, since we will wa
nt to | |
| 1910 // store the final page we end up on. | |
| 1911 // No point writing to the cache on a reload or loadSame, since we will just
write | |
| 1912 // over it again when we leave that page. | |
| 1913 // FIXME: <rdar://problem/4886592> - We should work out the complexities of
caching pages with frames as they | |
| 1914 // are the most interesting pages on the web, and often those that would ben
efit the most from caching! | |
| 1915 FrameLoadType loadType = this->loadType(); | |
| 1916 | |
| 1917 return m_documentLoader | |
| 1918 && m_documentLoader->mainDocumentError().isNull() | |
| 1919 && !m_frame->tree()->childCount() | |
| 1920 && !m_frame->tree()->parent() | |
| 1921 // FIXME: If we ever change this so that pages with plug-ins will be cac
hed, | |
| 1922 // we need to make sure that we don't cache pages that have outstanding
NPObjects | |
| 1923 // (objects created by the plug-in). Since there is no way to pause/resu
me a Netscape plug-in, | |
| 1924 // they would need to be destroyed and then recreated, and there is no w
ay that we can recreate | |
| 1925 // the right NPObjects. See <rdar://problem/5197041> for more informatio
n. | |
| 1926 && !m_containsPlugIns | |
| 1927 && !m_URL.protocolIs("https") | |
| 1928 && m_frame->document() | |
| 1929 && !m_frame->document()->hasWindowEventListener(unloadEvent) | |
| 1930 #if ENABLE(DATABASE) | |
| 1931 && !m_frame->document()->hasOpenDatabases() | |
| 1932 #endif | |
| 1933 && m_frame->page() | |
| 1934 && m_frame->page()->backForwardList()->enabled() | |
| 1935 && m_frame->page()->backForwardList()->capacity() > 0 | |
| 1936 && m_frame->page()->settings()->usesPageCache() | |
| 1937 && m_currentHistoryItem | |
| 1938 && !isQuickRedirectComing() | |
| 1939 && loadType != FrameLoadTypeReload | |
| 1940 && loadType != FrameLoadTypeReloadAllowingStaleData | |
| 1941 && loadType != FrameLoadTypeSame | |
| 1942 && !m_documentLoader->isLoadingInAPISense() | |
| 1943 && !m_documentLoader->isStopping() | |
| 1944 #if ENABLE(OFFLINE_WEB_APPLICATIONS) | |
| 1945 // FIXME: We should investigating caching pages that have an associated | |
| 1946 // application cache. <rdar://problem/5917899> tracks that work. | |
| 1947 && !m_documentLoader->applicationCache() | |
| 1948 && !m_documentLoader->candidateApplicationCacheGroup() | |
| 1949 #endif | |
| 1950 ; | |
| 1951 } | |
| 1952 | |
| 1953 void FrameLoader::updatePolicyBaseURL() | |
| 1954 { | |
| 1955 if (m_frame->tree()->parent() && m_frame->tree()->parent()->document()) | |
| 1956 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL())
; | |
| 1957 else | |
| 1958 setPolicyBaseURL(m_URL); | |
| 1959 } | |
| 1960 | |
| 1961 void FrameLoader::setPolicyBaseURL(const KURL& url) | |
| 1962 { | |
| 1963 if (m_frame->document()) | |
| 1964 m_frame->document()->setPolicyBaseURL(url); | |
| 1965 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
| 1966 child->loader()->setPolicyBaseURL(url); | |
| 1967 } | |
| 1968 | |
| 1969 // This does the same kind of work that didOpenURL does, except it relies on the
fact | |
| 1970 // that a higher level already checked that the URLs match and the scrolling is
the right thing to do. | |
| 1971 void FrameLoader::scrollToAnchor(const KURL& url) | |
| 1972 { | |
| 1973 m_URL = url; | |
| 1974 updateHistoryForAnchorScroll(); | |
| 1975 | |
| 1976 // If we were in the autoscroll/panScroll mode we want to stop it before fol
lowing the link to the anchor | |
| 1977 m_frame->eventHandler()->stopAutoscrollTimer(); | |
| 1978 started(); | |
| 1979 gotoAnchor(); | |
| 1980 | |
| 1981 // It's important to model this as a load that starts and immediately finish
es. | |
| 1982 // Otherwise, the parent frame may think we never finished loading. | |
| 1983 m_isComplete = false; | |
| 1984 checkCompleted(); | |
| 1985 } | |
| 1986 | |
| 1987 bool FrameLoader::isComplete() const | |
| 1988 { | |
| 1989 return m_isComplete; | |
| 1990 } | |
| 1991 | |
| 1992 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection) | |
| 1993 { | |
| 1994 ASSERT(m_frame->page()); | |
| 1995 | |
| 1996 stopRedirectionTimer(); | |
| 1997 m_scheduledRedirection.set(redirection); | |
| 1998 if (!m_isComplete && redirection->type != ScheduledRedirection::redirection) | |
| 1999 completed(); | |
| 2000 if (m_isComplete || redirection->type != ScheduledRedirection::redirection) | |
| 2001 startRedirectionTimer(); | |
| 2002 } | |
| 2003 | |
| 2004 void FrameLoader::startRedirectionTimer() | |
| 2005 { | |
| 2006 ASSERT(m_frame->page()); | |
| 2007 ASSERT(m_scheduledRedirection); | |
| 2008 | |
| 2009 m_redirectionTimer.stop(); | |
| 2010 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay); | |
| 2011 | |
| 2012 switch (m_scheduledRedirection->type) { | |
| 2013 case ScheduledRedirection::redirection: | |
| 2014 case ScheduledRedirection::locationChange: | |
| 2015 case ScheduledRedirection::locationChangeDuringLoad: | |
| 2016 clientRedirected(KURL(m_scheduledRedirection->url), | |
| 2017 m_scheduledRedirection->delay, | |
| 2018 currentTime() + m_redirectionTimer.nextFireInterval(), | |
| 2019 m_scheduledRedirection->lockHistory, | |
| 2020 m_isExecutingJavaScriptFormAction); | |
| 2021 return; | |
| 2022 case ScheduledRedirection::reload: | |
| 2023 case ScheduledRedirection::historyNavigation: | |
| 2024 // Don't report history navigations. | |
| 2025 return; | |
| 2026 } | |
| 2027 ASSERT_NOT_REACHED(); | |
| 2028 } | |
| 2029 | |
| 2030 void FrameLoader::stopRedirectionTimer() | |
| 2031 { | |
| 2032 if (!m_redirectionTimer.isActive()) | |
| 2033 return; | |
| 2034 | |
| 2035 m_redirectionTimer.stop(); | |
| 2036 | |
| 2037 if (m_scheduledRedirection) { | |
| 2038 switch (m_scheduledRedirection->type) { | |
| 2039 case ScheduledRedirection::redirection: | |
| 2040 case ScheduledRedirection::locationChange: | |
| 2041 case ScheduledRedirection::locationChangeDuringLoad: | |
| 2042 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress
); | |
| 2043 return; | |
| 2044 case ScheduledRedirection::reload: | |
| 2045 case ScheduledRedirection::historyNavigation: | |
| 2046 // Don't report history navigations. | |
| 2047 return; | |
| 2048 } | |
| 2049 ASSERT_NOT_REACHED(); | |
| 2050 } | |
| 2051 } | |
| 2052 | |
| 2053 void FrameLoader::completed() | |
| 2054 { | |
| 2055 RefPtr<Frame> protect(m_frame); | |
| 2056 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
| 2057 child->loader()->parentCompleted(); | |
| 2058 if (Frame* parent = m_frame->tree()->parent()) | |
| 2059 parent->loader()->checkCompleted(); | |
| 2060 submitFormAgain(); | |
| 2061 } | |
| 2062 | |
| 2063 void FrameLoader::started() | |
| 2064 { | |
| 2065 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent()) | |
| 2066 frame->loader()->m_isComplete = false; | |
| 2067 } | |
| 2068 | |
| 2069 bool FrameLoader::containsPlugins() const | |
| 2070 { | |
| 2071 return m_containsPlugIns; | |
| 2072 } | |
| 2073 | |
| 2074 void FrameLoader::prepareForLoadStart() | |
| 2075 { | |
| 2076 if (Page* page = m_frame->page()) | |
| 2077 page->progress()->progressStarted(m_frame); | |
| 2078 m_client->dispatchDidStartProvisionalLoad(); | |
| 2079 } | |
| 2080 | |
| 2081 void FrameLoader::setupForReplace() | |
| 2082 { | |
| 2083 setState(FrameStateProvisional); | |
| 2084 m_provisionalDocumentLoader = m_documentLoader; | |
| 2085 m_documentLoader = 0; | |
| 2086 detachChildren(); | |
| 2087 } | |
| 2088 | |
| 2089 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType) | |
| 2090 { | |
| 2091 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType); | |
| 2092 } | |
| 2093 | |
| 2094 void FrameLoader::loadFrameRequestWithFormState(const FrameLoadRequest& request,
bool lockHistory, Event* event, PassRefPtr<FormState> prpFormState) | |
| 2095 { | |
| 2096 RefPtr<FormState> formState = prpFormState; | |
| 2097 KURL url = request.resourceRequest().url(); | |
| 2098 | |
| 2099 String referrer; | |
| 2100 String argsReferrer = request.resourceRequest().httpReferrer(); | |
| 2101 if (!argsReferrer.isEmpty()) | |
| 2102 referrer = argsReferrer; | |
| 2103 else | |
| 2104 referrer = m_outgoingReferrer; | |
| 2105 | |
| 2106 ASSERT(frame()->document()); | |
| 2107 if (url.protocolIs("file")) { | |
| 2108 if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referr
er)) { | |
| 2109 FrameLoader::reportLocalLoadFailed(m_frame, url.string()); | |
| 2110 return; | |
| 2111 } | |
| 2112 } | |
| 2113 | |
| 2114 if (shouldHideReferrer(url, referrer)) | |
| 2115 referrer = String(); | |
| 2116 | |
| 2117 Frame* targetFrame = findFrameForNavigation(request.frameName()); | |
| 2118 | |
| 2119 if (request.resourceRequest().httpMethod() != "POST") { | |
| 2120 FrameLoadType loadType; | |
| 2121 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData) | |
| 2122 loadType = FrameLoadTypeReload; | |
| 2123 else if (lockHistory) | |
| 2124 loadType = FrameLoadTypeRedirectWithLockedHistory; | |
| 2125 else | |
| 2126 loadType = FrameLoadTypeStandard; | |
| 2127 | |
| 2128 loadURL(request.resourceRequest().url(), referrer, request.frameName(),
loadType, | |
| 2129 event, formState.release()); | |
| 2130 } else | |
| 2131 loadPostRequest(request.resourceRequest(), referrer, request.frameName()
, event, formState.release()); | |
| 2132 | |
| 2133 if (targetFrame && targetFrame != m_frame) | |
| 2134 if (Page* page = targetFrame->page()) | |
| 2135 page->chrome()->focus(); | |
| 2136 } | |
| 2137 | |
| 2138 | |
| 2139 void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& requ
est, bool lockHistory, Event* event, | |
| 2140 HTMLFormElement* submitForm, const HashMap<String, String>& formValues) | |
| 2141 { | |
| 2142 RefPtr<FormState> formState; | |
| 2143 if (submitForm && !formValues.isEmpty()) | |
| 2144 formState = FormState::create(submitForm, formValues, m_frame); | |
| 2145 | |
| 2146 loadFrameRequestWithFormState(request, lockHistory, event, formState.release
()); | |
| 2147 } | |
| 2148 | |
| 2149 | |
| 2150 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
ng& frameName, FrameLoadType newLoadType, | |
| 2151 Event* event, PassRefPtr<FormState> prpFormState) | |
| 2152 { | |
| 2153 RefPtr<FormState> formState = prpFormState; | |
| 2154 bool isFormSubmission = formState; | |
| 2155 | |
| 2156 ResourceRequest request(newURL); | |
| 2157 if (!referrer.isEmpty()) | |
| 2158 request.setHTTPReferrer(referrer); | |
| 2159 addExtraFieldsToRequest(request, true, event || isFormSubmission); | |
| 2160 if (newLoadType == FrameLoadTypeReload) | |
| 2161 request.setCachePolicy(ReloadIgnoringCacheData); | |
| 2162 | |
| 2163 ASSERT(newLoadType != FrameLoadTypeSame); | |
| 2164 | |
| 2165 NavigationAction action(newURL, newLoadType, isFormSubmission, event); | |
| 2166 | |
| 2167 if (!frameName.isEmpty()) { | |
| 2168 if (Frame* targetFrame = findFrameForNavigation(frameName)) | |
| 2169 targetFrame->loader()->loadURL(newURL, referrer, String(), newLoadTy
pe, event, formState); | |
| 2170 else | |
| 2171 checkNewWindowPolicy(action, request, formState, frameName); | |
| 2172 return; | |
| 2173 } | |
| 2174 | |
| 2175 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; | |
| 2176 | |
| 2177 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL); | |
| 2178 | |
| 2179 // Make sure to do scroll to anchor processing even if the URL is | |
| 2180 // exactly the same so pages with '#' links and DHTML side effects | |
| 2181 // work properly. | |
| 2182 if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) { | |
| 2183 oldDocumentLoader->setTriggeringAction(action); | |
| 2184 stopPolicyCheck(); | |
| 2185 checkNavigationPolicy(request, oldDocumentLoader.get(), formState, | |
| 2186 callContinueFragmentScrollAfterNavigationPolicy, this); | |
| 2187 } else { | |
| 2188 // must grab this now, since this load may stop the previous load and cl
ear this flag | |
| 2189 bool isRedirect = m_quickRedirectComing; | |
| 2190 loadWithNavigationAction(request, action, newLoadType, formState); | |
| 2191 if (isRedirect) { | |
| 2192 m_quickRedirectComing = false; | |
| 2193 if (m_provisionalDocumentLoader) | |
| 2194 m_provisionalDocumentLoader->setIsClientRedirect(true); | |
| 2195 } else if (sameURL) | |
| 2196 // Example of this case are sites that reload the same URL with a di
fferent cookie | |
| 2197 // driving the generated content, or a master frame with links that
drive a target | |
| 2198 // frame, where the user has clicked on the same link repeatedly. | |
| 2199 // But if the load type is FrameLoadTypeReloadAllowingStaleData, whi
ch means the frame | |
| 2200 // is reloaded only because user select one encoding from encoding m
enu, so we do not | |
| 2201 // change the load type. | |
| 2202 if (m_loadType != FrameLoadTypeReloadAllowingStaleData) | |
| 2203 m_loadType = FrameLoadTypeSame; | |
| 2204 } | |
| 2205 } | |
| 2206 | |
| 2207 void FrameLoader::load(const ResourceRequest& request) | |
| 2208 { | |
| 2209 load(request, SubstituteData()); | |
| 2210 } | |
| 2211 | |
| 2212 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& sub
stituteData) | |
| 2213 { | |
| 2214 if (m_inStopAllLoaders) | |
| 2215 return; | |
| 2216 | |
| 2217 // FIXME: is this the right place to reset loadType? Perhaps this should be
done after loading is finished or aborted. | |
| 2218 m_loadType = FrameLoadTypeStandard; | |
| 2219 load(m_client->createDocumentLoader(request, substituteData).get()); | |
| 2220 } | |
| 2221 | |
| 2222 void FrameLoader::load(const ResourceRequest& request, const String& frameName) | |
| 2223 { | |
| 2224 if (frameName.isEmpty()) { | |
| 2225 load(request); | |
| 2226 return; | |
| 2227 } | |
| 2228 | |
| 2229 Frame* frame = findFrameForNavigation(frameName); | |
| 2230 if (frame) { | |
| 2231 frame->loader()->load(request); | |
| 2232 return; | |
| 2233 } | |
| 2234 | |
| 2235 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), r
equest, 0, frameName); | |
| 2236 } | |
| 2237 | |
| 2238 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const
NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState) | |
| 2239 { | |
| 2240 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, Subs
tituteData()); | |
| 2241 | |
| 2242 loader->setTriggeringAction(action); | |
| 2243 if (m_documentLoader) { | |
| 2244 // if the load type is not FrameLoadTypeReloadAllowingStaleData, | |
| 2245 // which means we will load page by user action, so we need not | |
| 2246 // use original encoding override. | |
| 2247 if (type == FrameLoadTypeReloadAllowingStaleData) | |
| 2248 loader->setOverrideEncoding(m_documentLoader->overrideEncoding()); | |
| 2249 else | |
| 2250 loader->setOverrideEncoding(String()); | |
| 2251 } | |
| 2252 | |
| 2253 loadWithDocumentLoader(loader.get(), type, formState); | |
| 2254 } | |
| 2255 | |
| 2256 void FrameLoader::load(DocumentLoader* newDocumentLoader) | |
| 2257 { | |
| 2258 ResourceRequest& r = newDocumentLoader->request(); | |
| 2259 addExtraFieldsToRequest(r, true, false); | |
| 2260 FrameLoadType type; | |
| 2261 | |
| 2262 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url()
)) { | |
| 2263 r.setCachePolicy(ReloadIgnoringCacheData); | |
| 2264 type = FrameLoadTypeSame; | |
| 2265 } else | |
| 2266 type = FrameLoadTypeStandard; | |
| 2267 | |
| 2268 // Do not use original encoding override since it is not loaded by user | |
| 2269 // selecting encoding. | |
| 2270 if (m_documentLoader) | |
| 2271 newDocumentLoader->setOverrideEncoding(String()); | |
| 2272 | |
| 2273 // When we loading alternate content for an unreachable URL that we're | |
| 2274 // visiting in the history list, we treat it as a reload so the history list
| |
| 2275 // is appropriately maintained. | |
| 2276 // | |
| 2277 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLo
adTypeReload" ... | |
| 2278 // shouldn't a more explicit type of reload be defined, that means roughly | |
| 2279 // "load without affecting history" ? | |
| 2280 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) { | |
| 2281 ASSERT(type == FrameLoadTypeStandard); | |
| 2282 type = FrameLoadTypeReload; | |
| 2283 } | |
| 2284 | |
| 2285 loadWithDocumentLoader(newDocumentLoader, type, 0); | |
| 2286 } | |
| 2287 | |
| 2288 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
ype, PassRefPtr<FormState> prpFormState) | |
| 2289 { | |
| 2290 ASSERT(m_client->hasWebView()); | |
| 2291 | |
| 2292 // Unfortunately the view must be non-nil, this is ultimately due | |
| 2293 // to parser requiring a FrameView. We should fix this dependency. | |
| 2294 | |
| 2295 ASSERT(m_client->hasFrameView()); | |
| 2296 | |
| 2297 m_policyLoadType = type; | |
| 2298 RefPtr<FormState> formState = prpFormState; | |
| 2299 bool isFormSubmission = formState; | |
| 2300 | |
| 2301 const KURL& newURL = loader->request().url(); | |
| 2302 | |
| 2303 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) { | |
| 2304 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; | |
| 2305 NavigationAction action(newURL, m_policyLoadType, isFormSubmission); | |
| 2306 | |
| 2307 oldDocumentLoader->setTriggeringAction(action); | |
| 2308 stopPolicyCheck(); | |
| 2309 checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formSt
ate, | |
| 2310 callContinueFragmentScrollAfterNavigationPolicy, this); | |
| 2311 } else { | |
| 2312 if (Frame* parent = m_frame->tree()->parent()) { | |
| 2313 if (type == FrameLoadTypeReloadAllowingStaleData) | |
| 2314 loader->setOverrideEncoding(parent->loader()->documentLoader()->
overrideEncoding()); | |
| 2315 else | |
| 2316 loader->setOverrideEncoding(String()); | |
| 2317 } | |
| 2318 | |
| 2319 stopPolicyCheck(); | |
| 2320 setPolicyDocumentLoader(loader); | |
| 2321 | |
| 2322 checkNavigationPolicy(loader->request(), loader, formState, | |
| 2323 callContinueLoadAfterNavigationPolicy, this); | |
| 2324 } | |
| 2325 } | |
| 2326 | |
| 2327 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Documen
t* doc) | |
| 2328 { | |
| 2329 // We can always load any URL that isn't considered local (e.g. http URLs) | |
| 2330 if (!shouldTreatURLAsLocal(url.string())) | |
| 2331 return true; | |
| 2332 | |
| 2333 // If we were provided a document, we let its local file policy dictate the
result, | |
| 2334 // otherwise we allow local loads only if the supplied referrer is also loca
l. | |
| 2335 if (doc) | |
| 2336 return doc->securityOrigin()->canLoadLocalResources(); | |
| 2337 else if (!referrer.isEmpty()) | |
| 2338 return shouldTreatURLAsLocal(referrer); | |
| 2339 else | |
| 2340 return false; | |
| 2341 } | |
| 2342 | |
| 2343 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) | |
| 2344 { | |
| 2345 ASSERT(!url.isEmpty()); | |
| 2346 if (!frame) | |
| 2347 return; | |
| 2348 | |
| 2349 frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel
, "Not allowed to load local resource: " + url, 0, String()); | |
| 2350 } | |
| 2351 | |
| 2352 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer) | |
| 2353 { | |
| 2354 bool referrerIsSecureURL = protocolIs(referrer, "https"); | |
| 2355 bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http"); | |
| 2356 | |
| 2357 if (!referrerIsWebURL) | |
| 2358 return true; | |
| 2359 | |
| 2360 if (!referrerIsSecureURL) | |
| 2361 return false; | |
| 2362 | |
| 2363 bool URLIsSecureURL = url.protocolIs("https"); | |
| 2364 | |
| 2365 return !URLIsSecureURL; | |
| 2366 } | |
| 2367 | |
| 2368 const ResourceRequest& FrameLoader::initialRequest() const | |
| 2369 { | |
| 2370 return activeDocumentLoader()->originalRequest(); | |
| 2371 } | |
| 2372 | |
| 2373 void FrameLoader::receivedData(const char* data, int length) | |
| 2374 { | |
| 2375 activeDocumentLoader()->receivedData(data, length); | |
| 2376 } | |
| 2377 | |
| 2378 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error) | |
| 2379 { | |
| 2380 m_delegateIsHandlingUnimplementablePolicy = true; | |
| 2381 m_client->dispatchUnableToImplementPolicy(error); | |
| 2382 m_delegateIsHandlingUnimplementablePolicy = false; | |
| 2383 } | |
| 2384 | |
| 2385 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response) | |
| 2386 { | |
| 2387 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response)); | |
| 2388 } | |
| 2389 | |
| 2390 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceReques
t& request) | |
| 2391 { | |
| 2392 return m_client->interruptForPolicyChangeError(request); | |
| 2393 } | |
| 2394 | |
| 2395 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, Navig
ationPolicyDecisionFunction function, void* argument) | |
| 2396 { | |
| 2397 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argum
ent); | |
| 2398 } | |
| 2399 | |
| 2400 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisi
onFunction function, void* argument) | |
| 2401 { | |
| 2402 ASSERT(activeDocumentLoader()); | |
| 2403 | |
| 2404 // Always show content with valid substitute data. | |
| 2405 if (activeDocumentLoader()->substituteData().isValid()) { | |
| 2406 function(argument, PolicyUse); | |
| 2407 return; | |
| 2408 } | |
| 2409 | |
| 2410 #if ENABLE(FTPDIR) | |
| 2411 // Respect the hidden FTP Directory Listing pref so it can be tested even if
the policy delegate might otherwise disallow it | |
| 2412 Settings* settings = m_frame->settings(); | |
| 2413 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "applic
ation/x-ftp-directory") { | |
| 2414 function(argument, PolicyUse); | |
| 2415 return; | |
| 2416 } | |
| 2417 #endif | |
| 2418 | |
| 2419 m_policyCheck.set(function, argument); | |
| 2420 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContent
Policy, | |
| 2421 MIMEType, activeDocumentLoader()->request()); | |
| 2422 } | |
| 2423 | |
| 2424 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) | |
| 2425 { | |
| 2426 KURL unreachableURL = docLoader->unreachableURL(); | |
| 2427 | |
| 2428 if (unreachableURL.isEmpty()) | |
| 2429 return false; | |
| 2430 | |
| 2431 if (!isBackForwardLoadType(m_policyLoadType)) | |
| 2432 return false; | |
| 2433 | |
| 2434 // We only treat unreachableURLs specially during the delegate callbacks | |
| 2435 // for provisional load errors and navigation policy decisions. The former | |
| 2436 // case handles well-formed URLs that can't be loaded, and the latter | |
| 2437 // case handles malformed URLs and unknown schemes. Loading alternate conten
t | |
| 2438 // at other times behaves like a standard load. | |
| 2439 DocumentLoader* compareDocumentLoader = 0; | |
| 2440 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementa
blePolicy) | |
| 2441 compareDocumentLoader = m_policyDocumentLoader.get(); | |
| 2442 else if (m_delegateIsHandlingProvisionalLoadError) | |
| 2443 compareDocumentLoader = m_provisionalDocumentLoader.get(); | |
| 2444 | |
| 2445 return compareDocumentLoader && unreachableURL == compareDocumentLoader->req
uest().url(); | |
| 2446 } | |
| 2447 | |
| 2448 void FrameLoader::reloadAllowingStaleData(const String& encoding) | |
| 2449 { | |
| 2450 if (!m_documentLoader) | |
| 2451 return; | |
| 2452 | |
| 2453 ResourceRequest request = m_documentLoader->request(); | |
| 2454 KURL unreachableURL = m_documentLoader->unreachableURL(); | |
| 2455 if (!unreachableURL.isEmpty()) | |
| 2456 request.setURL(unreachableURL); | |
| 2457 | |
| 2458 request.setCachePolicy(ReturnCacheDataElseLoad); | |
| 2459 | |
| 2460 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, Subs
tituteData()); | |
| 2461 setPolicyDocumentLoader(loader.get()); | |
| 2462 | |
| 2463 loader->setOverrideEncoding(encoding); | |
| 2464 | |
| 2465 loadWithDocumentLoader(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0
); | |
| 2466 } | |
| 2467 | |
| 2468 void FrameLoader::reload() | |
| 2469 { | |
| 2470 if (!m_documentLoader) | |
| 2471 return; | |
| 2472 | |
| 2473 ResourceRequest& initialRequest = m_documentLoader->request(); | |
| 2474 | |
| 2475 // If a window is created by javascript, its main frame can have an empty bu
t non-nil URL. | |
| 2476 // Reloading in this case will lose the current contents (see 4151001). | |
| 2477 if (initialRequest.url().isEmpty()) | |
| 2478 return; | |
| 2479 | |
| 2480 // Replace error-page URL with the URL we were trying to reach. | |
| 2481 KURL unreachableURL = m_documentLoader->unreachableURL(); | |
| 2482 if (!unreachableURL.isEmpty()) | |
| 2483 initialRequest.setURL(unreachableURL); | |
| 2484 | |
| 2485 // Create a new document loader for the reload, this will become m_documentL
oader eventually, | |
| 2486 // but first it has to be the "policy" document loader, and then the "provis
ional" document loader. | |
| 2487 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialReques
t, SubstituteData()); | |
| 2488 | |
| 2489 ResourceRequest& request = loader->request(); | |
| 2490 | |
| 2491 request.setCachePolicy(ReloadIgnoringCacheData); | |
| 2492 request.setHTTPHeaderField("Cache-Control", "max-age=0"); | |
| 2493 | |
| 2494 // If we're about to re-post, set up action so the application can warn the
user. | |
| 2495 if (request.httpMethod() == "POST") | |
| 2496 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTy
peFormResubmitted)); | |
| 2497 | |
| 2498 loader->setOverrideEncoding(String()); | |
| 2499 | |
| 2500 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0); | |
| 2501 } | |
| 2502 | |
| 2503 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const | |
| 2504 { | |
| 2505 // The navigation change is safe if the active frame is: | |
| 2506 // - in the same security origin as the target or one of the target's ance
stors | |
| 2507 // Or the target frame is: | |
| 2508 // - a top-level frame in the frame hierarchy | |
| 2509 | |
| 2510 if (!targetFrame) | |
| 2511 return true; | |
| 2512 | |
| 2513 if (m_frame == targetFrame) | |
| 2514 return true; | |
| 2515 | |
| 2516 if (!targetFrame->tree()->parent()) | |
| 2517 return true; | |
| 2518 | |
| 2519 Document* activeDocument = m_frame->document(); | |
| 2520 ASSERT(activeDocument); | |
| 2521 const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin(
); | |
| 2522 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ance
storFrame->tree()->parent()) { | |
| 2523 Document* ancestorDocument = ancestorFrame->document(); | |
| 2524 if (!ancestorDocument) | |
| 2525 return true; | |
| 2526 | |
| 2527 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securit
yOrigin(); | |
| 2528 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin)) | |
| 2529 return true; | |
| 2530 } | |
| 2531 | |
| 2532 Settings* settings = targetFrame->settings(); | |
| 2533 if (settings && !settings->privateBrowsingEnabled()) { | |
| 2534 Document* targetDocument = targetFrame->document(); | |
| 2535 // FIXME: this error message should contain more specifics of why the na
vigation change is not allowed. | |
| 2536 String message = String::format("Unsafe JavaScript attempt to initiate a
navigation change for frame with URL %s from frame with URL %s.\n", | |
| 2537 targetDocument->url().string().utf8().data(), activeDocument->url().
string().utf8().data()); | |
| 2538 | |
| 2539 // FIXME: should we print to the console of the activeFrame as well? | |
| 2540 targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMe
ssageLevel, message, 1, String()); | |
| 2541 } | |
| 2542 | |
| 2543 return false; | |
| 2544 } | |
| 2545 | |
| 2546 void FrameLoader::stopLoadingSubframes() | |
| 2547 { | |
| 2548 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = chi
ld->tree()->nextSibling()) | |
| 2549 child->loader()->stopAllLoaders(); | |
| 2550 } | |
| 2551 | |
| 2552 void FrameLoader::stopAllLoaders() | |
| 2553 { | |
| 2554 // If this method is called from within this method, infinite recursion can
occur (3442218). Avoid this. | |
| 2555 if (m_inStopAllLoaders) | |
| 2556 return; | |
| 2557 | |
| 2558 m_inStopAllLoaders = true; | |
| 2559 | |
| 2560 stopPolicyCheck(); | |
| 2561 | |
| 2562 stopLoadingSubframes(); | |
| 2563 if (m_provisionalDocumentLoader) | |
| 2564 m_provisionalDocumentLoader->stopLoading(); | |
| 2565 if (m_documentLoader) | |
| 2566 m_documentLoader->stopLoading(); | |
| 2567 | |
| 2568 setProvisionalDocumentLoader(0); | |
| 2569 | |
| 2570 if (m_documentLoader) | |
| 2571 m_documentLoader->clearArchiveResources(); | |
| 2572 | |
| 2573 m_inStopAllLoaders = false; | |
| 2574 } | |
| 2575 | |
| 2576 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete) | |
| 2577 { | |
| 2578 stopAllLoaders(); | |
| 2579 | |
| 2580 if (deferCheckLoadComplete) | |
| 2581 scheduleCheckLoadComplete(); | |
| 2582 else if (m_frame->page()) | |
| 2583 checkLoadComplete(); | |
| 2584 } | |
| 2585 | |
| 2586 DocumentLoader* FrameLoader::activeDocumentLoader() const | |
| 2587 { | |
| 2588 if (m_state == FrameStateProvisional) | |
| 2589 return m_provisionalDocumentLoader.get(); | |
| 2590 return m_documentLoader.get(); | |
| 2591 } | |
| 2592 | |
| 2593 bool FrameLoader::isLoading() const | |
| 2594 { | |
| 2595 DocumentLoader* docLoader = activeDocumentLoader(); | |
| 2596 if (!docLoader) | |
| 2597 return false; | |
| 2598 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresource
s() || docLoader->isLoadingPlugIns(); | |
| 2599 } | |
| 2600 | |
| 2601 bool FrameLoader::frameHasLoaded() const | |
| 2602 { | |
| 2603 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !
m_creatingInitialEmptyDocument); | |
| 2604 } | |
| 2605 | |
| 2606 void FrameLoader::setDocumentLoader(DocumentLoader* loader) | |
| 2607 { | |
| 2608 if (!loader && !m_documentLoader) | |
| 2609 return; | |
| 2610 | |
| 2611 ASSERT(loader != m_documentLoader); | |
| 2612 ASSERT(!loader || loader->frameLoader() == this); | |
| 2613 | |
| 2614 m_client->prepareForDataSourceReplacement(); | |
| 2615 detachChildren(); | |
| 2616 if (m_documentLoader) | |
| 2617 m_documentLoader->detachFromFrame(); | |
| 2618 | |
| 2619 m_documentLoader = loader; | |
| 2620 } | |
| 2621 | |
| 2622 DocumentLoader* FrameLoader::documentLoader() const | |
| 2623 { | |
| 2624 return m_documentLoader.get(); | |
| 2625 } | |
| 2626 | |
| 2627 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader) | |
| 2628 { | |
| 2629 if (m_policyDocumentLoader == loader) | |
| 2630 return; | |
| 2631 | |
| 2632 ASSERT(m_frame); | |
| 2633 if (loader) | |
| 2634 loader->setFrame(m_frame); | |
| 2635 if (m_policyDocumentLoader | |
| 2636 && m_policyDocumentLoader != m_provisionalDocumentLoader | |
| 2637 && m_policyDocumentLoader != m_documentLoader) | |
| 2638 m_policyDocumentLoader->detachFromFrame(); | |
| 2639 | |
| 2640 m_policyDocumentLoader = loader; | |
| 2641 } | |
| 2642 | |
| 2643 DocumentLoader* FrameLoader::policyDocumentLoader() const | |
| 2644 { | |
| 2645 return m_policyDocumentLoader.get(); | |
| 2646 } | |
| 2647 | |
| 2648 DocumentLoader* FrameLoader::provisionalDocumentLoader() const | |
| 2649 { | |
| 2650 return m_provisionalDocumentLoader.get(); | |
| 2651 } | |
| 2652 | |
| 2653 DocumentLoader* FrameLoader::policyDocumentLoader() | |
| 2654 { | |
| 2655 return m_policyDocumentLoader.get(); | |
| 2656 } | |
| 2657 | |
| 2658 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader) | |
| 2659 { | |
| 2660 ASSERT(!loader || !m_provisionalDocumentLoader); | |
| 2661 ASSERT(!loader || loader->frameLoader() == this); | |
| 2662 | |
| 2663 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_document
Loader) | |
| 2664 m_provisionalDocumentLoader->detachFromFrame(); | |
| 2665 | |
| 2666 m_provisionalDocumentLoader = loader; | |
| 2667 } | |
| 2668 | |
| 2669 FrameState FrameLoader::state() const | |
| 2670 { | |
| 2671 return m_state; | |
| 2672 } | |
| 2673 | |
| 2674 double FrameLoader::timeOfLastCompletedLoad() | |
| 2675 { | |
| 2676 return storedTimeOfLastCompletedLoad; | |
| 2677 } | |
| 2678 | |
| 2679 void FrameLoader::setState(FrameState newState) | |
| 2680 { | |
| 2681 m_state = newState; | |
| 2682 | |
| 2683 if (newState == FrameStateProvisional) | |
| 2684 provisionalLoadStarted(); | |
| 2685 else if (newState == FrameStateComplete) { | |
| 2686 frameLoadCompleted(); | |
| 2687 storedTimeOfLastCompletedLoad = currentTime(); | |
| 2688 if (m_documentLoader) | |
| 2689 m_documentLoader->stopRecordingResponses(); | |
| 2690 } | |
| 2691 } | |
| 2692 | |
| 2693 void FrameLoader::clearProvisionalLoad() | |
| 2694 { | |
| 2695 setProvisionalDocumentLoader(0); | |
| 2696 if (Page* page = m_frame->page()) | |
| 2697 page->progress()->progressCompleted(m_frame); | |
| 2698 setState(FrameStateComplete); | |
| 2699 } | |
| 2700 | |
| 2701 void FrameLoader::markLoadComplete() | |
| 2702 { | |
| 2703 setState(FrameStateComplete); | |
| 2704 } | |
| 2705 | |
| 2706 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage) | |
| 2707 { | |
| 2708 RefPtr<CachedPage> cachedPage = prpCachedPage; | |
| 2709 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; | |
| 2710 | |
| 2711 // Check to see if we need to cache the page we are navigating away from int
o the back/forward cache. | |
| 2712 // We are doing this here because we know for sure that a new page is about
to be loaded. | |
| 2713 if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isI
nPageCache()) | |
| 2714 cachePageForHistoryItem(m_currentHistoryItem.get()); | |
| 2715 | |
| 2716 if (m_loadType != FrameLoadTypeReplace) | |
| 2717 closeOldDataSources(); | |
| 2718 | |
| 2719 if (!cachedPage && !m_creatingInitialEmptyDocument) | |
| 2720 m_client->makeRepresentation(pdl.get()); | |
| 2721 | |
| 2722 transitionToCommitted(cachedPage); | |
| 2723 | |
| 2724 // Call clientRedirectCancelledOrFinished() here so that the frame load dele
gate is notified that the redirect's | |
| 2725 // status has changed, if there was a redirect. The frame load delegate may
have saved some state about | |
| 2726 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDat
e:forFrame:. Since we are | |
| 2727 // just about to commit a new page, there cannot possibly be a pending redir
ect at this point. | |
| 2728 if (m_sentRedirectNotification) | |
| 2729 clientRedirectCancelledOrFinished(false); | |
| 2730 | |
| 2731 if (cachedPage && cachedPage->document()) { | |
| 2732 open(*cachedPage); | |
| 2733 cachedPage->clear(); | |
| 2734 } else { | |
| 2735 KURL url = pdl->substituteData().responseURL(); | |
| 2736 if (url.isEmpty()) | |
| 2737 url = pdl->url(); | |
| 2738 if (url.isEmpty()) | |
| 2739 url = pdl->responseURL(); | |
| 2740 if (url.isEmpty()) | |
| 2741 url = blankURL(); | |
| 2742 | |
| 2743 didOpenURL(url); | |
| 2744 } | |
| 2745 opened(); | |
| 2746 } | |
| 2747 | |
| 2748 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage) | |
| 2749 { | |
| 2750 ASSERT(m_client->hasWebView()); | |
| 2751 ASSERT(m_state == FrameStateProvisional); | |
| 2752 | |
| 2753 if (m_state != FrameStateProvisional) | |
| 2754 return; | |
| 2755 | |
| 2756 m_client->setCopiesOnScroll(); | |
| 2757 updateHistoryForCommit(); | |
| 2758 | |
| 2759 // The call to closeURL() invokes the unload event handler, which can execut
e arbitrary | |
| 2760 // JavaScript. If the script initiates a new load, we need to abandon the cu
rrent load, | |
| 2761 // or the two will stomp each other. | |
| 2762 DocumentLoader* pdl = m_provisionalDocumentLoader.get(); | |
| 2763 if (m_documentLoader) | |
| 2764 closeURL(); | |
| 2765 if (pdl != m_provisionalDocumentLoader) | |
| 2766 return; | |
| 2767 | |
| 2768 // Nothing else can interupt this commit - set the Provisional->Committed tr
ansition in stone | |
| 2769 if (m_documentLoader) | |
| 2770 m_documentLoader->stopLoadingSubresources(); | |
| 2771 if (m_documentLoader) | |
| 2772 m_documentLoader->stopLoadingPlugIns(); | |
| 2773 | |
| 2774 setDocumentLoader(m_provisionalDocumentLoader.get()); | |
| 2775 setProvisionalDocumentLoader(0); | |
| 2776 setState(FrameStateCommittedPage); | |
| 2777 | |
| 2778 // Handle adding the URL to the back/forward list. | |
| 2779 DocumentLoader* dl = m_documentLoader.get(); | |
| 2780 String ptitle = dl->title(); | |
| 2781 | |
| 2782 switch (m_loadType) { | |
| 2783 case FrameLoadTypeForward: | |
| 2784 case FrameLoadTypeBack: | |
| 2785 case FrameLoadTypeIndexedBackForward: | |
| 2786 if (Page* page = m_frame->page()) | |
| 2787 if (page->backForwardList()) { | |
| 2788 updateHistoryForBackForwardNavigation(); | |
| 2789 | |
| 2790 // Create a document view for this document, or used the cac
hed view. | |
| 2791 if (cachedPage) { | |
| 2792 DocumentLoader* cachedDocumentLoader = cachedPage->docum
entLoader(); | |
| 2793 ASSERT(cachedDocumentLoader); | |
| 2794 cachedDocumentLoader->setFrame(m_frame); | |
| 2795 m_client->transitionToCommittedFromCachedPage(cachedPage
.get()); | |
| 2796 | |
| 2797 } else | |
| 2798 m_client->transitionToCommittedForNewPage(); | |
| 2799 } | |
| 2800 break; | |
| 2801 | |
| 2802 case FrameLoadTypeReload: | |
| 2803 case FrameLoadTypeSame: | |
| 2804 case FrameLoadTypeReplace: | |
| 2805 updateHistoryForReload(); | |
| 2806 m_client->transitionToCommittedForNewPage(); | |
| 2807 break; | |
| 2808 | |
| 2809 // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllow
ingStaleData with the above case | |
| 2810 case FrameLoadTypeReloadAllowingStaleData: | |
| 2811 m_client->transitionToCommittedForNewPage(); | |
| 2812 break; | |
| 2813 | |
| 2814 case FrameLoadTypeStandard: | |
| 2815 updateHistoryForStandardLoad(); | |
| 2816 #ifndef BUILDING_ON_TIGER | |
| 2817 // This code was originally added for a Leopard performance imporvem
ent. We decided to | |
| 2818 // ifdef it to fix correctness issues on Tiger documented in <rdar:/
/problem/5441823>. | |
| 2819 if (m_frame->view()) | |
| 2820 m_frame->view()->suppressScrollbars(true); | |
| 2821 #endif | |
| 2822 m_client->transitionToCommittedForNewPage(); | |
| 2823 break; | |
| 2824 | |
| 2825 case FrameLoadTypeRedirectWithLockedHistory: | |
| 2826 updateHistoryForRedirectWithLockedHistory(); | |
| 2827 m_client->transitionToCommittedForNewPage(); | |
| 2828 break; | |
| 2829 | |
| 2830 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds"
is). | |
| 2831 // An exception should be thrown if we're in the FrameLoadTypeUninitiali
zed state. | |
| 2832 default: | |
| 2833 ASSERT_NOT_REACHED(); | |
| 2834 } | |
| 2835 | |
| 2836 m_responseMIMEType = dl->responseMIMEType(); | |
| 2837 | |
| 2838 // Tell the client we've committed this URL. | |
| 2839 ASSERT(m_client->hasFrameView()); | |
| 2840 | |
| 2841 if (m_creatingInitialEmptyDocument) | |
| 2842 return; | |
| 2843 | |
| 2844 m_committedFirstRealDocumentLoad = true; | |
| 2845 | |
| 2846 // For non-cached HTML pages, these methods are called in FrameLoader::begin
. | |
| 2847 if (cachedPage || !m_client->hasHTMLView()) { | |
| 2848 dispatchDidCommitLoad(); | |
| 2849 | |
| 2850 // If we have a title let the WebView know about it. | |
| 2851 if (!ptitle.isNull()) | |
| 2852 m_client->dispatchDidReceiveTitle(ptitle); | |
| 2853 } | |
| 2854 } | |
| 2855 | |
| 2856 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgres
s) | |
| 2857 { | |
| 2858 // Note that -webView:didCancelClientRedirectForFrame: is called on the fram
e load delegate even if | |
| 2859 // the redirect succeeded. We should either rename this API, or add a new m
ethod, like | |
| 2860 // -webView:didFinishClientRedirectForFrame: | |
| 2861 m_client->dispatchDidCancelClientRedirect(); | |
| 2862 | |
| 2863 if (!cancelWithLoadInProgress) | |
| 2864 m_quickRedirectComing = false; | |
| 2865 | |
| 2866 m_sentRedirectNotification = false; | |
| 2867 } | |
| 2868 | |
| 2869 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireD
ate, bool lockHistory, bool isJavaScriptFormAction) | |
| 2870 { | |
| 2871 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate); | |
| 2872 | |
| 2873 // Remember that we sent a redirect notification to the frame load delegate
so that when we commit | |
| 2874 // the next provisional load, we can send a corresponding -webView:didCancel
ClientRedirectForFrame: | |
| 2875 m_sentRedirectNotification = true; | |
| 2876 | |
| 2877 // If a "quick" redirect comes in an, we set a special mode so we treat the
next | |
| 2878 // load as part of the same navigation. If we don't have a document loader,
we have | |
| 2879 // no "original" load on which to base a redirect, so we treat the redirect
as a normal load. | |
| 2880 m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptForm
Action; | |
| 2881 } | |
| 2882 | |
| 2883 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationUR
L) | |
| 2884 { | |
| 2885 // This function implements the rule: "Don't reload if navigating by fragmen
t within | |
| 2886 // the same URL, but do reload if going to a new URL or to the same URL with
no | |
| 2887 // fragment identifier at all." | |
| 2888 if (!destinationURL.hasRef()) | |
| 2889 return true; | |
| 2890 return !equalIgnoringRef(currentURL, destinationURL); | |
| 2891 } | |
| 2892 | |
| 2893 void FrameLoader::closeOldDataSources() | |
| 2894 { | |
| 2895 // FIXME: Is it important for this traversal to be postorder instead of preo
rder? | |
| 2896 // If so, add helpers for postorder traversal, and use them. If not, then le
ts not | |
| 2897 // use a recursive algorithm here. | |
| 2898 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
| 2899 child->loader()->closeOldDataSources(); | |
| 2900 | |
| 2901 if (m_documentLoader) | |
| 2902 m_client->dispatchWillClose(); | |
| 2903 | |
| 2904 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DO
MDocument to observers | |
| 2905 } | |
| 2906 | |
| 2907 void FrameLoader::open(CachedPage& cachedPage) | |
| 2908 { | |
| 2909 ASSERT(m_frame->page()); | |
| 2910 ASSERT(m_frame->page()->mainFrame() == m_frame); | |
| 2911 | |
| 2912 cancelRedirection(); | |
| 2913 | |
| 2914 // We still have to close the previous part page. | |
| 2915 closeURL(); | |
| 2916 | |
| 2917 m_isComplete = false; | |
| 2918 | |
| 2919 // Don't re-emit the load event. | |
| 2920 m_didCallImplicitClose = true; | |
| 2921 | |
| 2922 // Delete old status bar messages (if it _was_ activated on last URL). | |
| 2923 if (m_frame->script()->isEnabled()) { | |
| 2924 m_frame->setJSStatusBarText(String()); | |
| 2925 m_frame->setJSDefaultStatusBarText(String()); | |
| 2926 } | |
| 2927 | |
| 2928 KURL url = cachedPage.url(); | |
| 2929 | |
| 2930 if ((url.protocolIs("http") || url.protocolIs("https")) && !url.host().isEmp
ty() && url.path().isEmpty()) | |
| 2931 url.setPath("/"); | |
| 2932 | |
| 2933 m_URL = url; | |
| 2934 m_workingURL = url; | |
| 2935 | |
| 2936 started(); | |
| 2937 | |
| 2938 clear(); | |
| 2939 | |
| 2940 Document* document = cachedPage.document(); | |
| 2941 ASSERT(document); | |
| 2942 document->setInPageCache(false); | |
| 2943 | |
| 2944 m_needsClear = true; | |
| 2945 m_isComplete = false; | |
| 2946 m_didCallImplicitClose = false; | |
| 2947 m_outgoingReferrer = url.string(); | |
| 2948 | |
| 2949 FrameView* view = cachedPage.view(); | |
| 2950 if (view) | |
| 2951 view->setWasScrolledByUser(false); | |
| 2952 m_frame->setView(view); | |
| 2953 | |
| 2954 m_frame->setDocument(document); | |
| 2955 m_frame->domWindow()->setURL(document->url()); | |
| 2956 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); | |
| 2957 | |
| 2958 m_decoder = document->decoder(); | |
| 2959 | |
| 2960 updatePolicyBaseURL(); | |
| 2961 | |
| 2962 cachedPage.restore(m_frame->page()); | |
| 2963 | |
| 2964 checkCompleted(); | |
| 2965 } | |
| 2966 | |
| 2967 bool FrameLoader::isStopping() const | |
| 2968 { | |
| 2969 return activeDocumentLoader()->isStopping(); | |
| 2970 } | |
| 2971 | |
| 2972 void FrameLoader::finishedLoading() | |
| 2973 { | |
| 2974 // Retain because the stop may release the last reference to it. | |
| 2975 RefPtr<Frame> protect(m_frame); | |
| 2976 | |
| 2977 RefPtr<DocumentLoader> dl = activeDocumentLoader(); | |
| 2978 dl->finishedLoading(); | |
| 2979 if (!dl->mainDocumentError().isNull() || !dl->frameLoader()) | |
| 2980 return; | |
| 2981 dl->setPrimaryLoadComplete(true); | |
| 2982 m_client->dispatchDidLoadMainResource(dl.get()); | |
| 2983 checkLoadComplete(); | |
| 2984 } | |
| 2985 | |
| 2986 bool FrameLoader::isHostedByObjectElement() const | |
| 2987 { | |
| 2988 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); | |
| 2989 return owner && owner->hasTagName(objectTag); | |
| 2990 } | |
| 2991 | |
| 2992 bool FrameLoader::isLoadingMainFrame() const | |
| 2993 { | |
| 2994 Page* page = m_frame->page(); | |
| 2995 return page && m_frame == page->mainFrame(); | |
| 2996 } | |
| 2997 | |
| 2998 bool FrameLoader::canShowMIMEType(const String& MIMEType) const | |
| 2999 { | |
| 3000 return m_client->canShowMIMEType(MIMEType); | |
| 3001 } | |
| 3002 | |
| 3003 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme) | |
| 3004 { | |
| 3005 return m_client->representationExistsForURLScheme(URLScheme); | |
| 3006 } | |
| 3007 | |
| 3008 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme) | |
| 3009 { | |
| 3010 return m_client->generatedMIMETypeForURLScheme(URLScheme); | |
| 3011 } | |
| 3012 | |
| 3013 void FrameLoader::cancelContentPolicyCheck() | |
| 3014 { | |
| 3015 m_client->cancelPolicyCheck(); | |
| 3016 m_policyCheck.clear(); | |
| 3017 } | |
| 3018 | |
| 3019 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame() | |
| 3020 { | |
| 3021 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad(); | |
| 3022 } | |
| 3023 | |
| 3024 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader) | |
| 3025 { | |
| 3026 #if PLATFORM(WIN) | |
| 3027 if (m_creatingInitialEmptyDocument) | |
| 3028 return; | |
| 3029 #endif | |
| 3030 | |
| 3031 // If loading a webarchive, run through webarchive machinery | |
| 3032 const String& responseMIMEType = loader->responseMIMEType(); | |
| 3033 | |
| 3034 // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that i
s required even with Archive loads | |
| 3035 // so we still need to call it. Other platforms should only call finishLoad
ing for non-archive loads | |
| 3036 // That work should be factored out so this #ifdef can be removed | |
| 3037 #if PLATFORM(MAC) | |
| 3038 m_client->finishedLoading(loader); | |
| 3039 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) | |
| 3040 return; | |
| 3041 #else | |
| 3042 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) { | |
| 3043 m_client->finishedLoading(loader); | |
| 3044 return; | |
| 3045 } | |
| 3046 #endif | |
| 3047 | |
| 3048 RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().ge
t(), responseMIMEType)); | |
| 3049 if (!archive) | |
| 3050 return; | |
| 3051 | |
| 3052 loader->addAllArchiveResources(archive.get()); | |
| 3053 | |
| 3054 ArchiveResource* mainResource = archive->mainResource(); | |
| 3055 loader->setParsedArchiveData(mainResource->data()); | |
| 3056 continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainRes
ource->textEncoding(), mainResource->url()); | |
| 3057 } | |
| 3058 | |
| 3059 bool FrameLoader::isReplacing() const | |
| 3060 { | |
| 3061 return m_loadType == FrameLoadTypeReplace; | |
| 3062 } | |
| 3063 | |
| 3064 void FrameLoader::setReplacing() | |
| 3065 { | |
| 3066 m_loadType = FrameLoadTypeReplace; | |
| 3067 } | |
| 3068 | |
| 3069 void FrameLoader::revertToProvisional(DocumentLoader* loader) | |
| 3070 { | |
| 3071 m_client->revertToProvisionalState(loader); | |
| 3072 } | |
| 3073 | |
| 3074 bool FrameLoader::subframeIsLoading() const | |
| 3075 { | |
| 3076 // It's most likely that the last added frame is the last to load so we walk
backwards. | |
| 3077 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree
()->previousSibling()) { | |
| 3078 FrameLoader* childLoader = child->loader(); | |
| 3079 DocumentLoader* documentLoader = childLoader->documentLoader(); | |
| 3080 if (documentLoader && documentLoader->isLoadingInAPISense()) | |
| 3081 return true; | |
| 3082 documentLoader = childLoader->provisionalDocumentLoader(); | |
| 3083 if (documentLoader && documentLoader->isLoadingInAPISense()) | |
| 3084 return true; | |
| 3085 } | |
| 3086 return false; | |
| 3087 } | |
| 3088 | |
| 3089 void FrameLoader::willChangeTitle(DocumentLoader* loader) | |
| 3090 { | |
| 3091 m_client->willChangeTitle(loader); | |
| 3092 } | |
| 3093 | |
| 3094 FrameLoadType FrameLoader::loadType() const | |
| 3095 { | |
| 3096 return m_loadType; | |
| 3097 } | |
| 3098 | |
| 3099 void FrameLoader::stopPolicyCheck() | |
| 3100 { | |
| 3101 m_client->cancelPolicyCheck(); | |
| 3102 PolicyCheck check = m_policyCheck; | |
| 3103 m_policyCheck.clear(); | |
| 3104 check.cancel(); | |
| 3105 } | |
| 3106 | |
| 3107 void FrameLoader::checkLoadCompleteForThisFrame() | |
| 3108 { | |
| 3109 ASSERT(m_client->hasWebView()); | |
| 3110 | |
| 3111 switch (m_state) { | |
| 3112 case FrameStateProvisional: { | |
| 3113 if (m_delegateIsHandlingProvisionalLoadError) | |
| 3114 return; | |
| 3115 | |
| 3116 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; | |
| 3117 if (!pdl) | |
| 3118 return; | |
| 3119 | |
| 3120 // If we've received any errors we may be stuck in the provisional s
tate and actually complete. | |
| 3121 const ResourceError& error = pdl->mainDocumentError(); | |
| 3122 if (error.isNull()) | |
| 3123 return; | |
| 3124 | |
| 3125 // Check all children first. | |
| 3126 RefPtr<HistoryItem> item; | |
| 3127 if (Page* page = m_frame->page()) | |
| 3128 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFr
ame()) | |
| 3129 item = m_currentHistoryItem; | |
| 3130 | |
| 3131 bool shouldReset = true; | |
| 3132 if (!pdl->isLoadingInAPISense()) { | |
| 3133 m_delegateIsHandlingProvisionalLoadError = true; | |
| 3134 m_client->dispatchDidFailProvisionalLoad(error); | |
| 3135 m_delegateIsHandlingProvisionalLoadError = false; | |
| 3136 | |
| 3137 // FIXME: can stopping loading here possibly have any effect, if
isLoading is false, | |
| 3138 // which it must be to be in this branch of the if? And is it OK
to just do a full-on | |
| 3139 // stopAllLoaders instead of stopLoadingSubframes? | |
| 3140 stopLoadingSubframes(); | |
| 3141 pdl->stopLoading(); | |
| 3142 | |
| 3143 // Finish resetting the load state, but only if another load has
n't been started by the | |
| 3144 // delegate callback. | |
| 3145 if (pdl == m_provisionalDocumentLoader) | |
| 3146 clearProvisionalLoad(); | |
| 3147 else if (m_provisionalDocumentLoader) { | |
| 3148 KURL unreachableURL = m_provisionalDocumentLoader->unreachab
leURL(); | |
| 3149 if (!unreachableURL.isEmpty() && unreachableURL == pdl->requ
est().url()) | |
| 3150 shouldReset = false; | |
| 3151 } | |
| 3152 } | |
| 3153 if (shouldReset && item) | |
| 3154 if (Page* page = m_frame->page()) | |
| 3155 page->backForwardList()->goToItem(item.get()); | |
| 3156 return; | |
| 3157 } | |
| 3158 | |
| 3159 case FrameStateCommittedPage: { | |
| 3160 DocumentLoader* dl = m_documentLoader.get(); | |
| 3161 if (!dl || dl->isLoadingInAPISense()) | |
| 3162 return; | |
| 3163 | |
| 3164 markLoadComplete(); | |
| 3165 | |
| 3166 // FIXME: Is this subsequent work important if we already navigated
away? | |
| 3167 // Maybe there are bugs because of that, or extra work we can skip b
ecause | |
| 3168 // the new page is ready. | |
| 3169 | |
| 3170 m_client->forceLayoutForNonHTML(); | |
| 3171 | |
| 3172 // If the user had a scroll point, scroll to it, overriding the anch
or point if any. | |
| 3173 if (Page* page = m_frame->page()) | |
| 3174 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoa
dTypeReload) && page->backForwardList()) | |
| 3175 restoreScrollPositionAndViewState(); | |
| 3176 | |
| 3177 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentL
oad) | |
| 3178 return; | |
| 3179 | |
| 3180 const ResourceError& error = dl->mainDocumentError(); | |
| 3181 #ifndef NDEBUG | |
| 3182 m_didDispatchDidCommitLoad = false; | |
| 3183 #endif | |
| 3184 if (!error.isNull()) | |
| 3185 m_client->dispatchDidFailLoad(error); | |
| 3186 else | |
| 3187 m_client->dispatchDidFinishLoad(); | |
| 3188 | |
| 3189 if (Page* page = m_frame->page()) | |
| 3190 page->progress()->progressCompleted(m_frame); | |
| 3191 return; | |
| 3192 } | |
| 3193 | |
| 3194 case FrameStateComplete: | |
| 3195 // Even if already complete, we might have set a previous item on a
frame that | |
| 3196 // didn't do any data loading on the past transaction. Make sure to
clear these out. | |
| 3197 m_client->frameLoadCompleted(); | |
| 3198 return; | |
| 3199 } | |
| 3200 | |
| 3201 ASSERT_NOT_REACHED(); | |
| 3202 } | |
| 3203 | |
| 3204 void FrameLoader::continueAfterContentPolicy(PolicyAction policy) | |
| 3205 { | |
| 3206 PolicyCheck check = m_policyCheck; | |
| 3207 m_policyCheck.clear(); | |
| 3208 check.call(policy); | |
| 3209 } | |
| 3210 | |
| 3211 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction) | |
| 3212 { | |
| 3213 if (!m_provisionalDocumentLoader) | |
| 3214 return; | |
| 3215 | |
| 3216 // DocumentLoader calls back to our prepareForLoadStart | |
| 3217 m_provisionalDocumentLoader->prepareForLoadStart(); | |
| 3218 | |
| 3219 // The load might be cancelled inside of prepareForLoadStart(), nulling out
the m_provisionalDocumentLoader, | |
| 3220 // so we need to null check it again. | |
| 3221 if (!m_provisionalDocumentLoader) | |
| 3222 return; | |
| 3223 | |
| 3224 DocumentLoader* activeDocLoader = activeDocumentLoader(); | |
| 3225 if (activeDocLoader && activeDocLoader->isLoadingMainResource()) | |
| 3226 return; | |
| 3227 | |
| 3228 m_provisionalDocumentLoader->setLoadingFromCachedPage(false); | |
| 3229 | |
| 3230 unsigned long identifier = 0; | |
| 3231 | |
| 3232 if (Page* page = m_frame->page()) { | |
| 3233 identifier = page->progress()->createUniqueIdentifier(); | |
| 3234 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocume
ntLoader.get(), m_provisionalDocumentLoader->originalRequest()); | |
| 3235 } | |
| 3236 | |
| 3237 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier)) | |
| 3238 m_provisionalDocumentLoader->updateLoading(); | |
| 3239 } | |
| 3240 | |
| 3241 void FrameLoader::didFirstLayout() | |
| 3242 { | |
| 3243 if (Page* page = m_frame->page()) | |
| 3244 if (isBackForwardLoadType(m_loadType) && page->backForwardList()) | |
| 3245 restoreScrollPositionAndViewState(); | |
| 3246 | |
| 3247 m_firstLayoutDone = true; | |
| 3248 m_client->dispatchDidFirstLayout(); | |
| 3249 } | |
| 3250 | |
| 3251 void FrameLoader::frameLoadCompleted() | |
| 3252 { | |
| 3253 m_client->frameLoadCompleted(); | |
| 3254 | |
| 3255 // After a canceled provisional load, firstLayoutDone is false. | |
| 3256 // Reset it to true if we're displaying a page. | |
| 3257 if (m_documentLoader) | |
| 3258 m_firstLayoutDone = true; | |
| 3259 } | |
| 3260 | |
| 3261 bool FrameLoader::firstLayoutDone() const | |
| 3262 { | |
| 3263 return m_firstLayoutDone; | |
| 3264 } | |
| 3265 | |
| 3266 bool FrameLoader::isQuickRedirectComing() const | |
| 3267 { | |
| 3268 return m_quickRedirectComing; | |
| 3269 } | |
| 3270 | |
| 3271 void FrameLoader::detachChildren() | |
| 3272 { | |
| 3273 // FIXME: Is it really necessary to do this in reverse order? | |
| 3274 Frame* previous; | |
| 3275 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) { | |
| 3276 previous = child->tree()->previousSibling(); | |
| 3277 child->loader()->detachFromParent(); | |
| 3278 } | |
| 3279 } | |
| 3280 | |
| 3281 void FrameLoader::recursiveCheckLoadComplete() | |
| 3282 { | |
| 3283 Vector<RefPtr<Frame>, 10> frames; | |
| 3284 | |
| 3285 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = fra
me->tree()->nextSibling()) | |
| 3286 frames.append(frame); | |
| 3287 | |
| 3288 unsigned size = frames.size(); | |
| 3289 for (unsigned i = 0; i < size; i++) | |
| 3290 frames[i]->loader()->recursiveCheckLoadComplete(); | |
| 3291 | |
| 3292 checkLoadCompleteForThisFrame(); | |
| 3293 } | |
| 3294 | |
| 3295 // Called every time a resource is completely loaded, or an error is received. | |
| 3296 void FrameLoader::checkLoadComplete() | |
| 3297 { | |
| 3298 ASSERT(m_client->hasWebView()); | |
| 3299 | |
| 3300 // FIXME: Always traversing the entire frame tree is a bit inefficient, but | |
| 3301 // is currently needed in order to null out the previous history item for al
l frames. | |
| 3302 if (Page* page = m_frame->page()) | |
| 3303 page->mainFrame()->loader()->recursiveCheckLoadComplete(); | |
| 3304 } | |
| 3305 | |
| 3306 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const | |
| 3307 { | |
| 3308 if (!recurse) | |
| 3309 return numRequests(m_frame->document()); | |
| 3310 | |
| 3311 int count = 0; | |
| 3312 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_fr
ame)) | |
| 3313 count += numRequests(frame->document()); | |
| 3314 return count; | |
| 3315 } | |
| 3316 | |
| 3317 FrameLoaderClient* FrameLoader::client() const | |
| 3318 { | |
| 3319 return m_client; | |
| 3320 } | |
| 3321 | |
| 3322 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event) | |
| 3323 { | |
| 3324 // FIXME: We'd like to remove this altogether and fix the multiple form subm
ission issue another way. | |
| 3325 // We do not want to submit more than one form from the same page, | |
| 3326 // nor do we want to submit a single form more than once. | |
| 3327 // This flag prevents these from happening; not sure how other browsers prev
ent this. | |
| 3328 // The flag is reset in each time we start handle a new mouse or key down ev
ent, and | |
| 3329 // also in setView since this part may get reused for a page from the back/f
orward cache. | |
| 3330 // The form multi-submit logic here is only needed when we are submitting a
form that affects this frame. | |
| 3331 // FIXME: Frame targeting is only one of the ways the submission could end u
p doing something other | |
| 3332 // than replacing this frame's content, so this check is flawed. On the othe
r hand, the check is hardly | |
| 3333 // needed any more now that we reset m_submittedFormURL on each mouse or key
down event. | |
| 3334 Frame* target = m_frame->tree()->find(request.frameName()); | |
| 3335 if (target && m_frame->tree()->isDescendantOf(target)) { | |
| 3336 if (m_submittedFormURL == request.resourceRequest().url()) | |
| 3337 return; | |
| 3338 m_submittedFormURL = request.resourceRequest().url(); | |
| 3339 } | |
| 3340 | |
| 3341 // FIXME: We should probably call userGestureHint() to tell whether this for
m submission was the result of a user gesture. | |
| 3342 loadFrameRequestWithFormAndValues(request, false, event, m_formAboutToBeSubm
itted.get(), m_formValuesAboutToBeSubmitted); | |
| 3343 | |
| 3344 clearRecordedFormValues(); | |
| 3345 } | |
| 3346 | |
| 3347 String FrameLoader::userAgent(const KURL& url) const | |
| 3348 { | |
| 3349 return m_client->userAgent(url); | |
| 3350 } | |
| 3351 | |
| 3352 void FrameLoader::tokenizerProcessedData() | |
| 3353 { | |
| 3354 // ASSERT(m_frame->page()); | |
| 3355 // ASSERT(m_frame->document()); | |
| 3356 | |
| 3357 checkCompleted(); | |
| 3358 } | |
| 3359 | |
| 3360 void FrameLoader::didTellClientAboutLoad(const String& url) | |
| 3361 { | |
| 3362 #if 0 | |
| 3363 // This hash table is unused in our fork. The only reader is | |
| 3364 // haveToldClientAboutLoad, and the only caller of that is | |
| 3365 // loadedResourceFromMemoryCache. We have commented out that location | |
| 3366 // because we want to send every URL to the client for mixed content | |
| 3367 // detection. Therefore, this hash table is unused. | |
| 3368 // | |
| 3369 // The table stores every URL ever loaded, or which has been attempted to be | |
| 3370 // loaded by a frame. For some apps like gmail, this can get into the | |
| 3371 // thousands after it has been running for a while. With Gmail URLs often | |
| 3372 // being more than 100 characters (and 2-bytes per char in a String), this | |
| 3373 // can quickly use a lot of memory we don't need. | |
| 3374 m_urlsClientKnowsAbout.add(url); | |
| 3375 #endif | |
| 3376 } | |
| 3377 | |
| 3378 bool FrameLoader::haveToldClientAboutLoad(const String& url) | |
| 3379 { | |
| 3380 #if 0 | |
| 3381 // See didTellClientAboutLoad() above for why this is removed in our fork. | |
| 3382 // This is commented out for consistency only. All lookups will fail anyway. | |
| 3383 return m_urlsClientKnowsAbout.contains(url); | |
| 3384 #else | |
| 3385 return false; | |
| 3386 #endif | |
| 3387 } | |
| 3388 | |
| 3389 void FrameLoader::handledOnloadEvents() | |
| 3390 { | |
| 3391 m_client->dispatchDidHandleOnloadEvents(); | |
| 3392 } | |
| 3393 | |
| 3394 void FrameLoader::frameDetached() | |
| 3395 { | |
| 3396 stopAllLoaders(); | |
| 3397 detachFromParent(); | |
| 3398 } | |
| 3399 | |
| 3400 void FrameLoader::detachFromParent() | |
| 3401 { | |
| 3402 RefPtr<Frame> protect(m_frame); | |
| 3403 | |
| 3404 closeURL(); | |
| 3405 stopAllLoaders(); | |
| 3406 saveScrollPositionAndViewStateToItem(currentHistoryItem()); | |
| 3407 detachChildren(); | |
| 3408 | |
| 3409 if (Page* page = m_frame->page()) | |
| 3410 page->inspectorController()->frameDetachedFromParent(m_frame); | |
| 3411 | |
| 3412 m_client->detachedFromParent2(); | |
| 3413 setDocumentLoader(0); | |
| 3414 m_client->detachedFromParent3(); | |
| 3415 if (Frame* parent = m_frame->tree()->parent()) { | |
| 3416 parent->tree()->removeChild(m_frame); | |
| 3417 parent->loader()->scheduleCheckCompleted(); | |
| 3418 } else { | |
| 3419 m_frame->setView(0); | |
| 3420 m_frame->pageDestroyed(); | |
| 3421 } | |
| 3422 m_client->detachedFromParent4(); | |
| 3423 } | |
| 3424 | |
| 3425 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainRes
ource, bool alwaysFromRequest) | |
| 3426 { | |
| 3427 applyUserAgent(request); | |
| 3428 | |
| 3429 if (m_loadType == FrameLoadTypeReload) { | |
| 3430 request.setCachePolicy(ReloadIgnoringCacheData); | |
| 3431 request.setHTTPHeaderField("Cache-Control", "max-age=0"); | |
| 3432 } | |
| 3433 | |
| 3434 // Don't set the cookie policy URL if it's already been set. | |
| 3435 if (request.mainDocumentURL().isEmpty()) { | |
| 3436 if (mainResource && (isLoadingMainFrame() || alwaysFromRequest)) | |
| 3437 request.setMainDocumentURL(request.url()); | |
| 3438 else if (Page* page = m_frame->page()) | |
| 3439 request.setMainDocumentURL(page->mainFrame()->loader()->url()); | |
| 3440 } | |
| 3441 | |
| 3442 if (mainResource) | |
| 3443 request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q
=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); | |
| 3444 } | |
| 3445 | |
| 3446 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int le
ngth) | |
| 3447 { | |
| 3448 if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType())) | |
| 3449 return; | |
| 3450 m_client->committedLoad(loader, data, length); | |
| 3451 } | |
| 3452 | |
| 3453 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String
& referrer, const String& frameName, | |
| 3454 Event* event, PassRefPtr<FormState> prpFormState) | |
| 3455 { | |
| 3456 RefPtr<FormState> formState = prpFormState; | |
| 3457 | |
| 3458 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag. | |
| 3459 // This prevents a potential bug which may cause a page with a form that use
s itself | |
| 3460 // as an action to be returned from the cache without submitting. | |
| 3461 | |
| 3462 // FIXME: Where's the code that implements what the comment above says? | |
| 3463 | |
| 3464 // Previously when this method was reached, the original FrameLoadRequest ha
d been deconstructed to build a | |
| 3465 // bunch of parameters that would come in here and then be built back up to
a ResourceRequest. In case | |
| 3466 // any caller depends on the immutability of the original ResourceRequest, I
'm rebuilding a ResourceRequest | |
| 3467 // from scratch as it did all along. | |
| 3468 const KURL& url = inRequest.url(); | |
| 3469 RefPtr<FormData> formData = inRequest.httpBody(); | |
| 3470 const String& contentType = inRequest.httpContentType(); | |
| 3471 | |
| 3472 ResourceRequest workingResourceRequest(url); | |
| 3473 addExtraFieldsToRequest(workingResourceRequest, true, true); | |
| 3474 | |
| 3475 if (!referrer.isEmpty()) | |
| 3476 workingResourceRequest.setHTTPReferrer(referrer); | |
| 3477 workingResourceRequest.setHTTPMethod("POST"); | |
| 3478 workingResourceRequest.setHTTPBody(formData); | |
| 3479 workingResourceRequest.setHTTPContentType(contentType); | |
| 3480 | |
| 3481 NavigationAction action(url, FrameLoadTypeStandard, true, event); | |
| 3482 | |
| 3483 if (!frameName.isEmpty()) { | |
| 3484 if (Frame* targetFrame = findFrameForNavigation(frameName)) | |
| 3485 targetFrame->loader()->loadWithNavigationAction(workingResourceReque
st, action, FrameLoadTypeStandard, formState.release()); | |
| 3486 else | |
| 3487 checkNewWindowPolicy(action, workingResourceRequest, formState.relea
se(), frameName); | |
| 3488 } else | |
| 3489 loadWithNavigationAction(workingResourceRequest, action, FrameLoadTypeSt
andard, formState.release()); | |
| 3490 } | |
| 3491 | |
| 3492 bool FrameLoader::isReloading() const | |
| 3493 { | |
| 3494 return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData; | |
| 3495 } | |
| 3496 | |
| 3497 void FrameLoader::loadEmptyDocumentSynchronously() | |
| 3498 { | |
| 3499 ResourceRequest request(KURL("")); | |
| 3500 load(request); | |
| 3501 } | |
| 3502 | |
| 3503 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
est, ResourceError& error, ResourceResponse& response, Vector<char>& data) | |
| 3504 { | |
| 3505 // Since this is a subresource, we can load any URL (we ignore the return va
lue). | |
| 3506 // But we still want to know whether we should hide the referrer or not, so
we call the canLoad method. | |
| 3507 String referrer = m_outgoingReferrer; | |
| 3508 if (shouldHideReferrer(request.url(), referrer)) | |
| 3509 referrer = String(); | |
| 3510 | |
| 3511 ResourceRequest initialRequest = request; | |
| 3512 initialRequest.setTimeoutInterval(10); | |
| 3513 | |
| 3514 if (initialRequest.isConditional()) | |
| 3515 initialRequest.setCachePolicy(ReloadIgnoringCacheData); | |
| 3516 else | |
| 3517 initialRequest.setCachePolicy(documentLoader()->request().cachePolicy())
; | |
| 3518 | |
| 3519 if (!referrer.isEmpty()) | |
| 3520 initialRequest.setHTTPReferrer(referrer); | |
| 3521 | |
| 3522 if (Page* page = m_frame->page()) | |
| 3523 initialRequest.setMainDocumentURL(page->mainFrame()->loader()->documentL
oader()->request().url()); | |
| 3524 initialRequest.setHTTPUserAgent(client()->userAgent(request.url())); | |
| 3525 | |
| 3526 unsigned long identifier = 0; | |
| 3527 ResourceRequest newRequest(initialRequest); | |
| 3528 requestFromDelegate(newRequest, identifier, error); | |
| 3529 | |
| 3530 if (error.isNull()) { | |
| 3531 ASSERT(!newRequest.isNull()); | |
| 3532 didTellClientAboutLoad(newRequest.url().string()); | |
| 3533 | |
| 3534 #if ENABLE(OFFLINE_WEB_APPLICATIONS) | |
| 3535 ApplicationCacheResource* resource; | |
| 3536 if (documentLoader()->shouldLoadResourceFromApplicationCache(newRequest,
resource)) { | |
| 3537 if (resource) { | |
| 3538 response = resource->response(); | |
| 3539 data.append(resource->data()->data(), resource->data()->size
()); | |
| 3540 } else | |
| 3541 error = cannotShowURLError(newRequest); | |
| 3542 } else | |
| 3543 #endif | |
| 3544 ResourceHandle::loadResourceSynchronously(newRequest, error, respons
e, data, m_frame); | |
| 3545 } | |
| 3546 | |
| 3547 sendRemainingDelegateMessages(identifier, response, data.size(), error); | |
| 3548 return identifier; | |
| 3549 } | |
| 3550 | |
| 3551 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, con
st ResourceRequest& clientRequest) | |
| 3552 { | |
| 3553 return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLo
ader(), clientRequest); | |
| 3554 } | |
| 3555 | |
| 3556 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clien
tRequest, const ResourceResponse& redirectResponse) | |
| 3557 { | |
| 3558 applyUserAgent(clientRequest); | |
| 3559 dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clie
ntRequest, redirectResponse); | |
| 3560 } | |
| 3561 | |
| 3562 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceRespo
nse& r) | |
| 3563 { | |
| 3564 activeDocumentLoader()->addResponse(r); | |
| 3565 | |
| 3566 if (Page* page = m_frame->page()) | |
| 3567 page->progress()->incrementProgress(loader->identifier(), r); | |
| 3568 dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r
); | |
| 3569 } | |
| 3570 | |
| 3571 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int l
ength, int lengthReceived) | |
| 3572 { | |
| 3573 if (Page* page = m_frame->page()) | |
| 3574 page->progress()->incrementProgress(loader->identifier(), data, length); | |
| 3575 dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier
(), lengthReceived); | |
| 3576 } | |
| 3577 | |
| 3578 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& err
or) | |
| 3579 { | |
| 3580 if (Page* page = m_frame->page()) | |
| 3581 page->progress()->completeProgress(loader->identifier()); | |
| 3582 if (!error.isNull()) | |
| 3583 m_client->dispatchDidFailLoading(loader->documentLoader(), loader->ident
ifier(), error); | |
| 3584 } | |
| 3585 | |
| 3586 const ResourceRequest& FrameLoader::originalRequest() const | |
| 3587 { | |
| 3588 return activeDocumentLoader()->originalRequestCopy(); | |
| 3589 } | |
| 3590 | |
| 3591 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isC
omplete) | |
| 3592 { | |
| 3593 // Retain because the stop may release the last reference to it. | |
| 3594 RefPtr<Frame> protect(m_frame); | |
| 3595 | |
| 3596 RefPtr<DocumentLoader> loader = activeDocumentLoader(); | |
| 3597 | |
| 3598 if (isComplete) { | |
| 3599 // FIXME: Don't want to do this if an entirely new load is going, so sho
uld check | |
| 3600 // that both data sources on the frame are either this or nil. | |
| 3601 stop(); | |
| 3602 if (m_client->shouldFallBack(error)) | |
| 3603 handleFallbackContent(); | |
| 3604 } | |
| 3605 | |
| 3606 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) { | |
| 3607 KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url(
); | |
| 3608 didNotOpenURL(failedURL); | |
| 3609 | |
| 3610 // We might have made a page cache item, but now we're bailing out due t
o an error before we ever | |
| 3611 // transitioned to the new page (before WebFrameState == commit). The g
oal here is to restore any state | |
| 3612 // so that the existing view (that wenever got far enough to replace) ca
n continue being used. | |
| 3613 invalidateCurrentItemCachedPage(); | |
| 3614 | |
| 3615 // Call clientRedirectCancelledOrFinished here so that the frame load de
legate is notified that the redirect's | |
| 3616 // status has changed, if there was a redirect. The frame load delegate
may have saved some state about | |
| 3617 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fir
eDate:forFrame:. Since we are definitely | |
| 3618 // not going to use this provisional resource, as it was cancelled, noti
fy the frame load delegate that the redirect | |
| 3619 // has ended. | |
| 3620 if (m_sentRedirectNotification) | |
| 3621 clientRedirectCancelledOrFinished(false); | |
| 3622 } | |
| 3623 | |
| 3624 | |
| 3625 loader->mainReceivedError(error, isComplete); | |
| 3626 } | |
| 3627 | |
| 3628 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument
, | |
| 3629 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) | |
| 3630 { | |
| 3631 FrameLoader* loader = static_cast<FrameLoader*>(argument); | |
| 3632 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue)
; | |
| 3633 } | |
| 3634 | |
| 3635 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequ
est& request, bool shouldContinue) | |
| 3636 { | |
| 3637 // FIXME: | |
| 3638 // some functions check m_quickRedirectComing, and others check for | |
| 3639 // FrameLoadTypeRedirectWithLockedHistory. | |
| 3640 bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadType
RedirectWithLockedHistory; | |
| 3641 m_quickRedirectComing = false; | |
| 3642 | |
| 3643 if (!shouldContinue) | |
| 3644 return; | |
| 3645 | |
| 3646 KURL url = request.url(); | |
| 3647 | |
| 3648 m_documentLoader->replaceRequestURLForAnchorScroll(url); | |
| 3649 if (!isRedirect && !shouldTreatURLAsSameAsCurrent(url)) { | |
| 3650 // NB: must happen after _setURL, since we add based on the current requ
est. | |
| 3651 // Must also happen before we openURL and displace the scroll position,
since | |
| 3652 // adding the BF item will save away scroll state. | |
| 3653 | |
| 3654 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed
before | |
| 3655 // it was done, currItem is now set the that slow doc, and prevItem is w
hatever was | |
| 3656 // before it. Adding the b/f item will bump the slow doc down to prevIt
em, even | |
| 3657 // though its load is not yet done. I think this all works out OK, for
one because | |
| 3658 // we have already saved away the scroll and doc state for the long slow
load, | |
| 3659 // but it's not an obvious case. | |
| 3660 | |
| 3661 addHistoryItemForFragmentScroll(); | |
| 3662 } | |
| 3663 | |
| 3664 scrollToAnchor(url); | |
| 3665 | |
| 3666 if (!isRedirect) | |
| 3667 // This will clear previousItem from the rest of the frame tree that did
n't | |
| 3668 // doing any loading. We need to make a pass on this now, since for anch
or nav | |
| 3669 // we'll not go through a real load and reach Completed state. | |
| 3670 checkLoadComplete(); | |
| 3671 | |
| 3672 m_client->dispatchDidChangeLocationWithinPage(); | |
| 3673 m_client->didFinishLoad(); | |
| 3674 } | |
| 3675 | |
| 3676 bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType load
Type, const KURL& url) | |
| 3677 { | |
| 3678 // Should we do anchor navigation within the existing content? | |
| 3679 | |
| 3680 // We don't do this if we are submitting a form, explicitly reloading, | |
| 3681 // currently displaying a frameset, or if the URL does not have a fragment. | |
| 3682 // These rules were originally based on what KHTML was doing in KHTMLPart::o
penURL. | |
| 3683 | |
| 3684 // FIXME: What about load types other than Standard and Reload? | |
| 3685 | |
| 3686 return !isFormSubmission | |
| 3687 && loadType != FrameLoadTypeReload | |
| 3688 && loadType != FrameLoadTypeSame | |
| 3689 && !shouldReload(this->url(), url) | |
| 3690 // We don't want to just scroll if a link from within a | |
| 3691 // frameset is trying to reload the frameset into _top. | |
| 3692 && !m_frame->isFrameSet(); | |
| 3693 } | |
| 3694 | |
| 3695 void FrameLoader::opened() | |
| 3696 { | |
| 3697 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirec
t()) | |
| 3698 updateHistoryForClientRedirect(); | |
| 3699 | |
| 3700 if (m_documentLoader->isLoadingFromCachedPage()) { | |
| 3701 m_frame->document()->didRestoreFromCache(); | |
| 3702 | |
| 3703 // Force a layout to update view size and thereby update scrollbars. | |
| 3704 m_client->forceLayout(); | |
| 3705 | |
| 3706 const ResponseVector& responses = m_documentLoader->responses(); | |
| 3707 size_t count = responses.size(); | |
| 3708 for (size_t i = 0; i < count; i++) { | |
| 3709 const ResourceResponse& response = responses[i]; | |
| 3710 // FIXME: If the WebKit client changes or cancels the request, this
is not respected. | |
| 3711 ResourceError error; | |
| 3712 unsigned long identifier; | |
| 3713 ResourceRequest request(response.url()); | |
| 3714 requestFromDelegate(request, identifier, error); | |
| 3715 // FIXME: If we get a resource with more than 2B bytes, this code wo
n't do the right thing. | |
| 3716 // However, with today's computers and networking speeds, this won't
happen in practice. | |
| 3717 // Could be an issue with a giant local file. | |
| 3718 sendRemainingDelegateMessages(identifier, response, static_cast<int>
(response.expectedContentLength()), error); | |
| 3719 } | |
| 3720 | |
| 3721 pageCache()->remove(m_currentHistoryItem.get()); | |
| 3722 | |
| 3723 m_documentLoader->setPrimaryLoadComplete(true); | |
| 3724 | |
| 3725 // FIXME: Why only this frame and not parent frames? | |
| 3726 checkLoadCompleteForThisFrame(); | |
| 3727 } | |
| 3728 } | |
| 3729 | |
| 3730 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const Res
ourceRequest& request, | |
| 3731 PassRefPtr<FormState> formState, const String& frameName) | |
| 3732 { | |
| 3733 m_policyCheck.set(request, formState, frameName, | |
| 3734 callContinueLoadAfterNewWindowPolicy, this); | |
| 3735 m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfter
NewWindowPolicy, | |
| 3736 action, request, formState, frameName); | |
| 3737 } | |
| 3738 | |
| 3739 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy) | |
| 3740 { | |
| 3741 PolicyCheck check = m_policyCheck; | |
| 3742 m_policyCheck.clear(); | |
| 3743 | |
| 3744 switch (policy) { | |
| 3745 case PolicyIgnore: | |
| 3746 check.clearRequest(); | |
| 3747 break; | |
| 3748 case PolicyDownload: | |
| 3749 m_client->startDownload(check.request()); | |
| 3750 check.clearRequest(); | |
| 3751 break; | |
| 3752 case PolicyUse: | |
| 3753 break; | |
| 3754 } | |
| 3755 | |
| 3756 check.call(policy == PolicyUse); | |
| 3757 } | |
| 3758 | |
| 3759 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, Document
Loader* loader, | |
| 3760 PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function,
void* argument) | |
| 3761 { | |
| 3762 NavigationAction action = loader->triggeringAction(); | |
| 3763 if (action.isEmpty()) { | |
| 3764 action = NavigationAction(request.url(), NavigationTypeOther); | |
| 3765 loader->setTriggeringAction(action); | |
| 3766 } | |
| 3767 | |
| 3768 // Don't ask more than once for the same request or if we are loading an emp
ty URL. | |
| 3769 // This avoids confusion on the part of the client. | |
| 3770 if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!re
quest.isNull() && request.url().isEmpty())) { | |
| 3771 function(argument, request, 0, true); | |
| 3772 loader->setLastCheckedRequest(request); | |
| 3773 return; | |
| 3774 } | |
| 3775 | |
| 3776 // We are always willing to show alternate content for unreachable URLs; | |
| 3777 // treat it like a reload so it maintains the right state for b/f list. | |
| 3778 if (loader->substituteData().isValid() && !loader->substituteData().failingU
RL().isEmpty()) { | |
| 3779 if (isBackForwardLoadType(m_policyLoadType)) | |
| 3780 m_policyLoadType = FrameLoadTypeReload; | |
| 3781 function(argument, request, 0, true); | |
| 3782 return; | |
| 3783 } | |
| 3784 | |
| 3785 loader->setLastCheckedRequest(request); | |
| 3786 | |
| 3787 m_policyCheck.set(request, formState.get(), function, argument); | |
| 3788 | |
| 3789 m_delegateIsDecidingNavigationPolicy = true; | |
| 3790 m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfte
rNavigationPolicy, | |
| 3791 action, request, formState); | |
| 3792 m_delegateIsDecidingNavigationPolicy = false; | |
| 3793 } | |
| 3794 | |
| 3795 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy) | |
| 3796 { | |
| 3797 PolicyCheck check = m_policyCheck; | |
| 3798 m_policyCheck.clear(); | |
| 3799 | |
| 3800 bool shouldContinue = policy == PolicyUse; | |
| 3801 | |
| 3802 switch (policy) { | |
| 3803 case PolicyIgnore: | |
| 3804 check.clearRequest(); | |
| 3805 break; | |
| 3806 case PolicyDownload: | |
| 3807 m_client->startDownload(check.request()); | |
| 3808 check.clearRequest(); | |
| 3809 break; | |
| 3810 case PolicyUse: { | |
| 3811 ResourceRequest request(check.request()); | |
| 3812 | |
| 3813 if (!m_client->canHandleRequest(request)) { | |
| 3814 handleUnimplementablePolicy(m_client->cannotShowURLError(check.r
equest())); | |
| 3815 check.clearRequest(); | |
| 3816 shouldContinue = false; | |
| 3817 } | |
| 3818 break; | |
| 3819 } | |
| 3820 } | |
| 3821 | |
| 3822 check.call(shouldContinue); | |
| 3823 } | |
| 3824 | |
| 3825 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument, | |
| 3826 const ResourceRequest& request, PassRefPtr<FormState> formState, bool should
Continue) | |
| 3827 { | |
| 3828 FrameLoader* loader = static_cast<FrameLoader*>(argument); | |
| 3829 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue
); | |
| 3830 } | |
| 3831 | |
| 3832 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& reque
st, PassRefPtr<FormState> formState, bool shouldContinue) | |
| 3833 { | |
| 3834 // If we loaded an alternate page to replace an unreachableURL, we'll get in
here with a | |
| 3835 // nil policyDataSource because loading the alternate page will have passed | |
| 3836 // through this method already, nested; otherwise, policyDataSource should s
till be set. | |
| 3837 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableUR
L().isEmpty()); | |
| 3838 | |
| 3839 bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isT
argetItem() : false; | |
| 3840 | |
| 3841 // Two reasons we can't continue: | |
| 3842 // 1) Navigation policy delegate said we can't so request is nil. A prima
ry case of this | |
| 3843 // is the user responding Cancel to the form repost nag sheet. | |
| 3844 // 2) User responded Cancel to an alert popped up by the before unload ev
ent handler. | |
| 3845 // The "before unload" event handler runs only for the main frame. | |
| 3846 bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shou
ldClose()); | |
| 3847 | |
| 3848 if (!canContinue) { | |
| 3849 // If we were waiting for a quick redirect, but the policy delegate deci
ded to ignore it, then we | |
| 3850 // need to report that the client redirect was cancelled. | |
| 3851 if (m_quickRedirectComing) | |
| 3852 clientRedirectCancelledOrFinished(false); | |
| 3853 | |
| 3854 setPolicyDocumentLoader(0); | |
| 3855 | |
| 3856 // If the navigation request came from the back/forward menu, and we pun
t on it, we have the | |
| 3857 // problem that we have optimistically moved the b/f cursor already, so
move it back. For sanity, | |
| 3858 // we only do this when punting a navigation for the target frame or top
-level frame. | |
| 3859 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_po
licyLoadType)) | |
| 3860 if (Page* page = m_frame->page()) { | |
| 3861 Frame* mainFrame = page->mainFrame(); | |
| 3862 if (HistoryItem* resetItem = mainFrame->loader()->m_currentHisto
ryItem.get()) | |
| 3863 page->backForwardList()->goToItem(resetItem); | |
| 3864 } | |
| 3865 return; | |
| 3866 } | |
| 3867 | |
| 3868 FrameLoadType type = m_policyLoadType; | |
| 3869 stopAllLoaders(); | |
| 3870 setProvisionalDocumentLoader(m_policyDocumentLoader.get()); | |
| 3871 m_loadType = type; | |
| 3872 setState(FrameStateProvisional); | |
| 3873 | |
| 3874 setPolicyDocumentLoader(0); | |
| 3875 | |
| 3876 if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage()) | |
| 3877 return; | |
| 3878 | |
| 3879 if (formState) | |
| 3880 m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubm
itForm, formState); | |
| 3881 else | |
| 3882 continueLoadAfterWillSubmitForm(); | |
| 3883 } | |
| 3884 | |
| 3885 | |
| 3886 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument, | |
| 3887 const ResourceRequest& request, PassRefPtr<FormState> formState, const Strin
g& frameName, bool shouldContinue) | |
| 3888 { | |
| 3889 FrameLoader* loader = static_cast<FrameLoader*>(argument); | |
| 3890 loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shou
ldContinue); | |
| 3891 } | |
| 3892 | |
| 3893 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& reques
t, | |
| 3894 PassRefPtr<FormState> formState, const String& frameName, bool shouldContinu
e) | |
| 3895 { | |
| 3896 if (!shouldContinue) | |
| 3897 return; | |
| 3898 | |
| 3899 RefPtr<Frame> frame = m_frame; | |
| 3900 RefPtr<Frame> mainFrame = m_client->dispatchCreatePage(); | |
| 3901 if (!mainFrame) | |
| 3902 return; | |
| 3903 | |
| 3904 if (frameName != "_blank") | |
| 3905 mainFrame->tree()->setName(frameName); | |
| 3906 | |
| 3907 mainFrame->loader()->setOpenedByDOM(); | |
| 3908 mainFrame->loader()->m_client->dispatchShow(); | |
| 3909 mainFrame->loader()->setOpener(frame.get()); | |
| 3910 mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), F
rameLoadTypeStandard, formState); | |
| 3911 } | |
| 3912 | |
| 3913 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const
ResourceResponse& response, int length, const ResourceError& error) | |
| 3914 { | |
| 3915 if (!response.isNull()) | |
| 3916 dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response)
; | |
| 3917 | |
| 3918 if (length > 0) | |
| 3919 dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, leng
th); | |
| 3920 | |
| 3921 if (error.isNull()) | |
| 3922 dispatchDidFinishLoading(m_documentLoader.get(), identifier); | |
| 3923 else | |
| 3924 m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, err
or); | |
| 3925 } | |
| 3926 | |
| 3927 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& i
dentifier, ResourceError& error) | |
| 3928 { | |
| 3929 ASSERT(!request.isNull()); | |
| 3930 | |
| 3931 identifier = 0; | |
| 3932 if (Page* page = m_frame->page()) { | |
| 3933 identifier = page->progress()->createUniqueIdentifier(); | |
| 3934 dispatchAssignIdentifierToInitialRequest(identifier, m_documentLoader.ge
t(), request); | |
| 3935 } | |
| 3936 | |
| 3937 ResourceRequest newRequest(request); | |
| 3938 dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, Reso
urceResponse()); | |
| 3939 | |
| 3940 if (newRequest.isNull()) | |
| 3941 error = cancelledError(request); | |
| 3942 else | |
| 3943 error = ResourceError(); | |
| 3944 | |
| 3945 request = newRequest; | |
| 3946 } | |
| 3947 | |
| 3948 void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource) | |
| 3949 { | |
| 3950 ResourceRequest request(resource->url()); | |
| 3951 const ResourceResponse& response = resource->response(); | |
| 3952 int length = resource->encodedSize(); | |
| 3953 | |
| 3954 if (Page* page = m_frame->page()) | |
| 3955 page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLo
ader.get(), request, response, length); | |
| 3956 | |
| 3957 | |
| 3958 #if 0 | |
| 3959 // The following test prevents reporting a resource has been loaded from | |
| 3960 // the cache as CachedResource.m_sendResourceLoadCallbacks is always false. | |
| 3961 // Also, haveToldClientAboutLoad() and didTellClientAboutLoad() would cause | |
| 3962 // dispatchDidLoadResourceFromMemoryCache() to be invoked only the first | |
| 3963 // time the resource is loaded from the cache. | |
| 3964 // We want to be notified every time a resource is loaded from the cache | |
| 3965 // (this is needed to detect mixed-contents), so we removed it. | |
| 3966 | |
| 3967 if (!resource->sendResourceLoadCallbacks() || haveToldClientAboutLoad(resour
ce->url())) | |
| 3968 return; | |
| 3969 #endif | |
| 3970 | |
| 3971 if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(),
request, response, length)) { | |
| 3972 didTellClientAboutLoad(resource->url()); | |
| 3973 return; | |
| 3974 } | |
| 3975 | |
| 3976 unsigned long identifier; | |
| 3977 ResourceError error; | |
| 3978 ResourceRequest r(request); | |
| 3979 requestFromDelegate(r, identifier, error); | |
| 3980 sendRemainingDelegateMessages(identifier, response, length, error); | |
| 3981 | |
| 3982 didTellClientAboutLoad(resource->url()); | |
| 3983 } | |
| 3984 | |
| 3985 void FrameLoader::applyUserAgent(ResourceRequest& request) | |
| 3986 { | |
| 3987 String userAgent = client()->userAgent(request.url()); | |
| 3988 ASSERT(!userAgent.isNull()); | |
| 3989 request.setHTTPUserAgent(userAgent); | |
| 3990 } | |
| 3991 | |
| 3992 bool FrameLoader::canGoBackOrForward(int distance) const | |
| 3993 { | |
| 3994 if (Page* page = m_frame->page()) { | |
| 3995 if (distance == 0) | |
| 3996 return true; | |
| 3997 if (distance > 0 && distance <= page->backForwardList()->forwardListCoun
t()) | |
| 3998 return true; | |
| 3999 if (distance < 0 && -distance <= page->backForwardList()->backListCount(
)) | |
| 4000 return true; | |
| 4001 } | |
| 4002 return false; | |
| 4003 } | |
| 4004 | |
| 4005 int FrameLoader::getHistoryLength() | |
| 4006 { | |
| 4007 if (Page* page = m_frame->page()) | |
| 4008 return page->backForwardList()->backListCount() + 1; | |
| 4009 return 0; | |
| 4010 } | |
| 4011 | |
| 4012 KURL FrameLoader::historyURL(int distance) | |
| 4013 { | |
| 4014 if (Page* page = m_frame->page()) { | |
| 4015 BackForwardList* list = page->backForwardList(); | |
| 4016 HistoryItem* item = list->itemAtIndex(distance); | |
| 4017 if (!item) { | |
| 4018 if (distance > 0) { | |
| 4019 int forwardListCount = list->forwardListCount(); | |
| 4020 if (forwardListCount > 0) | |
| 4021 item = list->itemAtIndex(forwardListCount); | |
| 4022 } else { | |
| 4023 int backListCount = list->backListCount(); | |
| 4024 if (backListCount > 0) | |
| 4025 item = list->itemAtIndex(-backListCount); | |
| 4026 } | |
| 4027 } | |
| 4028 if (item) | |
| 4029 return item->url(); | |
| 4030 } | |
| 4031 return KURL(); | |
| 4032 } | |
| 4033 | |
| 4034 void FrameLoader::addHistoryItemForFragmentScroll() | |
| 4035 { | |
| 4036 addBackForwardItemClippedAtTarget(false); | |
| 4037 } | |
| 4038 | |
| 4039 bool FrameLoader::loadProvisionalItemFromCachedPage() | |
| 4040 { | |
| 4041 RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.ge
t()); | |
| 4042 if (!cachedPage || !cachedPage->document()) | |
| 4043 return false; | |
| 4044 provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release()); | |
| 4045 return true; | |
| 4046 } | |
| 4047 | |
| 4048 void FrameLoader::cachePageForHistoryItem(HistoryItem* item) | |
| 4049 { | |
| 4050 if (Page* page = m_frame->page()) { | |
| 4051 RefPtr<CachedPage> cachedPage = CachedPage::create(page); | |
| 4052 cachedPage->setTimeStampToNow(); | |
| 4053 cachedPage->setDocumentLoader(documentLoader()); | |
| 4054 m_client->savePlatformDataToCachedPage(cachedPage.get()); | |
| 4055 | |
| 4056 pageCache()->add(item, cachedPage.release()); | |
| 4057 } | |
| 4058 } | |
| 4059 | |
| 4060 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const | |
| 4061 { | |
| 4062 if (!m_currentHistoryItem) | |
| 4063 return false; | |
| 4064 return url == m_currentHistoryItem->url() || url == m_currentHistoryItem->or
iginalURL(); | |
| 4065 } | |
| 4066 | |
| 4067 PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal) | |
| 4068 { | |
| 4069 DocumentLoader* docLoader = documentLoader(); | |
| 4070 | |
| 4071 KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL(); | |
| 4072 | |
| 4073 KURL url; | |
| 4074 KURL originalURL; | |
| 4075 | |
| 4076 if (!unreachableURL.isEmpty()) { | |
| 4077 url = unreachableURL; | |
| 4078 originalURL = unreachableURL; | |
| 4079 } else { | |
| 4080 originalURL = docLoader ? docLoader->originalURL() : KURL(); | |
| 4081 if (useOriginal) | |
| 4082 url = originalURL; | |
| 4083 else if (docLoader) | |
| 4084 url = docLoader->requestURL(); | |
| 4085 } | |
| 4086 | |
| 4087 LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().da
ta()); | |
| 4088 | |
| 4089 // Frames that have never successfully loaded any content | |
| 4090 // may have no URL at all. Currently our history code can't | |
| 4091 // deal with such things, so we nip that in the bud here. | |
| 4092 // Later we may want to learn to live with nil for URL. | |
| 4093 // See bug 3368236 and related bugs for more information. | |
| 4094 if (url.isEmpty()) | |
| 4095 url = blankURL(); | |
| 4096 if (originalURL.isEmpty()) | |
| 4097 originalURL = blankURL(); | |
| 4098 | |
| 4099 Frame* parentFrame = m_frame->tree()->parent(); | |
| 4100 String parent = parentFrame ? parentFrame->tree()->name() : ""; | |
| 4101 String title = docLoader ? docLoader->title() : ""; | |
| 4102 | |
| 4103 RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->name(),
parent, title); | |
| 4104 item->setOriginalURLString(originalURL.string()); | |
| 4105 | |
| 4106 // Save form state if this is a POST | |
| 4107 if (docLoader) { | |
| 4108 if (useOriginal) | |
| 4109 item->setFormInfoFromRequest(docLoader->originalRequest()); | |
| 4110 else | |
| 4111 item->setFormInfoFromRequest(docLoader->request()); | |
| 4112 } | |
| 4113 | |
| 4114 // Set the item for which we will save document state | |
| 4115 m_previousHistoryItem = m_currentHistoryItem; | |
| 4116 m_currentHistoryItem = item; | |
| 4117 | |
| 4118 return item.release(); | |
| 4119 } | |
| 4120 | |
| 4121 void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip) | |
| 4122 { | |
| 4123 Page* page = m_frame->page(); | |
| 4124 if (!page) | |
| 4125 return; | |
| 4126 | |
| 4127 if (documentLoader()->urlForHistory().isEmpty()) | |
| 4128 return; | |
| 4129 | |
| 4130 Frame* mainFrame = page->mainFrame(); | |
| 4131 ASSERT(mainFrame); | |
| 4132 FrameLoader* frameLoader = mainFrame->loader(); | |
| 4133 | |
| 4134 if (!frameLoader->m_didPerformFirstNavigation && page->backForwardList()->en
tries().size() == 1) { | |
| 4135 frameLoader->m_didPerformFirstNavigation = true; | |
| 4136 m_client->didPerformFirstNavigation(); | |
| 4137 } | |
| 4138 | |
| 4139 RefPtr<HistoryItem> item = frameLoader->createHistoryItemTree(m_frame, doCli
p); | |
| 4140 LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame
%s", item.get(), documentLoader()->url().string().ascii().data()); | |
| 4141 page->backForwardList()->addItem(item); | |
| 4142 } | |
| 4143 | |
| 4144 PassRefPtr<HistoryItem> FrameLoader::createHistoryItemTree(Frame* targetFrame, b
ool clipAtTarget) | |
| 4145 { | |
| 4146 RefPtr<HistoryItem> bfItem = createHistoryItem(m_frame->tree()->parent() ? t
rue : false); | |
| 4147 if (m_previousHistoryItem) | |
| 4148 saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get()); | |
| 4149 if (!(clipAtTarget && m_frame == targetFrame)) { | |
| 4150 // save frame state for items that aren't loading (khtml doesn't save th
ose) | |
| 4151 saveDocumentState(); | |
| 4152 for (Frame* child = m_frame->tree()->firstChild(); child; child = child-
>tree()->nextSibling()) { | |
| 4153 FrameLoader* childLoader = child->loader(); | |
| 4154 bool hasChildLoaded = childLoader->frameHasLoaded(); | |
| 4155 | |
| 4156 // If the child is a frame corresponding to an <object> element that
never loaded, | |
| 4157 // we don't want to create a history item, because that causes fallb
ack content | |
| 4158 // to be ignored on reload. | |
| 4159 | |
| 4160 if (!(!hasChildLoaded && childLoader->isHostedByObjectElement())) | |
| 4161 bfItem->addChildItem(childLoader->createHistoryItemTree(targetFr
ame, clipAtTarget)); | |
| 4162 } | |
| 4163 } | |
| 4164 if (m_frame == targetFrame) | |
| 4165 bfItem->setIsTargetItem(true); | |
| 4166 return bfItem; | |
| 4167 } | |
| 4168 | |
| 4169 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name) | |
| 4170 { | |
| 4171 Frame* frame = m_frame->tree()->find(name); | |
| 4172 if (shouldAllowNavigation(frame)) | |
| 4173 return frame; | |
| 4174 return 0; | |
| 4175 } | |
| 4176 | |
| 4177 void FrameLoader::saveScrollPositionAndViewStateToItem(HistoryItem* item) | |
| 4178 { | |
| 4179 if (!item || !m_frame->view()) | |
| 4180 return; | |
| 4181 | |
| 4182 item->setScrollPoint(IntPoint(m_frame->view()->contentsX(), m_frame->view()-
>contentsY())); | |
| 4183 // FIXME: It would be great to work out a way to put this code in WebCore in
stead of calling through to the client. | |
| 4184 m_client->saveViewStateToItem(item); | |
| 4185 } | |
| 4186 | |
| 4187 /* | |
| 4188 There is a race condition between the layout and load completion that affects r
estoring the scroll position. | |
| 4189 We try to restore the scroll position at both the first layout and upon load co
mpletion. | |
| 4190 | |
| 4191 1) If first layout happens before the load completes, we want to restore the sc
roll position then so that the | |
| 4192 first time we draw the page is already scrolled to the right place, instead of
starting at the top and later | |
| 4193 jumping down. It is possible that the old scroll position is past the part of
the doc laid out so far, in | |
| 4194 which case the restore silent fails and we will fix it in when we try to restor
e on doc completion. | |
| 4195 2) If the layout happens after the load completes, the attempt to restore at lo
ad completion time silently | |
| 4196 fails. We then successfully restore it when the layout happens. | |
| 4197 */ | |
| 4198 void FrameLoader::restoreScrollPositionAndViewState() | |
| 4199 { | |
| 4200 if (!m_committedFirstRealDocumentLoad) | |
| 4201 return; | |
| 4202 | |
| 4203 ASSERT(m_currentHistoryItem); | |
| 4204 | |
| 4205 // FIXME: As the ASSERT attests, it seems we should always have a currentIte
m here. | |
| 4206 // One counterexample is <rdar://problem/4917290> | |
| 4207 // For now, to cover this issue in release builds, there is no technical har
m to returning | |
| 4208 // early and from a user standpoint - as in the above radar - the previous p
age load failed | |
| 4209 // so there *is* no scroll or view state to restore! | |
| 4210 if (!m_currentHistoryItem) | |
| 4211 return; | |
| 4212 | |
| 4213 // FIXME: It would be great to work out a way to put this code in WebCore in
stead of calling | |
| 4214 // through to the client. It's currently used only for the PDF view on Mac. | |
| 4215 m_client->restoreViewState(); | |
| 4216 | |
| 4217 if (FrameView* view = m_frame->view()) | |
| 4218 if (!view->wasScrolledByUser()) { | |
| 4219 const IntPoint& scrollPoint = m_currentHistoryItem->scrollPoint(); | |
| 4220 view->setContentsPos(scrollPoint.x(), scrollPoint.y()); | |
| 4221 } | |
| 4222 } | |
| 4223 | |
| 4224 void FrameLoader::invalidateCurrentItemCachedPage() | |
| 4225 { | |
| 4226 // When we are pre-commit, the currentItem is where the pageCache data resid
es | |
| 4227 CachedPage* cachedPage = pageCache()->get(m_currentHistoryItem.get()); | |
| 4228 | |
| 4229 // FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in
RenderFlow::detach | |
| 4230 // Somehow the PageState object is not properly updated, and is holding onto
a stale document. | |
| 4231 // Both Xcode and FileMaker see this crash, Safari does not. | |
| 4232 | |
| 4233 ASSERT(!cachedPage || cachedPage->document() == m_frame->document()); | |
| 4234 if (cachedPage && cachedPage->document() == m_frame->document()) { | |
| 4235 cachedPage->document()->setInPageCache(false); | |
| 4236 cachedPage->clear(); | |
| 4237 } | |
| 4238 | |
| 4239 if (cachedPage) | |
| 4240 pageCache()->remove(m_currentHistoryItem.get()); | |
| 4241 } | |
| 4242 | |
| 4243 void FrameLoader::saveDocumentState() | |
| 4244 { | |
| 4245 if (m_creatingInitialEmptyDocument) | |
| 4246 return; | |
| 4247 | |
| 4248 // For a standard page load, we will have a previous item set, which will be
used to | |
| 4249 // store the form state. However, in some cases we will have no previous it
em, and | |
| 4250 // the current item is the right place to save the state. One example is wh
en we | |
| 4251 // detach a bunch of frames because we are navigating from a site with frame
s to | |
| 4252 // another site. Another is when saving the frame state of a frame that is
not the | |
| 4253 // target of the current navigation (if we even decide to save with that gra
nularity). | |
| 4254 | |
| 4255 // Because of previousItem's "masking" of currentItem for this purpose, it's
important | |
| 4256 // that previousItem be cleared at the end of a page transition. We leverag
e the | |
| 4257 // checkLoadComplete recursion to achieve this goal. | |
| 4258 | |
| 4259 HistoryItem* item = m_previousHistoryItem ? m_previousHistoryItem.get() : m_
currentHistoryItem.get(); | |
| 4260 if (!item) | |
| 4261 return; | |
| 4262 | |
| 4263 Document* document = m_frame->document(); | |
| 4264 ASSERT(document); | |
| 4265 | |
| 4266 if (document && item->isCurrentDocument(document)) { | |
| 4267 LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree
()->name().string().utf8().data(), item); | |
| 4268 item->setDocumentState(document->formElementsState()); | |
| 4269 } | |
| 4270 } | |
| 4271 | |
| 4272 // Loads content into this frame, as specified by history item | |
| 4273 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) | |
| 4274 { | |
| 4275 if (!m_frame->page()) | |
| 4276 return; | |
| 4277 | |
| 4278 KURL itemURL = item->url(); | |
| 4279 KURL itemOriginalURL = item->originalURL(); | |
| 4280 KURL currentURL; | |
| 4281 if (documentLoader()) | |
| 4282 currentURL = documentLoader()->url(); | |
| 4283 RefPtr<FormData> formData = item->formData(); | |
| 4284 | |
| 4285 // Are we navigating to an anchor within the page? | |
| 4286 // Note if we have child frames we do a real reload, since the child frames
might not | |
| 4287 // match our current frame structure, or they might not have the right conte
nt. We could | |
| 4288 // check for all that as an additional optimization. | |
| 4289 // We also do not do anchor-style navigation if we're posting a form. | |
| 4290 | |
| 4291 if (!formData && urlsMatchItem(item)) { | |
| 4292 // Must do this maintenance here, since we don't go through a real page
reload | |
| 4293 saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); | |
| 4294 | |
| 4295 if (FrameView* view = m_frame->view()) | |
| 4296 view->setWasScrolledByUser(false); | |
| 4297 | |
| 4298 m_currentHistoryItem = item; | |
| 4299 | |
| 4300 // FIXME: Form state might need to be saved here too. | |
| 4301 | |
| 4302 // We always call scrollToAnchor here, even if the URL doesn't have an | |
| 4303 // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-
date. | |
| 4304 scrollToAnchor(item->url()); | |
| 4305 | |
| 4306 // must do this maintenance here, since we don't go through a real page
reload | |
| 4307 restoreScrollPositionAndViewState(); | |
| 4308 | |
| 4309 // Fake the URL change by updating the data source's request. This will
no longer | |
| 4310 // be necessary if we do the better fix described above. | |
| 4311 documentLoader()->replaceRequestURLForAnchorScroll(itemURL); | |
| 4312 | |
| 4313 m_client->dispatchDidChangeLocationWithinPage(); | |
| 4314 | |
| 4315 // FrameLoaderClient::didFinishLoad() tells the internal load delegate t
he load finished with no error | |
| 4316 m_client->didFinishLoad(); | |
| 4317 } else { | |
| 4318 // Remember this item so we can traverse any child items as child frames
load | |
| 4319 m_provisionalHistoryItem = item; | |
| 4320 | |
| 4321 bool inPageCache = false; | |
| 4322 | |
| 4323 // Check if we'll be using the page cache. We only use the page cache | |
| 4324 // if one exists and it is less than _backForwardCacheExpirationInterval | |
| 4325 // seconds old. If the cache is expired it gets flushed here. | |
| 4326 if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) { | |
| 4327 double interval = currentTime() - cachedPage->timeStamp(); | |
| 4328 | |
| 4329 // FIXME: 1800 should not be hardcoded, it should come from | |
| 4330 // WebKitBackForwardCacheExpirationIntervalKey in WebKit. | |
| 4331 // Or we should remove WebKitBackForwardCacheExpirationIntervalKey. | |
| 4332 if (interval <= 1800) { | |
| 4333 loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0
); | |
| 4334 inPageCache = true; | |
| 4335 } else { | |
| 4336 LOG(PageCache, "Not restoring page for %s from back/forward cach
e because cache entry has expired", m_provisionalHistoryItem->url().string().asc
ii().data()); | |
| 4337 pageCache()->remove(item); | |
| 4338 } | |
| 4339 } | |
| 4340 | |
| 4341 if (!inPageCache) { | |
| 4342 ResourceRequest request(itemURL); | |
| 4343 | |
| 4344 addExtraFieldsToRequest(request, true, formData); | |
| 4345 | |
| 4346 // If this was a repost that failed the page cache, we might try to
repost the form. | |
| 4347 NavigationAction action; | |
| 4348 if (formData) { | |
| 4349 | |
| 4350 formData->generateFiles(m_frame->page()->chrome()->client()); | |
| 4351 | |
| 4352 request.setHTTPMethod("POST"); | |
| 4353 request.setHTTPReferrer(item->formReferrer()); | |
| 4354 request.setHTTPBody(formData); | |
| 4355 request.setHTTPContentType(item->formContentType()); | |
| 4356 | |
| 4357 // FIXME: Slight hack to test if the NSURL cache contains the pa
ge we're going to. | |
| 4358 // We want to know this before talking to the policy delegate, s
ince it affects whether | |
| 4359 // we show the DoYouReallyWantToRepost nag. | |
| 4360 // | |
| 4361 // This trick has a small bug (3123893) where we might find a ca
che hit, but then | |
| 4362 // have the item vanish when we try to use it in the ensuing nav
. This should be | |
| 4363 // extremely rare, but in that case the user will get an error o
n the navigation. | |
| 4364 | |
| 4365 if (ResourceHandle::willLoadFromCache(request)) | |
| 4366 action = NavigationAction(itemURL, loadType, false); | |
| 4367 else { | |
| 4368 request.setCachePolicy(ReloadIgnoringCacheData); | |
| 4369 action = NavigationAction(itemURL, NavigationTypeFormResubmi
tted); | |
| 4370 } | |
| 4371 } else { | |
| 4372 switch (loadType) { | |
| 4373 case FrameLoadTypeReload: | |
| 4374 request.setCachePolicy(ReloadIgnoringCacheData); | |
| 4375 break; | |
| 4376 case FrameLoadTypeBack: | |
| 4377 case FrameLoadTypeForward: | |
| 4378 case FrameLoadTypeIndexedBackForward: | |
| 4379 if (itemURL.protocol() != "https") | |
| 4380 request.setCachePolicy(ReturnCacheDataElseLoad); | |
| 4381 break; | |
| 4382 case FrameLoadTypeStandard: | |
| 4383 case FrameLoadTypeRedirectWithLockedHistory: | |
| 4384 // no-op: leave as protocol default | |
| 4385 // FIXME: I wonder if we ever hit this case | |
| 4386 break; | |
| 4387 case FrameLoadTypeSame: | |
| 4388 case FrameLoadTypeReloadAllowingStaleData: | |
| 4389 default: | |
| 4390 ASSERT_NOT_REACHED(); | |
| 4391 } | |
| 4392 | |
| 4393 action = NavigationAction(itemOriginalURL, loadType, false); | |
| 4394 } | |
| 4395 | |
| 4396 loadWithNavigationAction(request, action, loadType, 0); | |
| 4397 } | |
| 4398 } | |
| 4399 } | |
| 4400 | |
| 4401 // Walk the frame tree and ensure that the URLs match the URLs in the item. | |
| 4402 bool FrameLoader::urlsMatchItem(HistoryItem* item) const | |
| 4403 { | |
| 4404 const KURL& currentURL = documentLoader()->url(); | |
| 4405 if (!equalIgnoringRef(currentURL, item->url())) | |
| 4406 return false; | |
| 4407 | |
| 4408 const HistoryItemVector& childItems = item->children(); | |
| 4409 | |
| 4410 unsigned size = childItems.size(); | |
| 4411 for (unsigned i = 0; i < size; ++i) { | |
| 4412 Frame* childFrame = m_frame->tree()->child(childItems[i]->target()); | |
| 4413 if (childFrame && !childFrame->loader()->urlsMatchItem(childItems[i].get
())) | |
| 4414 return false; | |
| 4415 } | |
| 4416 | |
| 4417 return true; | |
| 4418 } | |
| 4419 | |
| 4420 // Main funnel for navigating to a previous location (back/forward, non-search s
nap-back) | |
| 4421 // This includes recursion to handle loading into framesets properly | |
| 4422 void FrameLoader::goToItem(HistoryItem* targetItem, FrameLoadType type) | |
| 4423 { | |
| 4424 ASSERT(!m_frame->tree()->parent()); | |
| 4425 | |
| 4426 // shouldGoToHistoryItem is a private delegate method. This is needed to fix
: | |
| 4427 // <rdar://problem/3951283> can view pages from the back/forward cache that
should be disallowed by Parental Controls | |
| 4428 // Ultimately, history item navigations should go through the policy delegat
e. That's covered in: | |
| 4429 // <rdar://problem/3979539> back/forward cache navigations should consult po
licy delegate | |
| 4430 Page* page = m_frame->page(); | |
| 4431 if (!page) | |
| 4432 return; | |
| 4433 if (!m_client->shouldGoToHistoryItem(targetItem)) | |
| 4434 return; | |
| 4435 | |
| 4436 // Set the BF cursor before commit, which lets the user quickly click back/f
orward again. | |
| 4437 // - plus, it only makes sense for the top level of the operation through th
e frametree, | |
| 4438 // as opposed to happening for some/one of the page commits that might happe
n soon | |
| 4439 BackForwardList* bfList = page->backForwardList(); | |
| 4440 HistoryItem* currentItem = bfList->currentItem(); | |
| 4441 bfList->goToItem(targetItem); | |
| 4442 recursiveGoToItem(targetItem, currentItem, type); | |
| 4443 } | |
| 4444 | |
| 4445 // The general idea here is to traverse the frame tree and the item tree in para
llel, | |
| 4446 // tracking whether each frame already has the content the item requests. If th
ere is | |
| 4447 // a match (by URL), we just restore scroll position and recurse. Otherwise we
must | |
| 4448 // reload that frame, and all its kids. | |
| 4449 void FrameLoader::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, Fr
ameLoadType type) | |
| 4450 { | |
| 4451 ASSERT(item); | |
| 4452 ASSERT(fromItem); | |
| 4453 | |
| 4454 KURL itemURL = item->url(); | |
| 4455 KURL currentURL; | |
| 4456 if (documentLoader()) | |
| 4457 currentURL = documentLoader()->url(); | |
| 4458 | |
| 4459 // Always reload the target frame of the item we're going to. This ensures
that we will | |
| 4460 // do -some- load for the transition, which means a proper notification will
be posted | |
| 4461 // to the app. | |
| 4462 // The exact URL has to match, including fragment. We want to go through th
e _load | |
| 4463 // method, even if to do a within-page navigation. | |
| 4464 // The current frame tree and the frame tree snapshot in the item have to ma
tch. | |
| 4465 if (!item->isTargetItem() && | |
| 4466 itemURL == currentURL && | |
| 4467 ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_fr
ame->tree()->name() == item->target()) && | |
| 4468 childFramesMatchItem(item)) | |
| 4469 { | |
| 4470 // This content is good, so leave it alone and look for children that ne
ed reloading | |
| 4471 // Save form state (works from currentItem, since prevItem is nil) | |
| 4472 ASSERT(!m_previousHistoryItem); | |
| 4473 saveDocumentState(); | |
| 4474 saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); | |
| 4475 | |
| 4476 if (FrameView* view = m_frame->view()) | |
| 4477 view->setWasScrolledByUser(false); | |
| 4478 | |
| 4479 m_currentHistoryItem = item; | |
| 4480 | |
| 4481 // Restore form state (works from currentItem) | |
| 4482 restoreDocumentState(); | |
| 4483 | |
| 4484 // Restore the scroll position (we choose to do this rather than going b
ack to the anchor point) | |
| 4485 restoreScrollPositionAndViewState(); | |
| 4486 | |
| 4487 const HistoryItemVector& childItems = item->children(); | |
| 4488 | |
| 4489 int size = childItems.size(); | |
| 4490 for (int i = 0; i < size; ++i) { | |
| 4491 String childName = childItems[i]->target(); | |
| 4492 HistoryItem* fromChildItem = fromItem->childItemWithName(childName); | |
| 4493 ASSERT(fromChildItem || fromItem->isTargetItem()); | |
| 4494 Frame* childFrame = m_frame->tree()->child(childName); | |
| 4495 ASSERT(childFrame); | |
| 4496 childFrame->loader()->recursiveGoToItem(childItems[i].get(), fromChi
ldItem, type); | |
| 4497 } | |
| 4498 } else { | |
| 4499 loadItem(item, type); | |
| 4500 } | |
| 4501 } | |
| 4502 | |
| 4503 // helper method that determines whether the subframes described by the item's s
ubitems | |
| 4504 // match our own current frameset | |
| 4505 bool FrameLoader::childFramesMatchItem(HistoryItem* item) const | |
| 4506 { | |
| 4507 const HistoryItemVector& childItems = item->children(); | |
| 4508 if (childItems.size() != m_frame->tree()->childCount()) | |
| 4509 return false; | |
| 4510 | |
| 4511 unsigned size = childItems.size(); | |
| 4512 for (unsigned i = 0; i < size; ++i) | |
| 4513 if (!m_frame->tree()->child(childItems[i]->target())) | |
| 4514 return false; | |
| 4515 | |
| 4516 // Found matches for all item targets | |
| 4517 return true; | |
| 4518 } | |
| 4519 | |
| 4520 // There are 3 things you might think of as "history", all of which are handled
by these functions. | |
| 4521 // | |
| 4522 // 1) Back/forward: The m_currentHistoryItem is part of this mechanism. | |
| 4523 // 2) Global history: Handled by the client. | |
| 4524 // 3) Visited links: Handled by the PageGroup. | |
| 4525 | |
| 4526 void FrameLoader::updateHistoryForStandardLoad() | |
| 4527 { | |
| 4528 LOG(History, "WebCoreHistory: Updating History for Standard Load in frame %s
", documentLoader()->url().string().ascii().data()); | |
| 4529 | |
| 4530 Settings* settings = m_frame->settings(); | |
| 4531 bool needPrivacy = !settings || settings->privateBrowsingEnabled(); | |
| 4532 const KURL& historyURL = documentLoader()->urlForHistory(); | |
| 4533 | |
| 4534 // If the navigation occured during load and this is a subframe, update the
current | |
| 4535 // back/forward item rather than adding a new one and don't add the new URL
to global | |
| 4536 // history at all. But do add it to visited links. <rdar://problem/5333496> | |
| 4537 bool frameNavigationDuringLoad = false; | |
| 4538 if (m_navigationDuringLoad) { | |
| 4539 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); | |
| 4540 frameNavigationDuringLoad = owner && !owner->createdByParser(); | |
| 4541 m_navigationDuringLoad = false; | |
| 4542 } | |
| 4543 | |
| 4544 if (!frameNavigationDuringLoad && !documentLoader()->isClientRedirect()) { | |
| 4545 if (!historyURL.isEmpty()) { | |
| 4546 addBackForwardItemClippedAtTarget(true); | |
| 4547 if (!needPrivacy) | |
| 4548 m_client->updateGlobalHistory(historyURL); | |
| 4549 } | |
| 4550 } else if (documentLoader()->unreachableURL().isEmpty() && m_currentHistoryI
tem) { | |
| 4551 m_currentHistoryItem->setURL(documentLoader()->url()); | |
| 4552 m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->request()
); | |
| 4553 } | |
| 4554 | |
| 4555 if (!historyURL.isEmpty() && !needPrivacy) { | |
| 4556 if (Page* page = m_frame->page()) | |
| 4557 page->group().addVisitedLink(historyURL); | |
| 4558 } | |
| 4559 } | |
| 4560 | |
| 4561 void FrameLoader::updateHistoryForClientRedirect() | |
| 4562 { | |
| 4563 #if !LOG_DISABLED | |
| 4564 if (documentLoader()) | |
| 4565 LOG(History, "WebCoreHistory: Updating History for client redirect in fr
ame %s", documentLoader()->title().utf8().data()); | |
| 4566 #endif | |
| 4567 | |
| 4568 // Clear out form data so we don't try to restore it into the incoming page.
Must happen after | |
| 4569 // webcore has closed the URL and saved away the form state. | |
| 4570 if (m_currentHistoryItem) { | |
| 4571 m_currentHistoryItem->clearDocumentState(); | |
| 4572 m_currentHistoryItem->clearScrollPoint(); | |
| 4573 } | |
| 4574 | |
| 4575 Settings* settings = m_frame->settings(); | |
| 4576 bool needPrivacy = !settings || settings->privateBrowsingEnabled(); | |
| 4577 const KURL& historyURL = documentLoader()->urlForHistory(); | |
| 4578 | |
| 4579 if (!historyURL.isEmpty() && !needPrivacy) { | |
| 4580 if (Page* page = m_frame->page()) | |
| 4581 page->group().addVisitedLink(historyURL); | |
| 4582 } | |
| 4583 } | |
| 4584 | |
| 4585 void FrameLoader::updateHistoryForBackForwardNavigation() | |
| 4586 { | |
| 4587 #if !LOG_DISABLED | |
| 4588 if (documentLoader()) | |
| 4589 LOG(History, "WebCoreHistory: Updating History for back/forward navigati
on in frame %s", documentLoader()->title().utf8().data()); | |
| 4590 #endif | |
| 4591 | |
| 4592 // Must grab the current scroll position before disturbing it | |
| 4593 saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get()); | |
| 4594 } | |
| 4595 | |
| 4596 void FrameLoader::updateHistoryForReload() | |
| 4597 { | |
| 4598 #if !LOG_DISABLED | |
| 4599 if (documentLoader()) | |
| 4600 LOG(History, "WebCoreHistory: Updating History for reload in frame %s",
documentLoader()->title().utf8().data()); | |
| 4601 #endif | |
| 4602 | |
| 4603 if (m_currentHistoryItem) { | |
| 4604 pageCache()->remove(m_currentHistoryItem.get()); | |
| 4605 | |
| 4606 if (loadType() == FrameLoadTypeReload) | |
| 4607 saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); | |
| 4608 | |
| 4609 // Sometimes loading a page again leads to a different result because of
cookies. Bugzilla 4072 | |
| 4610 if (documentLoader()->unreachableURL().isEmpty()) | |
| 4611 m_currentHistoryItem->setURL(documentLoader()->requestURL()); | |
| 4612 } | |
| 4613 } | |
| 4614 | |
| 4615 void FrameLoader::updateHistoryForRedirectWithLockedHistory() | |
| 4616 { | |
| 4617 #if !LOG_DISABLED | |
| 4618 if (documentLoader()) | |
| 4619 LOG(History, "WebCoreHistory: Updating History for internal load in fram
e %s", documentLoader()->title().utf8().data()); | |
| 4620 #endif | |
| 4621 | |
| 4622 Settings* settings = m_frame->settings(); | |
| 4623 bool needPrivacy = !settings || settings->privateBrowsingEnabled(); | |
| 4624 const KURL& historyURL = documentLoader()->urlForHistory(); | |
| 4625 | |
| 4626 if (documentLoader()->isClientRedirect()) { | |
| 4627 if (!m_currentHistoryItem && !m_frame->tree()->parent()) { | |
| 4628 addBackForwardItemClippedAtTarget(true); | |
| 4629 if (!needPrivacy && !historyURL.isEmpty()) | |
| 4630 m_client->updateGlobalHistory(historyURL); | |
| 4631 } | |
| 4632 if (m_currentHistoryItem) { | |
| 4633 m_currentHistoryItem->setURL(documentLoader()->url()); | |
| 4634 m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->reque
st()); | |
| 4635 } | |
| 4636 } else { | |
| 4637 Frame* parentFrame = m_frame->tree()->parent(); | |
| 4638 if (parentFrame && parentFrame->loader()->m_currentHistoryItem) | |
| 4639 parentFrame->loader()->m_currentHistoryItem->addChildItem(createHist
oryItem(true)); | |
| 4640 } | |
| 4641 | |
| 4642 if (!historyURL.isEmpty() && !needPrivacy) { | |
| 4643 if (Page* page = m_frame->page()) | |
| 4644 page->group().addVisitedLink(historyURL); | |
| 4645 } | |
| 4646 } | |
| 4647 | |
| 4648 void FrameLoader::updateHistoryForCommit() | |
| 4649 { | |
| 4650 #if !LOG_DISABLED | |
| 4651 if (documentLoader()) | |
| 4652 LOG(History, "WebCoreHistory: Updating History for commit in frame %s",
documentLoader()->title().utf8().data()); | |
| 4653 #endif | |
| 4654 FrameLoadType type = loadType(); | |
| 4655 if (isBackForwardLoadType(type) || | |
| 4656 (type == FrameLoadTypeReload && !provisionalDocumentLoader()->unreachabl
eURL().isEmpty())) { | |
| 4657 // Once committed, we want to use current item for saving DocState, and | |
| 4658 // the provisional item for restoring state. | |
| 4659 // Note previousItem must be set before we close the URL, which will | |
| 4660 // happen when the data source is made non-provisional below | |
| 4661 m_previousHistoryItem = m_currentHistoryItem; | |
| 4662 ASSERT(m_provisionalHistoryItem); | |
| 4663 m_currentHistoryItem = m_provisionalHistoryItem; | |
| 4664 m_provisionalHistoryItem = 0; | |
| 4665 } | |
| 4666 } | |
| 4667 | |
| 4668 void FrameLoader::updateHistoryForAnchorScroll() | |
| 4669 { | |
| 4670 if (m_URL.isEmpty()) | |
| 4671 return; | |
| 4672 | |
| 4673 Settings* settings = m_frame->settings(); | |
| 4674 if (!settings || settings->privateBrowsingEnabled()) | |
| 4675 return; | |
| 4676 | |
| 4677 Page* page = m_frame->page(); | |
| 4678 if (!page) | |
| 4679 return; | |
| 4680 | |
| 4681 page->group().addVisitedLink(m_URL); | |
| 4682 } | |
| 4683 | |
| 4684 // Walk the frame tree, telling all frames to save their form state into their c
urrent | |
| 4685 // history item. | |
| 4686 void FrameLoader::saveDocumentAndScrollState() | |
| 4687 { | |
| 4688 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_fr
ame)) { | |
| 4689 frame->loader()->saveDocumentState(); | |
| 4690 frame->loader()->saveScrollPositionAndViewStateToItem(frame->loader()->c
urrentHistoryItem()); | |
| 4691 } | |
| 4692 } | |
| 4693 | |
| 4694 // FIXME: These 6 setter/getters are here for a dwindling number of users in Web
Kit, WebFrame | |
| 4695 // being the primary one. After they're no longer needed there, they can be rem
oved! | |
| 4696 HistoryItem* FrameLoader::currentHistoryItem() | |
| 4697 { | |
| 4698 return m_currentHistoryItem.get(); | |
| 4699 } | |
| 4700 | |
| 4701 HistoryItem* FrameLoader::previousHistoryItem() | |
| 4702 { | |
| 4703 return m_previousHistoryItem.get(); | |
| 4704 } | |
| 4705 | |
| 4706 HistoryItem* FrameLoader::provisionalHistoryItem() | |
| 4707 { | |
| 4708 return m_provisionalHistoryItem.get(); | |
| 4709 } | |
| 4710 | |
| 4711 void FrameLoader::setCurrentHistoryItem(PassRefPtr<HistoryItem> item) | |
| 4712 { | |
| 4713 m_currentHistoryItem = item; | |
| 4714 } | |
| 4715 | |
| 4716 void FrameLoader::setPreviousHistoryItem(PassRefPtr<HistoryItem> item) | |
| 4717 { | |
| 4718 m_previousHistoryItem = item; | |
| 4719 } | |
| 4720 | |
| 4721 void FrameLoader::setProvisionalHistoryItem(PassRefPtr<HistoryItem> item) | |
| 4722 { | |
| 4723 m_provisionalHistoryItem = item; | |
| 4724 } | |
| 4725 | |
| 4726 void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceErr
or& error) | |
| 4727 { | |
| 4728 m_client->setMainDocumentError(loader, error); | |
| 4729 } | |
| 4730 | |
| 4731 void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const Resour
ceError& error) | |
| 4732 { | |
| 4733 loader->setPrimaryLoadComplete(true); | |
| 4734 m_client->dispatchDidLoadMainResource(activeDocumentLoader()); | |
| 4735 checkCompleted(); | |
| 4736 if (m_frame->page()) | |
| 4737 checkLoadComplete(); | |
| 4738 } | |
| 4739 | |
| 4740 void FrameLoader::mainReceivedError(const ResourceError& error, bool isComplete) | |
| 4741 { | |
| 4742 activeDocumentLoader()->mainReceivedError(error, isComplete); | |
| 4743 } | |
| 4744 | |
| 4745 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const | |
| 4746 { | |
| 4747 ResourceError error = m_client->cancelledError(request); | |
| 4748 error.setIsCancellation(true); | |
| 4749 return error; | |
| 4750 } | |
| 4751 | |
| 4752 ResourceError FrameLoader::blockedError(const ResourceRequest& request) const | |
| 4753 { | |
| 4754 return m_client->blockedError(request); | |
| 4755 } | |
| 4756 | |
| 4757 ResourceError FrameLoader::cannotShowURLError(const ResourceRequest& request) co
nst | |
| 4758 { | |
| 4759 return m_client->cannotShowURLError(request); | |
| 4760 } | |
| 4761 | |
| 4762 ResourceError FrameLoader::fileDoesNotExistError(const ResourceResponse& respons
e) const | |
| 4763 { | |
| 4764 return m_client->fileDoesNotExistError(response); | |
| 4765 } | |
| 4766 | |
| 4767 void FrameLoader::didFinishLoad(ResourceLoader* loader) | |
| 4768 { | |
| 4769 if (Page* page = m_frame->page()) | |
| 4770 page->progress()->completeProgress(loader->identifier()); | |
| 4771 dispatchDidFinishLoading(loader->documentLoader(), loader->identifier()); | |
| 4772 } | |
| 4773 | |
| 4774 void FrameLoader::didReceiveAuthenticationChallenge(ResourceLoader* loader, cons
t AuthenticationChallenge& currentWebChallenge) | |
| 4775 { | |
| 4776 m_client->dispatchDidReceiveAuthenticationChallenge(loader->documentLoader()
, loader->identifier(), currentWebChallenge); | |
| 4777 } | |
| 4778 | |
| 4779 void FrameLoader::didCancelAuthenticationChallenge(ResourceLoader* loader, const
AuthenticationChallenge& currentWebChallenge) | |
| 4780 { | |
| 4781 m_client->dispatchDidCancelAuthenticationChallenge(loader->documentLoader(),
loader->identifier(), currentWebChallenge); | |
| 4782 } | |
| 4783 | |
| 4784 PolicyCheck::PolicyCheck() | |
| 4785 : m_navigationFunction(0) | |
| 4786 , m_newWindowFunction(0) | |
| 4787 , m_contentFunction(0) | |
| 4788 { | |
| 4789 } | |
| 4790 | |
| 4791 void PolicyCheck::clear() | |
| 4792 { | |
| 4793 clearRequest(); | |
| 4794 m_navigationFunction = 0; | |
| 4795 m_newWindowFunction = 0; | |
| 4796 m_contentFunction = 0; | |
| 4797 } | |
| 4798 | |
| 4799 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> form
State, | |
| 4800 NavigationPolicyDecisionFunction function, void* argument) | |
| 4801 { | |
| 4802 m_request = request; | |
| 4803 m_formState = formState; | |
| 4804 m_frameName = String(); | |
| 4805 | |
| 4806 m_navigationFunction = function; | |
| 4807 m_newWindowFunction = 0; | |
| 4808 m_contentFunction = 0; | |
| 4809 m_argument = argument; | |
| 4810 } | |
| 4811 | |
| 4812 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> form
State, | |
| 4813 const String& frameName, NewWindowPolicyDecisionFunction function, void* arg
ument) | |
| 4814 { | |
| 4815 m_request = request; | |
| 4816 m_formState = formState; | |
| 4817 m_frameName = frameName; | |
| 4818 | |
| 4819 m_navigationFunction = 0; | |
| 4820 m_newWindowFunction = function; | |
| 4821 m_contentFunction = 0; | |
| 4822 m_argument = argument; | |
| 4823 } | |
| 4824 | |
| 4825 void PolicyCheck::set(ContentPolicyDecisionFunction function, void* argument) | |
| 4826 { | |
| 4827 m_request = ResourceRequest(); | |
| 4828 m_formState = 0; | |
| 4829 m_frameName = String(); | |
| 4830 | |
| 4831 m_navigationFunction = 0; | |
| 4832 m_newWindowFunction = 0; | |
| 4833 m_contentFunction = function; | |
| 4834 m_argument = argument; | |
| 4835 } | |
| 4836 | |
| 4837 void PolicyCheck::call(bool shouldContinue) | |
| 4838 { | |
| 4839 if (m_navigationFunction) | |
| 4840 m_navigationFunction(m_argument, m_request, m_formState.get(), shouldCon
tinue); | |
| 4841 if (m_newWindowFunction) | |
| 4842 m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameNam
e, shouldContinue); | |
| 4843 ASSERT(!m_contentFunction); | |
| 4844 } | |
| 4845 | |
| 4846 void PolicyCheck::call(PolicyAction action) | |
| 4847 { | |
| 4848 ASSERT(!m_navigationFunction); | |
| 4849 ASSERT(!m_newWindowFunction); | |
| 4850 ASSERT(m_contentFunction); | |
| 4851 m_contentFunction(m_argument, action); | |
| 4852 } | |
| 4853 | |
| 4854 void PolicyCheck::clearRequest() | |
| 4855 { | |
| 4856 m_request = ResourceRequest(); | |
| 4857 m_formState = 0; | |
| 4858 m_frameName = String(); | |
| 4859 } | |
| 4860 | |
| 4861 void PolicyCheck::cancel() | |
| 4862 { | |
| 4863 clearRequest(); | |
| 4864 if (m_navigationFunction) | |
| 4865 m_navigationFunction(m_argument, m_request, m_formState.get(), false); | |
| 4866 if (m_newWindowFunction) | |
| 4867 m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameNam
e, false); | |
| 4868 if (m_contentFunction) | |
| 4869 m_contentFunction(m_argument, PolicyIgnore); | |
| 4870 } | |
| 4871 | |
| 4872 void FrameLoader::setTitle(const String& title) | |
| 4873 { | |
| 4874 documentLoader()->setTitle(title); | |
| 4875 } | |
| 4876 | |
| 4877 KURL FrameLoader::originalRequestURL() const | |
| 4878 { | |
| 4879 return activeDocumentLoader()->originalRequest().url(); | |
| 4880 } | |
| 4881 | |
| 4882 String FrameLoader::referrer() const | |
| 4883 { | |
| 4884 return documentLoader()->request().httpReferrer(); | |
| 4885 } | |
| 4886 | |
| 4887 void FrameLoader::dispatchWindowObjectAvailable() | |
| 4888 { | |
| 4889 // TODO(tc): We should also return early if we have no window shell. | |
| 4890 // But we can't check that until we refactor ScriptController. | |
| 4891 if (!m_frame->script()->isEnabled()) | |
| 4892 return; | |
| 4893 | |
| 4894 m_client->windowObjectCleared(); | |
| 4895 | |
| 4896 if (Page* page = m_frame->page()) { | |
| 4897 if (InspectorController* inspector = page->inspectorController()) | |
| 4898 inspector->inspectedWindowScriptObjectCleared(m_frame); | |
| 4899 if (InspectorController* inspector = page->parentInspectorController()) | |
| 4900 inspector->windowScriptObjectAvailable(); | |
| 4901 } | |
| 4902 } | |
| 4903 | |
| 4904 Widget* FrameLoader::createJavaAppletWidget(const IntSize& size, Element* elemen
t, const HashMap<String, String>& args) | |
| 4905 { | |
| 4906 String baseURLString; | |
| 4907 Vector<String> paramNames; | |
| 4908 Vector<String> paramValues; | |
| 4909 HashMap<String, String>::const_iterator end = args.end(); | |
| 4910 for (HashMap<String, String>::const_iterator it = args.begin(); it != end; +
+it) { | |
| 4911 if (equalIgnoringCase(it->first, "baseurl")) | |
| 4912 baseURLString = it->second; | |
| 4913 paramNames.append(it->first); | |
| 4914 paramValues.append(it->second); | |
| 4915 } | |
| 4916 | |
| 4917 if (baseURLString.isEmpty()) | |
| 4918 baseURLString = m_frame->document()->baseURL().string(); | |
| 4919 KURL baseURL = completeURL(baseURLString); | |
| 4920 | |
| 4921 Widget* widget = m_client->createJavaAppletWidget(size, element, baseURL, pa
ramNames, paramValues); | |
| 4922 if (widget) | |
| 4923 m_containsPlugIns = true; | |
| 4924 | |
| 4925 return widget; | |
| 4926 } | |
| 4927 | |
| 4928 void FrameLoader::didChangeTitle(DocumentLoader* loader) | |
| 4929 { | |
| 4930 m_client->didChangeTitle(loader); | |
| 4931 | |
| 4932 // The title doesn't get communicated to the WebView until we are committed. | |
| 4933 if (loader->isCommitted()) { | |
| 4934 // Must update the entries in the back-forward list too. | |
| 4935 if (m_currentHistoryItem) | |
| 4936 m_currentHistoryItem->setTitle(loader->title()); | |
| 4937 // This must go through the WebFrame because it has the right notion of
the current b/f item. | |
| 4938 m_client->setTitle(loader->title(), loader->urlForHistory()); | |
| 4939 m_client->setMainFrameDocumentReady(true); // update observers with new
DOMDocument | |
| 4940 m_client->dispatchDidReceiveTitle(loader->title()); | |
| 4941 } | |
| 4942 } | |
| 4943 | |
| 4944 void FrameLoader::continueLoadWithData(SharedBuffer* buffer, const String& mimeT
ype, const String& textEncoding, const KURL& url) | |
| 4945 { | |
| 4946 m_responseMIMEType = mimeType; | |
| 4947 didOpenURL(url); | |
| 4948 | |
| 4949 String encoding; | |
| 4950 if (m_frame) | |
| 4951 encoding = documentLoader()->overrideEncoding(); | |
| 4952 bool userChosen = !encoding.isNull(); | |
| 4953 if (encoding.isNull()) | |
| 4954 encoding = textEncoding; | |
| 4955 setEncoding(encoding, userChosen); | |
| 4956 | |
| 4957 ASSERT(m_frame->document()); | |
| 4958 | |
| 4959 addData(buffer->data(), buffer->size()); | |
| 4960 } | |
| 4961 | |
| 4962 void FrameLoader::registerURLSchemeAsLocal(const String& scheme) | |
| 4963 { | |
| 4964 localSchemes().add(scheme); | |
| 4965 } | |
| 4966 | |
| 4967 bool FrameLoader::shouldTreatURLAsLocal(const String& url) | |
| 4968 { | |
| 4969 // This avoids an allocation of another String and the HashSet contains() | |
| 4970 // call for the file: and http: schemes. | |
| 4971 if (url.length() >= 5) { | |
| 4972 const UChar* s = url.characters(); | |
| 4973 if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] ==
':') | |
| 4974 return false; | |
| 4975 if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] ==
':') | |
| 4976 return true; | |
| 4977 } | |
| 4978 | |
| 4979 int loc = url.find(':'); | |
| 4980 if (loc == -1) | |
| 4981 return false; | |
| 4982 | |
| 4983 String scheme = url.left(loc); | |
| 4984 return localSchemes().contains(scheme); | |
| 4985 } | |
| 4986 | |
| 4987 bool FrameLoader::shouldTreatSchemeAsLocal(const String& scheme) | |
| 4988 { | |
| 4989 // This avoids an allocation of another String and the HashSet contains() | |
| 4990 // call for the file: and http: schemes. | |
| 4991 if (scheme.length() == 4) { | |
| 4992 const UChar* s = scheme.characters(); | |
| 4993 if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p') | |
| 4994 return false; | |
| 4995 if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e') | |
| 4996 return true; | |
| 4997 } | |
| 4998 | |
| 4999 if (scheme.isEmpty()) | |
| 5000 return false; | |
| 5001 | |
| 5002 return localSchemes().contains(scheme); | |
| 5003 } | |
| 5004 | |
| 5005 void FrameLoader::dispatchDidCommitLoad() | |
| 5006 { | |
| 5007 if (m_creatingInitialEmptyDocument) | |
| 5008 return; | |
| 5009 | |
| 5010 #ifndef NDEBUG | |
| 5011 m_didDispatchDidCommitLoad = true; | |
| 5012 #endif | |
| 5013 | |
| 5014 m_client->dispatchDidCommitLoad(); | |
| 5015 | |
| 5016 if (Page* page = m_frame->page()) | |
| 5017 page->inspectorController()->didCommitLoad(m_documentLoader.get()); | |
| 5018 } | |
| 5019 | |
| 5020 void FrameLoader::dispatchAssignIdentifierToInitialRequest(unsigned long identif
ier, DocumentLoader* loader, const ResourceRequest& request) | |
| 5021 { | |
| 5022 m_client->assignIdentifierToInitialRequest(identifier, loader, request); | |
| 5023 | |
| 5024 if (Page* page = m_frame->page()) | |
| 5025 page->inspectorController()->identifierForInitialRequest(identifier, loa
der, request); | |
| 5026 } | |
| 5027 | |
| 5028 void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long
identifier, ResourceRequest& request, const ResourceResponse& redirectResponse) | |
| 5029 { | |
| 5030 m_client->dispatchWillSendRequest(loader, identifier, request, redirectRespo
nse); | |
| 5031 | |
| 5032 if (Page* page = m_frame->page()) | |
| 5033 page->inspectorController()->willSendRequest(loader, identifier, request
, redirectResponse); | |
| 5034 } | |
| 5035 | |
| 5036 void FrameLoader::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned lo
ng identifier, const ResourceResponse& r) | |
| 5037 { | |
| 5038 m_client->dispatchDidReceiveResponse(loader, identifier, r); | |
| 5039 | |
| 5040 if (Page* page = m_frame->page()) | |
| 5041 page->inspectorController()->didReceiveResponse(loader, identifier, r); | |
| 5042 } | |
| 5043 | |
| 5044 void FrameLoader::dispatchDidReceiveContentLength(DocumentLoader* loader, unsign
ed long identifier, int length) | |
| 5045 { | |
| 5046 m_client->dispatchDidReceiveContentLength(loader, identifier, length); | |
| 5047 | |
| 5048 if (Page* page = m_frame->page()) | |
| 5049 page->inspectorController()->didReceiveContentLength(loader, identifier,
length); | |
| 5050 } | |
| 5051 | |
| 5052 void FrameLoader::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long
identifier) | |
| 5053 { | |
| 5054 m_client->dispatchDidFinishLoading(loader, identifier); | |
| 5055 | |
| 5056 if (Page* page = m_frame->page()) | |
| 5057 page->inspectorController()->didFinishLoading(loader, identifier); | |
| 5058 } | |
| 5059 | |
| 5060 #if USE(LOW_BANDWIDTH_DISPLAY) | |
| 5061 | |
| 5062 bool FrameLoader::addLowBandwidthDisplayRequest(CachedResource* cache) | |
| 5063 { | |
| 5064 if (m_frame->document()->inLowBandwidthDisplay() == false) | |
| 5065 return false; | |
| 5066 | |
| 5067 // if cache is loaded, don't add to the list, where notifyFinished() is expe
cted. | |
| 5068 if (cache->isLoaded()) | |
| 5069 return false; | |
| 5070 | |
| 5071 switch (cache->type()) { | |
| 5072 case CachedResource::CSSStyleSheet: | |
| 5073 case CachedResource::Script: | |
| 5074 m_needToSwitchOutLowBandwidthDisplay = true; | |
| 5075 m_externalRequestsInLowBandwidthDisplay.add(cache); | |
| 5076 cache->addClient(this); | |
| 5077 return true; | |
| 5078 case CachedResource::ImageResource: | |
| 5079 case CachedResource::FontResource: | |
| 5080 #if ENABLE(XSLT) | |
| 5081 case CachedResource::XSLStyleSheet: | |
| 5082 #endif | |
| 5083 #if ENABLE(XBL) | |
| 5084 case CachedResource::XBLStyleSheet: | |
| 5085 #endif | |
| 5086 return false; | |
| 5087 } | |
| 5088 | |
| 5089 ASSERT_NOT_REACHED(); | |
| 5090 return false; | |
| 5091 } | |
| 5092 | |
| 5093 void FrameLoader::removeAllLowBandwidthDisplayRequests() | |
| 5094 { | |
| 5095 HashSet<CachedResource*>::iterator end = m_externalRequestsInLowBandwidthDis
play.end(); | |
| 5096 for (HashSet<CachedResource*>::iterator it = m_externalRequestsInLowBandwidt
hDisplay.begin(); it != end; ++it) | |
| 5097 (*it)->removeClient(this); | |
| 5098 m_externalRequestsInLowBandwidthDisplay.clear(); | |
| 5099 } | |
| 5100 | |
| 5101 void FrameLoader::notifyFinished(CachedResource* script) | |
| 5102 { | |
| 5103 HashSet<CachedResource*>::iterator it = m_externalRequestsInLowBandwidthDisp
lay.find(script); | |
| 5104 if (it != m_externalRequestsInLowBandwidthDisplay.end()) { | |
| 5105 (*it)->removeClient(this); | |
| 5106 m_externalRequestsInLowBandwidthDisplay.remove(it); | |
| 5107 switchOutLowBandwidthDisplayIfReady(); | |
| 5108 } | |
| 5109 } | |
| 5110 | |
| 5111 void FrameLoader::switchOutLowBandwidthDisplayIfReady() | |
| 5112 { | |
| 5113 RefPtr<Document> oldDoc = m_frame->document(); | |
| 5114 if (oldDoc->inLowBandwidthDisplay()) { | |
| 5115 if (!m_needToSwitchOutLowBandwidthDisplay) { | |
| 5116 // no need to switch, just reset state | |
| 5117 oldDoc->setLowBandwidthDisplay(false); | |
| 5118 removeAllLowBandwidthDisplayRequests(); | |
| 5119 m_pendingSourceInLowBandwidthDisplay = String(); | |
| 5120 m_finishedParsingDuringLowBandwidthDisplay = false; | |
| 5121 return; | |
| 5122 } else if (m_externalRequestsInLowBandwidthDisplay.isEmpty() || | |
| 5123 m_pendingSourceInLowBandwidthDisplay.length() > cMaxPendingSourceLen
gthInLowBandwidthDisplay) { | |
| 5124 // clear the flag first | |
| 5125 oldDoc->setLowBandwidthDisplay(false); | |
| 5126 | |
| 5127 // similar to clear(), should be refactored to share more code | |
| 5128 oldDoc->cancelParsing(); | |
| 5129 oldDoc->detach(); | |
| 5130 if (m_frame->script()->isEnabled()) | |
| 5131 m_frame->script()->clearWindowShell(); | |
| 5132 if (m_frame->view()) | |
| 5133 m_frame->view()->clear(); | |
| 5134 | |
| 5135 // similar to begin(), should be refactored to share more code | |
| 5136 RefPtr<Document> newDoc = DOMImplementation::createDocument(m_respon
seMIMEType, m_frame, m_frame->inViewSourceMode()); | |
| 5137 m_frame->setDocument(newDoc); | |
| 5138 newDoc->setURL(m_URL); | |
| 5139 if (m_decoder) | |
| 5140 newDoc->setDecoder(m_decoder.get()); | |
| 5141 restoreDocumentState(); | |
| 5142 dispatchWindowObjectAvailable(); | |
| 5143 newDoc->implicitOpen(); | |
| 5144 | |
| 5145 // swap DocLoader ownership | |
| 5146 DocLoader* docLoader = newDoc->docLoader(); | |
| 5147 newDoc->setDocLoader(oldDoc->docLoader()); | |
| 5148 newDoc->docLoader()->replaceDocument(newDoc.get()); | |
| 5149 docLoader->replaceDocument(oldDoc.get()); | |
| 5150 oldDoc->setDocLoader(docLoader); | |
| 5151 | |
| 5152 // drop the old doc | |
| 5153 oldDoc = 0; | |
| 5154 | |
| 5155 // write decoded data to the new doc, similar to write() | |
| 5156 if (m_pendingSourceInLowBandwidthDisplay.length()) { | |
| 5157 // set cachePolicy to Cache to use the loaded resource | |
| 5158 newDoc->docLoader()->setCachePolicy(CachePolicyCache); | |
| 5159 if (m_decoder->encoding().usesVisualOrdering()) | |
| 5160 newDoc->setVisuallyOrdered(); | |
| 5161 newDoc->recalcStyle(Node::Force); | |
| 5162 newDoc->tokenizer()->write(m_pendingSourceInLowBandwidthDisplay,
true); | |
| 5163 | |
| 5164 if (m_finishedParsingDuringLowBandwidthDisplay) | |
| 5165 newDoc->finishParsing(); | |
| 5166 } | |
| 5167 | |
| 5168 // update rendering | |
| 5169 newDoc->updateRendering(); | |
| 5170 | |
| 5171 // reset states | |
| 5172 removeAllLowBandwidthDisplayRequests(); | |
| 5173 m_pendingSourceInLowBandwidthDisplay = String(); | |
| 5174 m_finishedParsingDuringLowBandwidthDisplay = false; | |
| 5175 m_needToSwitchOutLowBandwidthDisplay = false; | |
| 5176 } | |
| 5177 } | |
| 5178 } | |
| 5179 | |
| 5180 #endif | |
| 5181 | |
| 5182 void FrameLoader::unloadListenerChanged() { | |
| 5183 m_client->unloadListenerChanged(); | |
| 5184 } | |
| 5185 | |
| 5186 } // namespace WebCore | |
| OLD | NEW |