Commit 7ce491ff authored by rjw's avatar rjw

Added support to pause and resume javascript timers. This allows pages

        that have javascript timers to be added to the page cache.

        Fixes 3126138.

        Reviewed by trey and maciej.

        * khtml/ecma/kjs_window.cpp:
        (Window::pauseTimeouts):
        (Window::resumeTimeouts):
        (WindowQObject::pauseTimeouts):
        (WindowQObject::resumeTimeouts):
        (WindowQObject::timerEvent):
        * khtml/ecma/kjs_window.h:
        * kwq/KWQKHTMLPart.h:
        * kwq/KWQKHTMLPart.mm:
        (KWQKHTMLPart::pauseActions):
        (KWQKHTMLPart::resumeActions):
        (KWQKHTMLPart::canCachePage):
        (KWQKHTMLPart::openURLFromPageCache):
        * kwq/KWQObject.h:
        * kwq/KWQObject.mm:
        (QObject::pauseTimer):
        (QObject::_addTimer):
        (QObject::clearPausedTimers):
        (QObject::resumeTimers):
        (QObject::startTimer):
        * kwq/KWQPageState.h:
        * kwq/KWQPageState.mm:
        (-[KWQPageState initWithDocument:URL:windowProperties:locationProperties:]):
        (-[KWQPageState setPausedActions:int::]):
        (-[KWQPageState int::]):
        (-[KWQPageState _cleanupPausedActions]):
        (-[KWQPageState invalidate]):
        (-[KWQPageState dealloc]):
        * kwq/WebCoreBridge.mm:
        (-[WebCoreBridge openURL:reload:contentType:refresh:lastModified:pageCache:]):
        (-[WebCoreBridge saveDocumentToPageCache]):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@3370 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 4a401611
