Changeset 56875 in webkit
- Timestamp:
- Mar 31, 2010 4:22:23 PM (14 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r56872 r56875 1 2010-03-31 Adam Barth <abarth@webkit.org> 2 3 Reviewed by Darin Fisher. 4 5 Cleanup RedirectScheduler 6 https://bugs.webkit.org/show_bug.cgi?id=36874 7 8 Removed the nutty ScheduledRedirection struct in favor of a hierarchy 9 of classes to represent the various kinds of scheduled redirects. 10 Doing this lets us get rid of the pseudo RTTI switch statements on 11 "type" in favour of calling virtual functions. 12 13 No new tests because this change should be API identical with the 14 existing RedirectScheduler. 15 16 * loader/RedirectScheduler.cpp: 17 (WebCore::ScheduledNavigation::ScheduledNavigation): 18 (WebCore::ScheduledNavigation::~ScheduledNavigation): 19 (WebCore::ScheduledNavigation::isLocationChange): 20 (WebCore::ScheduledNavigation::shouldStartTimer): 21 (WebCore::ScheduledNavigation::didStartTimer): 22 (WebCore::ScheduledNavigation::didStopTimer): 23 (WebCore::ScheduledNavigation::delay): 24 (WebCore::ScheduledNavigation::lockHistory): 25 (WebCore::ScheduledNavigation::lockBackForwardList): 26 (WebCore::ScheduledNavigation::wasDuringLoad): 27 (WebCore::ScheduledURLNavigation::ScheduledURLNavigation): 28 (WebCore::ScheduledURLNavigation::fire): 29 (WebCore::ScheduledURLNavigation::didStartTimer): 30 (WebCore::ScheduledURLNavigation::didStopTimer): 31 (WebCore::ScheduledURLNavigation::url): 32 (WebCore::ScheduledURLNavigation::referrer): 33 (WebCore::ScheduledURLNavigation::wasUserGesture): 34 (WebCore::ScheduledRedirect::ScheduledRedirect): 35 (WebCore::ScheduledRedirect::isLocationChange): 36 (WebCore::ScheduledRedirect::shouldStartTimer): 37 (WebCore::ScheduledLocationChange::ScheduledLocationChange): 38 (WebCore::ScheduledRefresh::ScheduledRefresh): 39 (WebCore::ScheduledRefresh::fire): 40 (WebCore::ScheduledHistoryNavigation::ScheduledHistoryNavigation): 41 (WebCore::ScheduledHistoryNavigation::fire): 42 (WebCore::ScheduledFormSubmission::ScheduledFormSubmission): 43 (WebCore::ScheduledFormSubmission::fire): 44 (WebCore::RedirectScheduler::redirectScheduledDuringLoad): 45 (WebCore::RedirectScheduler::clear): 46 (WebCore::RedirectScheduler::scheduleRedirect): 47 (WebCore::RedirectScheduler::mustLockBackForwardList): 48 (WebCore::RedirectScheduler::scheduleLocationChange): 49 (WebCore::RedirectScheduler::scheduleFormSubmission): 50 (WebCore::RedirectScheduler::scheduleRefresh): 51 (WebCore::RedirectScheduler::locationChangePending): 52 (WebCore::RedirectScheduler::scheduleHistoryNavigation): 53 (WebCore::RedirectScheduler::timerFired): 54 (WebCore::RedirectScheduler::schedule): 55 (WebCore::RedirectScheduler::startTimer): 56 (WebCore::RedirectScheduler::cancel): 57 * loader/RedirectScheduler.h: 58 1 59 2010-03-31 Zhenyao Mo <zmo@google.com> 2 60 -
trunk/WebCore/loader/RedirectScheduler.cpp
r53950 r56875 48 48 namespace WebCore { 49 49 50 struct ScheduledRedirection : Noncopyable { 51 enum Type { redirection, locationChange, historyNavigation, formSubmission }; 52 53 const Type type; 54 const double delay; 55 const String url; 56 const String referrer; 57 const FrameLoadRequest frameRequest; 58 const RefPtr<Event> event; 59 const RefPtr<FormState> formState; 60 const int historySteps; 61 const bool lockHistory; 62 const bool lockBackForwardList; 63 const bool wasUserGesture; 64 const bool wasRefresh; 65 const bool wasDuringLoad; 66 bool toldClient; 67 68 ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh) 69 : type(redirection) 70 , delay(delay) 71 , url(url) 72 , historySteps(0) 73 , lockHistory(lockHistory) 74 , lockBackForwardList(lockBackForwardList) 75 , wasUserGesture(wasUserGesture) 76 , wasRefresh(refresh) 77 , wasDuringLoad(false) 78 , toldClient(false) 79 { 80 ASSERT(!url.isEmpty()); 81 } 82 83 ScheduledRedirection(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh, bool duringLoad) 84 : type(locationChange) 85 , delay(0) 86 , url(url) 87 , referrer(referrer) 88 , historySteps(0) 89 , lockHistory(lockHistory) 90 , lockBackForwardList(lockBackForwardList) 91 , wasUserGesture(wasUserGesture) 92 , wasRefresh(refresh) 93 , wasDuringLoad(duringLoad) 94 , toldClient(false) 95 { 96 ASSERT(!url.isEmpty()); 97 } 98 99 explicit ScheduledRedirection(int historyNavigationSteps) 100 : type(historyNavigation) 101 , delay(0) 102 , historySteps(historyNavigationSteps) 103 , lockHistory(false) 104 , lockBackForwardList(false) 105 , wasUserGesture(false) 106 , wasRefresh(false) 107 , wasDuringLoad(false) 108 , toldClient(false) 109 { 110 } 111 112 ScheduledRedirection(const FrameLoadRequest& frameRequest, 113 bool lockHistory, bool lockBackForwardList, PassRefPtr<Event> event, PassRefPtr<FormState> formState, 114 bool duringLoad) 115 : type(formSubmission) 116 , delay(0) 117 , frameRequest(frameRequest) 118 , event(event) 119 , formState(formState) 120 , historySteps(0) 121 , lockHistory(lockHistory) 122 , lockBackForwardList(lockBackForwardList) 123 , wasUserGesture(false) 124 , wasRefresh(false) 125 , wasDuringLoad(duringLoad) 126 , toldClient(false) 50 class ScheduledNavigation : public Noncopyable { 51 public: 52 ScheduledNavigation(double delay, bool lockHistory, bool lockBackForwardList, bool wasDuringLoad) 53 : m_delay(delay) 54 , m_lockHistory(lockHistory) 55 , m_lockBackForwardList(lockBackForwardList) 56 , m_wasDuringLoad(wasDuringLoad) 57 { 58 } 59 virtual ~ScheduledNavigation() { } 60 61 virtual void fire(Frame*) = 0; 62 63 // This method feels a bit like RTTI, but I don't see a cleaner way to get the behavior we want. 64 virtual bool isLocationChange() const { return true; } 65 66 virtual bool shouldStartTimer(Frame*) { return true; } 67 virtual void didStartTimer(Frame*, Timer<RedirectScheduler>*) { } 68 virtual void didStopTimer(Frame*, bool /* newLoadInProgress */) { } 69 70 double delay() const { return m_delay; } 71 bool lockHistory() const { return m_lockHistory; } 72 bool lockBackForwardList() const { return m_lockBackForwardList; } 73 bool wasDuringLoad() const { return m_wasDuringLoad; } 74 75 private: 76 double m_delay; 77 bool m_lockHistory; 78 bool m_lockBackForwardList; 79 bool m_wasDuringLoad; 80 }; 81 82 class ScheduledURLNavigation : public ScheduledNavigation { 83 public: 84 ScheduledURLNavigation(double delay, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool duringLoad) 85 : ScheduledNavigation(delay, lockHistory, lockBackForwardList, duringLoad) 86 , m_url(url) 87 , m_referrer(referrer) 88 , m_wasUserGesture(wasUserGesture) 89 , m_haveToldClient(false) 90 { 91 } 92 93 virtual void fire(Frame* frame) 94 { 95 frame->loader()->changeLocation(KURL(ParsedURLString, m_url), m_referrer, lockHistory(), lockBackForwardList(), m_wasUserGesture, false); 96 } 97 98 virtual void didStartTimer(Frame* frame, Timer<RedirectScheduler>* timer) 99 { 100 if (m_haveToldClient) 101 return; 102 m_haveToldClient = true; 103 frame->loader()->clientRedirected(KURL(ParsedURLString, m_url), delay(), currentTime() + timer->nextFireInterval(), lockBackForwardList()); 104 } 105 106 virtual void didStopTimer(Frame* frame, bool newLoadInProgress) 107 { 108 if (!m_haveToldClient) 109 return; 110 frame->loader()->clientRedirectCancelledOrFinished(newLoadInProgress); 111 } 112 113 String url() const { return m_url; } 114 String referrer() const { return m_referrer; } 115 bool wasUserGesture() const { return m_wasUserGesture; } 116 117 private: 118 String m_url; 119 String m_referrer; 120 bool m_wasUserGesture; 121 bool m_haveToldClient; 122 }; 123 124 class ScheduledRedirect : public ScheduledURLNavigation { 125 public: 126 ScheduledRedirect(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture) 127 : ScheduledURLNavigation(delay, url, String(), lockHistory, lockBackForwardList, wasUserGesture, false) { } 128 129 virtual bool isLocationChange() const { return false; } 130 virtual bool shouldStartTimer(Frame* frame) { return frame->loader()->allAncestorsAreComplete(); } 131 }; 132 133 class ScheduledLocationChange : public ScheduledURLNavigation { 134 public: 135 ScheduledLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool duringLoad) 136 : ScheduledURLNavigation(0.0, url, referrer, lockHistory, lockBackForwardList, wasUserGesture, duringLoad) { } 137 }; 138 139 class ScheduledRefresh : public ScheduledURLNavigation { 140 public: 141 ScheduledRefresh(const String& url, const String& referrer, bool wasUserGesture) 142 : ScheduledURLNavigation(0.0, url, referrer, true, true, wasUserGesture, false) { } 143 144 virtual void fire(Frame* frame) 145 { 146 frame->loader()->changeLocation(KURL(ParsedURLString, url()), referrer(), lockHistory(), lockBackForwardList(), wasUserGesture(), true); 147 } 148 }; 149 150 class ScheduledHistoryNavigation : public ScheduledNavigation { 151 public: 152 explicit ScheduledHistoryNavigation(int historySteps) : ScheduledNavigation(0, false, false, false), m_historySteps(historySteps) { } 153 154 virtual void fire(Frame* frame) 155 { 156 FrameLoader* loader = frame->loader(); 157 if (!m_historySteps) { 158 // Special case for go(0) from a frame -> reload only the frame 159 loader->urlSelected(loader->url(), "", 0, lockHistory(), lockBackForwardList(), false, SendReferrer); 160 return; 161 } 162 // go(i!=0) from a frame navigates into the history of the frame only, 163 // in both IE and NS (but not in Mozilla). We can't easily do that. 164 frame->page()->goBackOrForward(m_historySteps); 165 } 166 167 private: 168 int m_historySteps; 169 }; 170 171 class ScheduledFormSubmission : public ScheduledNavigation { 172 public: 173 ScheduledFormSubmission(const FrameLoadRequest& frameRequest, bool lockHistory, bool lockBackForwardList, PassRefPtr<Event> event, PassRefPtr<FormState> formState, bool duringLoad) 174 : ScheduledNavigation(0, lockHistory, lockBackForwardList, duringLoad) 175 , m_frameRequest(frameRequest) 176 , m_event(event) 177 , m_formState(formState) 127 178 { 128 179 ASSERT(!frameRequest.isEmpty()); 129 ASSERT(this->formState); 130 } 180 ASSERT(m_formState); 181 } 182 183 virtual void fire(Frame* frame) 184 { 185 // The submitForm function will find a target frame before using the redirection timer. 186 // Now that the timer has fired, we need to repeat the security check which normally is done when 187 // selecting a target, in case conditions have changed. Other code paths avoid this by targeting 188 // without leaving a time window. If we fail the check just silently drop the form submission. 189 if (!m_formState->sourceFrame()->loader()->shouldAllowNavigation(frame)) 190 return; 191 frame->loader()->loadFrameRequest(m_frameRequest, lockHistory(), lockBackForwardList(), m_event, m_formState, SendReferrer); 192 } 193 194 // FIXME: Implement didStartTimer? It would make sense to report form 195 // submissions as client redirects too. But we didn't do that in the past 196 // when form submission used a separate delay mechanism, so doing it will 197 // be a behavior change. 198 199 private: 200 const FrameLoadRequest m_frameRequest; 201 const RefPtr<Event> m_event; 202 const RefPtr<FormState> m_formState; 131 203 }; 132 204 … … 143 215 bool RedirectScheduler::redirectScheduledDuringLoad() 144 216 { 145 return m_ scheduledRedirection && m_scheduledRedirection->wasDuringLoad;217 return m_redirect && m_redirect->wasDuringLoad(); 146 218 } 147 219 … … 149 221 { 150 222 m_timer.stop(); 151 m_ scheduledRedirection.clear();223 m_redirect.clear(); 152 224 } 153 225 154 226 void RedirectScheduler::scheduleRedirect(double delay, const String& url) 155 227 { 228 if (!m_frame->page()) 229 return; 156 230 if (delay < 0 || delay > INT_MAX / 1000) 157 231 return; 158 159 if (!m_frame->page())160 return;161 162 232 if (url.isEmpty()) 163 233 return; 164 234 165 235 // We want a new history item if the refresh timeout is > 1 second. 166 if (!m_ scheduledRedirection || delay <= m_scheduledRedirection->delay)167 schedule(new ScheduledRedirect ion(delay, url, true, delay <= 1, false, false));236 if (!m_redirect || delay <= m_redirect->delay()) 237 schedule(new ScheduledRedirect(delay, url, true, delay <= 1, false)); 168 238 } 169 239 … … 173 243 // The definition of "during load" is any time before all handlers for the load event have been run. 174 244 // See https://bugs.webkit.org/show_bug.cgi?id=14957 for the original motivation for this. 175 245 176 246 for (Frame* ancestor = targetFrame->tree()->parent(); ancestor; ancestor = ancestor->tree()->parent()) { 177 247 Document* document = ancestor->document(); … … 186 256 if (!m_frame->page()) 187 257 return; 188 189 258 if (url.isEmpty()) 190 259 return; … … 206 275 bool duringLoad = !loader->committedFirstRealDocumentLoad(); 207 276 208 schedule(new Scheduled Redirection(url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false, duringLoad));277 schedule(new ScheduledLocationChange(url, referrer, lockHistory, lockBackForwardList, wasUserGesture, duringLoad)); 209 278 } 210 279 … … 228 297 bool lockBackForwardList = mustLockBackForwardList(m_frame) || (formState->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent()); 229 298 230 schedule(new Scheduled Redirection(frameRequest, lockHistory, lockBackForwardList, event, formState, duringLoad));299 schedule(new ScheduledFormSubmission(frameRequest, lockHistory, lockBackForwardList, event, formState, duringLoad)); 231 300 } 232 301 … … 235 304 if (!m_frame->page()) 236 305 return; 237 238 306 const KURL& url = m_frame->loader()->url(); 239 240 307 if (url.isEmpty()) 241 308 return; 242 309 243 schedule(new ScheduledRe direction(url.string(), m_frame->loader()->outgoingReferrer(), true, true, wasUserGesture, true, false));310 schedule(new ScheduledRefresh(url.string(), m_frame->loader()->outgoingReferrer(), wasUserGesture)); 244 311 } 245 312 246 313 bool RedirectScheduler::locationChangePending() 247 314 { 248 if (!m_ scheduledRedirection)315 if (!m_redirect) 249 316 return false; 250 251 switch (m_scheduledRedirection->type) { 252 case ScheduledRedirection::redirection: 253 return false; 254 case ScheduledRedirection::historyNavigation: 255 case ScheduledRedirection::locationChange: 256 case ScheduledRedirection::formSubmission: 257 return true; 258 } 259 ASSERT_NOT_REACHED(); 260 return false; 317 return m_redirect->isLocationChange(); 261 318 } 262 319 … … 285 342 286 343 // In all other cases, schedule the history traversal to occur asynchronously. 287 schedule(new Scheduled Redirection(steps));344 schedule(new ScheduledHistoryNavigation(steps)); 288 345 } 289 346 … … 292 349 if (!m_frame->page()) 293 350 return; 294 295 351 if (m_frame->page()->defersLoading()) 296 352 return; 297 353 298 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release()); 299 FrameLoader* loader = m_frame->loader(); 300 301 switch (redirection->type) { 302 case ScheduledRedirection::redirection: 303 case ScheduledRedirection::locationChange: 304 loader->changeLocation(KURL(ParsedURLString, redirection->url), redirection->referrer, 305 redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh); 306 return; 307 case ScheduledRedirection::historyNavigation: 308 if (redirection->historySteps == 0) { 309 // Special case for go(0) from a frame -> reload only the frame 310 loader->urlSelected(loader->url(), "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, SendReferrer); 311 return; 312 } 313 // go(i!=0) from a frame navigates into the history of the frame only, 314 // in both IE and NS (but not in Mozilla). We can't easily do that. 315 m_frame->page()->goBackOrForward(redirection->historySteps); 316 return; 317 case ScheduledRedirection::formSubmission: 318 // The submitForm function will find a target frame before using the redirection timer. 319 // Now that the timer has fired, we need to repeat the security check which normally is done when 320 // selecting a target, in case conditions have changed. Other code paths avoid this by targeting 321 // without leaving a time window. If we fail the check just silently drop the form submission. 322 if (!redirection->formState->sourceFrame()->loader()->shouldAllowNavigation(m_frame)) 323 return; 324 loader->loadFrameRequest(redirection->frameRequest, redirection->lockHistory, redirection->lockBackForwardList, 325 redirection->event, redirection->formState, SendReferrer); 326 return; 327 } 328 329 ASSERT_NOT_REACHED(); 330 } 331 332 void RedirectScheduler::schedule(PassOwnPtr<ScheduledRedirection> redirection) 354 OwnPtr<ScheduledNavigation> redirect(m_redirect.release()); 355 redirect->fire(m_frame); 356 } 357 358 void RedirectScheduler::schedule(PassOwnPtr<ScheduledNavigation> redirect) 333 359 { 334 360 ASSERT(m_frame->page()); 335 FrameLoader* loader = m_frame->loader();336 361 337 362 // If a redirect was scheduled during a load, then stop the current load. 338 363 // Otherwise when the current load transitions from a provisional to a 339 364 // committed state, pending redirects may be cancelled. 340 if (redirect ion->wasDuringLoad) {341 if (DocumentLoader* provisionalDocumentLoader = loader->provisionalDocumentLoader())365 if (redirect->wasDuringLoad()) { 366 if (DocumentLoader* provisionalDocumentLoader = m_frame->loader()->provisionalDocumentLoader()) 342 367 provisionalDocumentLoader->stopLoading(); 343 loader->stopLoading(UnloadEventPolicyUnloadAndPageHide);368 m_frame->loader()->stopLoading(UnloadEventPolicyUnloadAndPageHide); 344 369 } 345 370 346 371 cancel(); 347 m_scheduledRedirection = redirection; 348 if (!loader->isComplete() && m_scheduledRedirection->type != ScheduledRedirection::redirection) 349 loader->completed(); 372 m_redirect = redirect; 373 374 if (!m_frame->loader()->isComplete() && m_redirect->isLocationChange()) 375 m_frame->loader()->completed(); 376 350 377 startTimer(); 351 378 } … … 353 380 void RedirectScheduler::startTimer() 354 381 { 355 if (!m_ scheduledRedirection)382 if (!m_redirect) 356 383 return; 357 384 358 385 ASSERT(m_frame->page()); 359 360 FrameLoader* loader = m_frame->loader();361 362 386 if (m_timer.isActive()) 363 387 return; 364 365 if (m_scheduledRedirection->type == ScheduledRedirection::redirection && !loader->allAncestorsAreComplete()) 366 return; 367 368 m_timer.startOneShot(m_scheduledRedirection->delay); 369 370 switch (m_scheduledRedirection->type) { 371 case ScheduledRedirection::locationChange: 372 case ScheduledRedirection::redirection: 373 if (m_scheduledRedirection->toldClient) 374 return; 375 m_scheduledRedirection->toldClient = true; 376 loader->clientRedirected(KURL(ParsedURLString, m_scheduledRedirection->url), 377 m_scheduledRedirection->delay, 378 currentTime() + m_timer.nextFireInterval(), 379 m_scheduledRedirection->lockBackForwardList); 380 return; 381 case ScheduledRedirection::formSubmission: 382 // FIXME: It would make sense to report form submissions as client redirects too. 383 // But we didn't do that in the past when form submission used a separate delay 384 // mechanism, so doing it will be a behavior change. 385 return; 386 case ScheduledRedirection::historyNavigation: 387 // Don't report history navigations. 388 return; 389 } 390 ASSERT_NOT_REACHED(); 388 if (!m_redirect->shouldStartTimer(m_frame)) 389 return; 390 391 m_timer.startOneShot(m_redirect->delay()); 392 m_redirect->didStartTimer(m_frame, &m_timer); 391 393 } 392 394 … … 395 397 m_timer.stop(); 396 398 397 OwnPtr<Scheduled Redirection> redirection(m_scheduledRedirection.release());398 if (redirect ion && redirection->toldClient)399 m_frame->loader()->clientRedirectCancelledOrFinished(newLoadInProgress);399 OwnPtr<ScheduledNavigation> redirect(m_redirect.release()); 400 if (redirect) 401 redirect->didStopTimer(m_frame, newLoadInProgress); 400 402 } 401 403 -
trunk/WebCore/loader/RedirectScheduler.h
r49706 r56875 45 45 46 46 struct FrameLoadRequest; 47 struct ScheduledRedirection;47 class ScheduledNavigation; 48 48 49 49 class RedirectScheduler : public Noncopyable { … … 68 68 private: 69 69 void timerFired(Timer<RedirectScheduler>*); 70 void schedule(PassOwnPtr<Scheduled Redirection>);70 void schedule(PassOwnPtr<ScheduledNavigation>); 71 71 72 72 static bool mustLockBackForwardList(Frame* targetFrame); … … 74 74 Frame* m_frame; 75 75 Timer<RedirectScheduler> m_timer; 76 OwnPtr<Scheduled Redirection> m_scheduledRedirection;76 OwnPtr<ScheduledNavigation> m_redirect; 77 77 }; 78 78
Note: See TracChangeset
for help on using the changeset viewer.