2003-01-21 Richard Williamson <rjw@apple.com>
Added support to pause and resume javascript timers. This allows pages
that have javascript timers to be added to the page cache.
Fixes 3126138.
Reviewed by trey and maciej.
* khtml/ecma/kjs_window.cpp:
(Window::pauseTimeouts):
(Window::resumeTimeouts):
(WindowQObject::pauseTimeouts):
(WindowQObject::resumeTimeouts):
(WindowQObject::timerEvent):
* khtml/ecma/kjs_window.h:
* kwq/KWQKHTMLPart.h:
* kwq/KWQKHTMLPart.mm:
(KWQKHTMLPart::pauseActions):
(KWQKHTMLPart::resumeActions):
(KWQKHTMLPart::canCachePage):
(KWQKHTMLPart::openURLFromPageCache):
* kwq/KWQObject.h:
* kwq/KWQObject.mm:
(QObject::pauseTimer):
(QObject::_addTimer):
(QObject::clearPausedTimers):
(QObject::resumeTimers):
(QObject::startTimer):
* kwq/KWQPageState.h:
* kwq/KWQPageState.mm:
(-[KWQPageState initWithDocument:URL:windowProperties:locationProperties:]):
(-[KWQPageState setPausedActions:int::]):
(-[KWQPageState int::]):
(-[KWQPageState _cleanupPausedActions]):
(-[KWQPageState invalidate]):
(-[KWQPageState dealloc]):
* kwq/WebCoreBridge.mm:
(-[WebCoreBridge openURL:reload:contentType:refresh:lastModified:pageCache:]):
(-[WebCoreBridge saveDocumentToPageCache]):
2003-01-21 Darin Adler <darin@apple.com>
* khtml/xml/dom_nodeimpl.cpp: (NodeImpl::createRenderer):
......
2003-01-21 Richard Williamson <rjw@apple.com>
Added support to pause and resume javascript timers. This allows pages
that have javascript timers to be added to the page cache.
Fixes 3126138.
Reviewed by trey and maciej.
* khtml/ecma/kjs_window.cpp:
(Window::pauseTimeouts):
(Window::resumeTimeouts):
(WindowQObject::pauseTimeouts):
(WindowQObject::resumeTimeouts):
(WindowQObject::timerEvent):
* khtml/ecma/kjs_window.h:
* kwq/KWQKHTMLPart.h:
* kwq/KWQKHTMLPart.mm:
(KWQKHTMLPart::pauseActions):
(KWQKHTMLPart::resumeActions):
(KWQKHTMLPart::canCachePage):
(KWQKHTMLPart::openURLFromPageCache):
* kwq/KWQObject.h:
* kwq/KWQObject.mm:
(QObject::pauseTimer):
(QObject::_addTimer):
(QObject::clearPausedTimers):
(QObject::resumeTimers):
(QObject::startTimer):
* kwq/KWQPageState.h:
* kwq/KWQPageState.mm:
(-[KWQPageState initWithDocument:URL:windowProperties:locationProperties:]):
(-[KWQPageState setPausedActions:int::]):
(-[KWQPageState int::]):
(-[KWQPageState _cleanupPausedActions]):
(-[KWQPageState invalidate]):
(-[KWQPageState dealloc]):
* kwq/WebCoreBridge.mm:
(-[WebCoreBridge openURL:reload:contentType:refresh:lastModified:pageCache:]):
(-[WebCoreBridge saveDocumentToPageCache]):
2003-01-21 Darin Adler <darin@apple.com>
* khtml/xml/dom_nodeimpl.cpp: (NodeImpl::createRenderer):
......
......@@ -884,6 +884,16 @@ bool Window::hasTimeouts()
{
return winq->hasTimeouts();
}
QMap<int, ScheduledAction*> *Window::pauseTimeouts(const void *key)
{
return winq->pauseTimeouts(key);
}
void Window::resumeTimeouts(QMap<int, ScheduledAction*> *sa, const void *key)
{
return winq->resumeTimeouts(sa, key);
}
#endif
void Window::scheduleClose()
......@@ -1537,6 +1547,31 @@ int WindowQObject::installTimeout(const Value &func, List args, int t, bool sing
return id;
}
QMap<int, ScheduledAction*> *WindowQObject::pauseTimeouts(const void *key)
{
QMapIterator<int,ScheduledAction*> it;
QMap<int, KJS::ScheduledAction*>*pausedActions = new QMap<int, KJS::ScheduledAction*>;
for (it = scheduledActions.begin(); it != scheduledActions.end(); ++it) {
int timerId = it.key();
pauseTimer (timerId, key);
pausedActions->insert(timerId, it.data());
}
scheduledActions.clear();
return pausedActions;
}
void WindowQObject::resumeTimeouts(QMap<int, ScheduledAction*> *sa, const void *key)
{
QMapIterator<int,ScheduledAction*> it;
for (it = sa->begin(); it != sa->end(); ++it) {
int timerId = it.key();
scheduledActions.insert(timerId, it.data());
}
sa->clear();
resumeTimers (key, this);
}
void WindowQObject::clearTimeout(int timerId, bool delAction)
{
//kdDebug(6070) << "WindowQObject::clearTimeout " << this << " timerId=" << timerId << " delAction=" << delAction << endl;
......@@ -1565,6 +1600,7 @@ void WindowQObject::timerEvent(QTimerEvent *e)
clearTimeout(e->timerId(),false);
scheduledActions.remove(it);
}
if (!parent->part().isNull())
action->execute(parent);
......
......@@ -92,6 +92,8 @@ namespace KJS {
void clearTimeout(int timerId);
#ifdef APPLE_CHANGES
bool hasTimeouts();
QMap<int, ScheduledAction*> *pauseTimeouts(const void *key);
void resumeTimeouts(QMap<int, ScheduledAction*>*sa, const void *key);
#endif
void scheduleClose();
bool isSafeScript(ExecState *exec) const;
......@@ -162,6 +164,8 @@ namespace KJS {
void clearTimeout(int timerId, bool delAction = true);
#ifdef APPLE_CHANGES
bool hasTimeouts();
QMap<int, ScheduledAction*> *WindowQObject::pauseTimeouts(const void *key);
void WindowQObject::resumeTimeouts(QMap<int, ScheduledAction*> *sa, const void *key);
#endif
public slots:
......
......@@ -30,6 +30,8 @@
#include "dom_nodeimpl.h"
#include <CoreFoundation/CoreFoundation.h>
class KHTMLPartPrivate;
namespace khtml {
......@@ -38,6 +40,7 @@ namespace khtml {
namespace KJS {
class SavedProperties;
class ScheduledAction;
}
#ifdef __OBJC__
......@@ -46,12 +49,14 @@ namespace KJS {
@class NSResponder;
@class NSView;
@class WebCoreBridge;
@class KWQPageState;
#else
class NSAttributedString;
class NSEvent;
class NSResponder;
class NSView;
class WebCoreBridge;
class KWQPageState;
#endif
enum KWQSelectionDirection {
......@@ -95,13 +100,15 @@ public:
void unfocusWindow();
QMap<int, KJS::ScheduledAction*> *pauseActions(const void *key);
void resumeActions(QMap<int, KJS::ScheduledAction*> *actions, const void *key);
bool canCachePage();
void saveWindowProperties(KJS::SavedProperties *windowProperties);
void saveLocationProperties(KJS::SavedProperties *locationProperties);
void restoreWindowProperties(KJS::SavedProperties *windowProperties);
void restoreLocationProperties(KJS::SavedProperties *locationProperties);
void openURLFromPageCache(DOM::DocumentImpl *, RenderObject *, KURL *,
KJS::SavedProperties *windowProperties, KJS::SavedProperties *locationProperties);
void openURLFromPageCache(KWQPageState *state);
void saveDocumentState();
void restoreDocumentState();
......
......@@ -40,6 +40,7 @@
#import "KWQDummyView.h"
#import "KWQKJobClasses.h"
#import "KWQLogging.h"
#import "KWQPageState.h"
#import "xml/dom2_eventsimpl.h"
......@@ -469,13 +470,32 @@ NSView *KWQKHTMLPart::nextKeyViewForWidget(QWidget *startingWidget, KWQSelection
return partForNode(node)->nextKeyView(node, direction);
}
QMap<int, KJS::ScheduledAction*> *KWQKHTMLPart::pauseActions(const void *key)
{
if (d->m_doc && d->m_jscript) {
KJS::Window *w = KJS::Window::retrieveWindow(this);
if (w && w->hasTimeouts()) {
return w->pauseTimeouts(key);
}
}
return 0;
}
void KWQKHTMLPart::resumeActions(QMap<int, KJS::ScheduledAction*> *actions, const void *key)
{
if (d->m_doc && d->m_jscript) {
KJS::Window *w = KJS::Window::retrieveWindow(this);
w->resumeTimeouts(actions, key);
}
}
bool KWQKHTMLPart::canCachePage()
{
// Only save page state if:
// 1. We're not a frame or frameset.
// 2. The page has no unload handler.
// 3. The page has no password fields.
// 4. The page has no javascript timers.
if (d->m_doc &&
(d->m_frames.count() ||
parentPart() ||
......@@ -483,12 +503,6 @@ bool KWQKHTMLPart::canCachePage()
d->m_doc->hasPasswordField())) {
return false;
}
if (d->m_doc && d->m_jscript) {
Window *w = Window::retrieveWindow(this);
if (w && w->hasTimeouts()) {
return false;
}
}
return true;
}
......@@ -524,8 +538,15 @@ void KWQKHTMLPart::restoreLocationProperties(SavedProperties *locationProperties
window->location()->restoreProperties(*locationProperties);
}
void KWQKHTMLPart::openURLFromPageCache(DocumentImpl *doc, RenderObject *renderer, KURL *url, SavedProperties *windowProperties, SavedProperties *locationProperties)
void KWQKHTMLPart::openURLFromPageCache(KWQPageState *state)
{
DocumentImpl *doc = [state document];
RenderObject *renderer = [state renderer];
KURL *url = [state URL];
SavedProperties *windowProperties = [state windowProperties];
SavedProperties *locationProperties = [state locationProperties];
QMap<int, KJS::ScheduledAction*> *actions = [state pausedActions];
d->m_redirectionTimer.stop();
// We still have to close the previous part page.
......@@ -585,6 +606,9 @@ void KWQKHTMLPart::openURLFromPageCache(DocumentImpl *doc, RenderObject *rendere
restoreWindowProperties (windowProperties);
restoreLocationProperties (locationProperties);
if (actions)
resumeActions (actions, state);
checkCompleted();
}
......
......@@ -67,6 +67,12 @@ class QVariant;
class KWQGuardedPtrBase;
class KWQSignal;
#ifdef __OBJC__
@class NSTimer;
#else
class NSTimer;
#endif
class QObject : public Qt {
public:
QObject(QObject *parent = 0, const char *name = 0);
......@@ -82,6 +88,10 @@ public:
int startTimer(int);
void killTimer(int);
void killTimers();
void pauseTimer(int _timerId, const void *key);
void resumeTimers(const void *key, QObject *target);
static void clearPausedTimers (const void *key);
virtual void timerEvent(QTimerEvent *);
void installEventFilter(const QObject *o) { _eventFilterObject = o; }
......@@ -97,6 +107,8 @@ public:
static const QObject *sender() { return _sender; }
private:
void _addTimer(NSTimer *timer, int _timerId);
// no copying or assignment
QObject(const QObject &);
QObject &operator=(const QObject &);
......
......@@ -31,11 +31,13 @@
const QObject *QObject::_sender;
static CFMutableDictionaryRef timerDictionaries;
static CFMutableDictionaryRef allPausedTimers;
@interface KWQObjectTimerTarget : NSObject
{
QObject *target;
int timerId;
NSTimeInterval remainingTime;
}
- initWithQObject:(QObject *)object timerId:(int)timerId;
......@@ -131,10 +133,94 @@ bool QObject::event(QEvent *)
return false;
}
int QObject::startTimer(int milliseconds)
void QObject::pauseTimer (int _timerId, const void *key)
{
static int nextTimerID = 1;
NSMutableDictionary *timers = (NSMutableDictionary *)CFDictionaryGetValue(timerDictionaries, this);
NSNumber *timerId = [NSNumber numberWithInt:_timerId];
NSTimer *timer = (NSTimer *)[timers objectForKey:timerId];
KWQObjectTimerTarget *target = (KWQObjectTimerTarget *)[timer userInfo];
if (target && [timer isValid]){
NSDate *fireDate = [timer fireDate];
NSTimeInterval remainingTime = [fireDate timeIntervalSinceDate: [NSDate date]];
if (remainingTime < 0)
remainingTime = DBL_EPSILON;
if (allPausedTimers == NULL) {
// The global targets dictionary itself leaks, but the contents are removed
// when each timer fires or is killed.
allPausedTimers = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks);
}
NSMutableArray *pausedTimers = (NSMutableArray *)CFDictionaryGetValue(allPausedTimers, key);
if (pausedTimers == nil) {
pausedTimers = [[NSMutableArray alloc] init];
CFDictionarySetValue(allPausedTimers, key, pausedTimers);
[pausedTimers release];
}
target->remainingTime = remainingTime;
[pausedTimers addObject:target];
[timer invalidate];
[timers removeObjectForKey:timerId];
}
}
void QObject::_addTimer(NSTimer *timer, int _timerId)
{
NSMutableDictionary *timers = (NSMutableDictionary *)CFDictionaryGetValue(timerDictionaries, this);
if (timers == nil) {
timers = [[NSMutableDictionary alloc] init];
CFDictionarySetValue(timerDictionaries, this, timers);
[timers release];
}
[timers setObject:timer forKey:[NSNumber numberWithInt:_timerId]];
}
static int nextTimerID = 1;
void QObject::clearPausedTimers (const void *key)
{
if (allPausedTimers)
CFDictionaryRemoveValue(allPausedTimers, key);
}
void QObject::resumeTimers (const void *key, QObject *_target)
{
if (allPausedTimers == NULL) {
return;
}
int maxId = MAX(0, nextTimerID);
NSMutableArray *pausedTimers = (NSMutableArray *)CFDictionaryGetValue(allPausedTimers, key);
if (pausedTimers == nil)
return;
int count = [pausedTimers count];
while (count--){
KWQObjectTimerTarget *target = [pausedTimers objectAtIndex: count];
target->target = _target;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:target->remainingTime
target:target
selector:@selector(timerFired)
userInfo:target
repeats:YES];
[pausedTimers removeLastObject];
maxId = MAX (maxId, target->timerId);
_addTimer (timer, target->timerId);
}
nextTimerID = maxId+1;
CFDictionaryRemoveValue(allPausedTimers, key);
}
int QObject::startTimer(int milliseconds)
{
if (timerDictionaries == NULL) {
// The global timers dictionary itself leaks, but the contents are removed
// when each timer fires or is killed.
......@@ -156,7 +242,7 @@ int QObject::startTimer(int milliseconds)
repeats:YES];
[target release];
[timers setObject:timer forKey:[NSNumber numberWithInt:nextTimerID]];
_addTimer (timer, nextTimerID);
return nextTimerID++;
}
......
......@@ -25,6 +25,10 @@
#import <Foundation/Foundation.h>
#include <qmap.h>
#include "kjs_window.h"
class KURL;
namespace DOM {
......@@ -46,6 +50,7 @@ namespace KJS {
KJS::SavedProperties *windowProperties;
KJS::SavedProperties *locationProperties;
khtml::RenderObject *docRenderer;
QMap<int, KJS::ScheduledAction*> *pausedActions;
}
- initWithDocument:(DOM::DocumentImpl *)doc URL:(const KURL &)u windowProperties:(KJS::SavedProperties *)wp locationProperties:(KJS::SavedProperties *)lp;
......@@ -55,7 +60,8 @@ namespace KJS {
- (KJS::SavedProperties *)windowProperties;
- (KJS::SavedProperties *)locationProperties;
- (khtml::RenderObject *)renderer;
- (void)setPausedActions: (QMap<int, KJS::ScheduledAction*> *)pa;
- (QMap<int, KJS::ScheduledAction*> *)pausedActions;
- (void)invalidate;
@end
......@@ -29,6 +29,7 @@
#import "dom_docimpl.h"
#import "khtmlview.h"
#import "kjs_window.h"
#import "KWQAssertions.h"
#import "KWQKHTMLPart.h"
......@@ -49,9 +50,34 @@ using KJS::SavedProperties;
URL = new KURL(u);
windowProperties = wp;
locationProperties = lp;
return self;
}
- (void)setPausedActions: (QMap<int, KJS::ScheduledAction*> *)pa
{
pausedActions = pa;
}
- (QMap<int, KJS::ScheduledAction*> *)pausedActions
{
return pausedActions;
}
- (void)_cleanupPausedActions
{
if (pausedActions){
QMapIterator<int,KJS::ScheduledAction*> it;
for (it = pausedActions->begin(); it != pausedActions->end(); ++it) {
KJS::ScheduledAction *action = *it;
delete action;
}
delete pausedActions;
pausedActions = 0;
}
QObject::clearPausedTimers(self);
}
// Called when the KWQPageState is restored. It should relinquish ownership
// of objects to core.
- (void)invalidate
......@@ -66,6 +92,8 @@ using KJS::SavedProperties;
delete URL;
URL = 0;
[self _cleanupPausedActions];
delete windowProperties;
windowProperties = 0;
delete locationProperties;
......@@ -97,6 +125,8 @@ using KJS::SavedProperties;
delete URL;
delete windowProperties;
delete locationProperties;
[self _cleanupPausedActions];
[super dealloc];
}
......
......@@ -143,7 +143,7 @@ static bool initializedObjectCacheSize = FALSE;
{
if (pageCache) {
KWQPageState *state = [pageCache objectForKey:@"WebCorePageState"];
_part->openURLFromPageCache([state document], [state renderer], [state URL], [state windowProperties], [state locationProperties]);
_part->openURLFromPageCache(state);
[state invalidate];
return;
}
......@@ -240,6 +240,9 @@ static bool initializedObjectCacheSize = FALSE;
windowProperties:windowProperties
locationProperties:locationProperties] autorelease];
[pageState setPausedActions: _part->pauseActions((const void *)pageState)];
return [self saveDocumentToPageCache:pageState];
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment