Reviewed by Maciej.
[WebKit-https.git] / WebKitTools / Drosera / DebuggerDocument.m
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "DebuggerDocument.h"
30 #import "DebuggerApplication.h"
31
32 static NSString *DebuggerConsoleToolbarItem = @"DebuggerConsoleToolbarItem";
33 static NSString *DebuggerContinueToolbarItem = @"DebuggerContinueToolbarItem";
34 static NSString *DebuggerPauseToolbarItem = @"DebuggerPauseToolbarItem";
35 static NSString *DebuggerStepIntoToolbarItem = @"DebuggerStepIntoToolbarItem";
36 static NSString *DebuggerStepOverToolbarItem = @"DebuggerStepOverToolbarItem";
37 static NSString *DebuggerStepOutToolbarItem = @"DebuggerStepOutToolbarItem";
38
39 @interface WebScriptObject (WebScriptObjectPrivate)
40 - (unsigned int)count;
41 @end
42
43 @implementation DebuggerDocument
44 + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
45 {
46     return NO;
47 }
48
49 + (BOOL)isKeyExcludedFromWebScript:(const char *)name
50 {
51     return NO;
52 }
53
54 #pragma mark -
55
56 - (id)initWithServerName:(NSString *)serverName
57 {
58     if ((self = [super init]))
59         [self switchToServerNamed:serverName];
60     return self;
61 }
62
63 - (void)dealloc
64 {
65     [server release];
66     [currentServerName release];
67     [super dealloc];
68 }
69
70 #pragma mark -
71 #pragma mark Stack & Variables
72
73 - (WebScriptCallFrame *)currentFrame
74 {
75     return currentFrame;
76 }
77
78 - (NSString *)currentFrameFunctionName
79 {
80     return [currentFrame functionName];
81 }
82
83 - (NSArray *)currentFunctionStack
84 {
85     NSMutableArray *result = [[NSMutableArray alloc] init];
86     WebScriptCallFrame *frame = currentFrame;
87     while (frame) {
88         if ([frame functionName])
89             [result addObject:[frame functionName]];
90         else
91             [result addObject:@"(global scope)"];
92         frame = [frame caller];
93     }
94     return [result autorelease];
95 }
96
97 - (id)evaluateScript:(NSString *)script inCallFrame:(int)frame
98 {
99     WebScriptCallFrame *cframe = currentFrame;
100     for (unsigned count = 0; count < frame; count++)
101         cframe = [cframe caller];
102     if (!cframe)
103         return nil;
104
105     id result = [cframe evaluateWebScript:script];
106     if ([result isKindOfClass:NSClassFromString(@"WebScriptObject")])
107         return [result callWebScriptMethod:@"toString" withArguments:nil];
108     return result;
109 }
110
111 - (NSArray *)webScriptAttributeKeysForScriptObject:(WebScriptObject *)object
112 {
113     WebScriptObject *func = [object evaluateWebScript:@"(function () { var result = new Array(); for (var x in this) { result.push(x); } return result; })"];
114     [object setValue:func forKey:@"__drosera_introspection"];
115
116     NSMutableArray *result = [[NSMutableArray alloc] init];
117     WebScriptObject *variables = [object callWebScriptMethod:@"__drosera_introspection" withArguments:nil];
118     unsigned length = [variables count];
119     for (unsigned i = 0; i < length; i++) {
120         NSString *key = [variables webScriptValueAtIndex:i];
121         if (![key isEqualToString:@"__drosera_introspection"])
122             [result addObject:key];
123     }
124
125     [object removeWebScriptKey:@"__drosera_introspection"];
126
127     [result sortUsingSelector:@selector(compare:)];
128     return [result autorelease];
129 }
130
131 - (NSArray *)localScopeVariableNamesForCallFrame:(int)frame
132 {
133     WebScriptCallFrame *cframe = currentFrame;
134     for (unsigned count = 0; count < frame; count++)
135         cframe = [cframe caller];
136
137     if (![[cframe scopeChain] count])
138         return nil;
139
140     WebScriptObject *scope = [[cframe scopeChain] objectAtIndex:0]; // local is always first
141     return [self webScriptAttributeKeysForScriptObject:scope];
142 }
143
144 - (NSString *)valueForScopeVariableNamed:(NSString *)key inCallFrame:(int)frame
145 {
146     WebScriptCallFrame *cframe = currentFrame;
147     for (unsigned count = 0; count < frame; count++)
148         cframe = [cframe caller];
149
150     if (![[cframe scopeChain] count])
151         return nil;
152
153     unsigned scopeCount = [[cframe scopeChain] count];
154     for (unsigned i = 0; i < scopeCount; i++) {
155         WebScriptObject *scope = [[cframe scopeChain] objectAtIndex:i];
156         id value = [scope valueForKey:key];
157         if ([value isKindOfClass:NSClassFromString(@"WebScriptObject")])
158             return [value callWebScriptMethod:@"toString" withArguments:nil];
159         if (value && ![value isKindOfClass:[NSString class]])
160             return [NSString stringWithFormat:@"%@", value];
161         if (value)
162             return value;
163     }
164
165     return nil;
166 }
167
168 #pragma mark -
169 #pragma mark Pause & Step
170
171 - (BOOL)isPaused
172 {
173     return paused;
174 }
175
176 - (void)pause
177 {
178     paused = YES;
179     if ([[(NSDistantObject *)server connectionForProxy] isValid])
180         [server pause];
181     [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
182 }
183
184 - (void)resume
185 {
186     paused = NO;
187     if ([[(NSDistantObject *)server connectionForProxy] isValid])
188         [server resume];
189 }
190
191 - (void)stepInto
192 {
193     if ([[(NSDistantObject *)server connectionForProxy] isValid])
194         [server step];
195 }
196
197 - (void)log:(NSString *)msg
198 {
199     NSLog(@"%@", msg);
200 }
201
202 #pragma mark -
203 #pragma mark Interface Actions
204
205 - (IBAction)pause:(id)sender
206 {
207     [[webView windowScriptObject] callWebScriptMethod:@"pause" withArguments:nil];
208 }
209
210 - (IBAction)resume:(id)sender
211 {
212     [[webView windowScriptObject] callWebScriptMethod:@"resume" withArguments:nil];
213 }
214
215 - (IBAction)stepInto:(id)sender
216 {
217     [[webView windowScriptObject] callWebScriptMethod:@"stepInto" withArguments:nil];
218 }
219
220 - (IBAction)stepOver:(id)sender
221 {
222     [[webView windowScriptObject] callWebScriptMethod:@"stepOver" withArguments:nil];
223 }
224
225 - (IBAction)stepOut:(id)sender
226 {
227     [[webView windowScriptObject] callWebScriptMethod:@"stepOut" withArguments:nil];
228 }
229
230 - (IBAction)showConsole:(id)sender
231 {
232     [[webView windowScriptObject] callWebScriptMethod:@"showConsoleWindow" withArguments:nil];
233 }
234
235 #pragma mark -
236 #pragma mark Window Controller Overrides
237
238 - (NSString *)windowNibName
239 {
240     return @"Debugger";
241 }
242
243 - (void)windowDidLoad
244 {
245     [super windowDidLoad];
246
247     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationTerminating:) name:NSApplicationWillTerminateNotification object:nil];
248
249     NSString *path = [[NSBundle mainBundle] pathForResource:@"debugger" ofType:@"html" inDirectory:nil];
250     [[webView mainFrame] loadRequest:[[[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:path]] autorelease]];
251
252     NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"debugger"];
253     [toolbar setDelegate:self];
254     [toolbar setAllowsUserCustomization:YES];
255     [toolbar setAutosavesConfiguration:YES];
256     [[self window] setToolbar:toolbar];
257     [toolbar release];
258 }
259
260 - (void)windowWillClose:(NSNotification *)notification
261 {
262     [[webView windowScriptObject] removeWebScriptKey:@"DebuggerDocument"];
263
264     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:nil];
265
266     [self switchToServerNamed:nil];
267
268     [self autorelease]; // DebuggerApplication expects us to release on close
269 }
270
271 #pragma mark -
272 #pragma mark Connection Handling
273
274 - (void)switchToServerNamed:(NSString *)name
275 {
276     if (server) {
277         [[NSNotificationCenter defaultCenter] removeObserver:self name:NSConnectionDidDieNotification object:[(NSDistantObject *)server connectionForProxy]];
278         if ([[(NSDistantObject *)server connectionForProxy] isValid]) {
279             [server removeListener:self];
280             [self resume];
281         }
282     }
283
284     id old = server;
285     server = ([name length] ? [[NSConnection rootProxyForConnectionWithRegisteredName:name host:nil] retain] : nil);
286     [old release];
287
288     old = currentServerName;
289     currentServerName = [name copy];
290     [old release];
291
292     if (server) {
293         @try {
294             [(NSDistantObject *)server setProtocolForProxy:@protocol(WebScriptDebugServer)];
295             [server addListener:self];
296         } @catch (NSException *exception) {
297             [currentServerName release];
298             currentServerName = nil;
299             [server release];
300             server = nil;
301         }
302
303         if (server)
304             [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serverConnectionDidDie:) name:NSConnectionDidDieNotification object:[(NSDistantObject *)server connectionForProxy]];  
305     }
306 }
307
308 - (void)applicationTerminating:(NSNotification *)notifiction
309 {
310     if (server && [[(NSDistantObject *)server connectionForProxy] isValid]) {
311         [self switchToServerNamed:nil];
312         // call the runloop for a while to make sure our removeListener: is sent to the server
313         [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
314     }
315 }
316
317 - (void)serverConnectionDidDie:(NSNotification *)notifiction
318 {
319     [self switchToServerNamed:nil];
320 }
321
322 #pragma mark -
323 #pragma mark Toolbar Delegate
324
325 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
326 {
327     if ([itemIdentifier isEqualToString:DebuggerContinueToolbarItem]) {
328         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
329
330         [item setLabel:@"Continue"];
331         [item setPaletteLabel:@"Continue"];
332
333         [item setToolTip:@"Continue script execution"];
334         [item setImage:[NSImage imageNamed:@"continue"]];
335
336         [item setTarget:self];
337         [item setAction:@selector(resume:)];
338
339         return [item autorelease];
340     } else if ([itemIdentifier isEqualToString:DebuggerConsoleToolbarItem]) {
341         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
342
343         [item setLabel:@"Console"];
344         [item setPaletteLabel:@"Console"];
345
346         [item setToolTip:@"Console"];
347         [item setImage:[NSImage imageNamed:@"console"]];
348
349         [item setTarget:self];
350         [item setAction:@selector(showConsole:)];
351
352         return [item autorelease];
353     } else if ([itemIdentifier isEqualToString:DebuggerPauseToolbarItem]) {
354         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
355
356         [item setLabel:@"Pause"];
357         [item setPaletteLabel:@"Pause"];
358
359         [item setToolTip:@"Pause script execution"];
360         [item setImage:[NSImage imageNamed:@"pause"]];
361
362         [item setTarget:self];
363         [item setAction:@selector(pause:)];
364
365         return [item autorelease];
366     } else if ([itemIdentifier isEqualToString:DebuggerStepIntoToolbarItem]) {
367         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
368
369         [item setLabel:@"Step Into"];
370         [item setPaletteLabel:@"Step Into"];
371
372         [item setToolTip:@"Step into function call"];
373         [item setImage:[NSImage imageNamed:@"step"]];
374
375         [item setTarget:self];
376         [item setAction:@selector(stepInto:)];
377
378         return [item autorelease];
379     } else if ([itemIdentifier isEqualToString:DebuggerStepOverToolbarItem]) {
380         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
381
382         [item setLabel:@"Step Over"];
383         [item setPaletteLabel:@"Step Over"];
384
385         [item setToolTip:@"Step over function call"];
386         [item setImage:[NSImage imageNamed:@"stepOver"]];
387
388         [item setTarget:self];
389         [item setAction:@selector(stepOver:)];
390
391         return [item autorelease];
392     } else if ([itemIdentifier isEqualToString:DebuggerStepOutToolbarItem]) {
393         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
394
395         [item setLabel:@"Step Out"];
396         [item setPaletteLabel:@"Step Over"];
397
398         [item setToolTip:@"Step out of current function"];
399         [item setImage:[NSImage imageNamed:@"stepOut"]];
400
401         [item setTarget:self];
402         [item setAction:@selector(stepOut:)];
403
404         return [item autorelease];
405     }
406
407     return nil;
408 }
409
410 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
411 {
412     return [NSArray arrayWithObjects:DebuggerContinueToolbarItem, DebuggerPauseToolbarItem,
413         NSToolbarSeparatorItemIdentifier, DebuggerStepIntoToolbarItem, DebuggerStepOutToolbarItem,
414         DebuggerStepOverToolbarItem, NSToolbarFlexibleSpaceItemIdentifier, DebuggerConsoleToolbarItem, nil];
415 }
416
417 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
418 {
419     return [NSArray arrayWithObjects:DebuggerConsoleToolbarItem, DebuggerContinueToolbarItem, DebuggerPauseToolbarItem,
420         DebuggerStepIntoToolbarItem, DebuggerStepOutToolbarItem, DebuggerStepOverToolbarItem, NSToolbarCustomizeToolbarItemIdentifier,
421         NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
422 }
423
424 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)interfaceItem
425 {
426     SEL action = [interfaceItem action];
427     if (action == @selector(pause:))
428         return ![self isPaused];
429     if (action == @selector(resume:) ||
430         action == @selector(stepOver:) ||
431         action == @selector(stepOut:) ||
432         action == @selector(stepInto:))
433         return [self isPaused];
434     return YES;
435 }
436
437 #pragma mark -
438 #pragma mark WebView UI Delegate
439
440 - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
441 {
442     WebView *newWebView = [[WebView alloc] initWithFrame:NSZeroRect frameName:nil groupName:nil];
443     [newWebView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
444     [newWebView setUIDelegate:self];
445     [newWebView setPolicyDelegate:self];
446     [newWebView setFrameLoadDelegate:self];
447     if (request)
448         [[newWebView mainFrame] loadRequest:request];
449
450     NSWindow *window = [[NSWindow alloc] initWithContentRect:NSZeroRect styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask | NSUnifiedTitleAndToolbarWindowMask) backing:NSBackingStoreBuffered defer:NO screen:[[webView window] screen]];
451     [window setReleasedWhenClosed:YES];
452     [newWebView setFrame:[[window contentView] frame]];
453     [[window contentView] addSubview:newWebView];
454     [newWebView release];
455
456     return newWebView;
457 }
458
459 - (void)webViewShow:(WebView *)sender
460 {
461     [[sender window] makeKeyAndOrderFront:sender];
462 }
463
464 - (BOOL)webViewAreToolbarsVisible:(WebView *)sender
465 {
466     return [[[sender window] toolbar] isVisible];
467 }
468
469 - (void)webView:(WebView *)sender setToolbarsVisible:(BOOL)visible
470 {
471     [[[sender window] toolbar] setVisible:visible];
472 }
473
474 - (void)webView:(WebView *)sender setResizable:(BOOL)resizable
475 {
476     [[sender window] setShowsResizeIndicator:resizable];
477     [[[sender window] standardWindowButton:NSWindowZoomButton] setEnabled:resizable];
478 }
479
480 - (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
481 {
482     NSRange range = [message rangeOfString:@"\t"];
483     NSString *title = @"Alert";
484     if (range.location != NSNotFound) {
485         title = [message substringToIndex:range.location];
486         message = [message substringFromIndex:(range.location + range.length)];
487     }
488
489     NSBeginInformationalAlertSheet(title, nil, nil, nil, [sender window], nil, NULL, NULL, NULL, message);
490 }
491
492 - (void)scriptConfirmSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(int *)contextInfo
493 {
494     *contextInfo = returnCode;
495 }
496
497 - (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
498 {
499     NSRange range = [message rangeOfString:@"\t"];
500     NSString *title = @"Alert";
501     if (range.location != NSNotFound) {
502         title = [message substringToIndex:range.location];
503         message = [message substringFromIndex:(range.location + range.length)];
504     }
505
506     int result = NSNotFound;
507     NSBeginInformationalAlertSheet(title, nil, @"Cancel", nil, [sender window], self, @selector(scriptConfirmSheetDidEnd:returnCode:contextInfo:), NULL, &result, message);
508
509     while (result == NSNotFound) {
510         NSEvent *nextEvent = [[NSApplication sharedApplication] nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
511         [[NSApplication sharedApplication] sendEvent:nextEvent];
512     }
513
514     return result;
515 }
516
517 #pragma mark -
518 #pragma mark WebView Frame Load Delegate
519
520 - (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
521 {
522     // note: this is the Debuggers's own WebView, not the one being debugged
523     if ([[sender window] isEqual:[self window]])
524         [[sender windowScriptObject] setValue:self forKey:@"DebuggerDocument"];
525 }
526
527 - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
528 {
529     // note: this is the Debuggers's own WebView, not the one being debugged
530     if ([[sender window] isEqual:[self window]])
531         webViewLoaded = YES;
532 }
533
534 - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
535 {
536     // note: this is the Debuggers's own WebViews, not the one being debugged
537     if ([frame isEqual:[sender mainFrame]]) {
538         NSDictionary *info = [[(DebuggerApplication *)[[NSApplication sharedApplication] delegate] knownServers] objectForKey:currentServerName];
539         NSString *processName = [info objectForKey:WebScriptDebugServerProcessNameKey];
540         if (info && [processName length]) {
541             NSMutableString *newTitle = [[NSMutableString alloc] initWithString:processName];
542             [newTitle appendString:@" - "];
543             [newTitle appendString:title];
544             [[sender window] setTitle:newTitle];
545             [newTitle release];
546         } else 
547             [[sender window] setTitle:title];
548     }
549 }
550
551 #pragma mark -
552 #pragma mark Debug Listener Callbacks
553
554 - (void)webView:(WebView *)view didLoadMainResourceForDataSource:(WebDataSource *)dataSource
555 {
556     NSString *documentSourceCopy = nil;
557     id <WebDocumentRepresentation> rep = [dataSource representation];
558     if ([rep canProvideDocumentSource])
559         documentSourceCopy = [[rep documentSource] copy];
560
561     if (!documentSourceCopy)
562         return;
563
564     NSString *urlCopy = [[[[dataSource response] URL] absoluteString] copy];
565     NSArray *args = [[NSArray alloc] initWithObjects:(documentSourceCopy ? documentSourceCopy : @""), (urlCopy ? urlCopy : @""), [NSNumber numberWithBool:NO], nil];
566     [[webView windowScriptObject] callWebScriptMethod:@"updateFileSource" withArguments:args];
567
568     [args release];
569     [documentSourceCopy release];
570     [urlCopy release];
571 }
572
573 - (void)webView:(WebView *)view didParseSource:(NSString *)source baseLineNumber:(unsigned)baseLine fromURL:(NSURL *)url sourceId:(int)sid forWebFrame:(WebFrame *)webFrame
574 {
575     if (!webViewLoaded)
576         return;
577
578     NSString *sourceCopy = [source copy];
579     if (!sourceCopy)
580         return;
581
582     NSString *documentSourceCopy = nil;
583     NSString *urlCopy = [[url absoluteString] copy];
584
585     WebDataSource *dataSource = [webFrame dataSource];
586     if (!url || [[[dataSource response] URL] isEqual:url]) {
587         id <WebDocumentRepresentation> rep = [dataSource representation];
588         if ([rep canProvideDocumentSource])
589             documentSourceCopy = [[rep documentSource] copy];
590         if (!urlCopy)
591             urlCopy = [[[[dataSource response] URL] absoluteString] copy];
592     }
593
594     NSArray *args = [[NSArray alloc] initWithObjects:sourceCopy, (documentSourceCopy ? documentSourceCopy : @""), (urlCopy ? urlCopy : @""), [NSNumber numberWithInt:sid], [NSNumber numberWithUnsignedInt:baseLine], nil];
595     [[webView windowScriptObject] callWebScriptMethod:@"didParseScript" withArguments:args];
596
597     [args release];
598     [sourceCopy release];
599     [documentSourceCopy release];
600     [urlCopy release];
601 }
602
603 - (void)webView:(WebView *)view failedToParseSource:(NSString *)source baseLineNumber:(unsigned)baseLine fromURL:(NSURL *)url withError:(NSError *)error forWebFrame:(WebFrame *)webFrame
604 {
605 }
606
607 - (void)webView:(WebView *)view didEnterCallFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
608 {
609     if (!webViewLoaded)
610         return;
611
612     id old = currentFrame;
613     currentFrame = [frame retain];
614     [old release];
615
616     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
617     [[webView windowScriptObject] callWebScriptMethod:@"didEnterCallFrame" withArguments:args];
618     [args release];
619 }
620
621 - (void)webView:(WebView *)view willExecuteStatement:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
622 {
623     if (!webViewLoaded)
624         return;
625
626     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
627     [[webView windowScriptObject] callWebScriptMethod:@"willExecuteStatement" withArguments:args];
628     [args release];
629 }
630
631 - (void)webView:(WebView *)view willLeaveCallFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
632 {
633     if (!webViewLoaded)
634         return;
635
636     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
637     [[webView windowScriptObject] callWebScriptMethod:@"willLeaveCallFrame" withArguments:args];
638     [args release];
639
640     id old = currentFrame;
641     currentFrame = [[frame caller] retain];
642     [old release];
643 }
644
645 - (void)webView:(WebView *)view exceptionWasRaised:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
646 {
647     if (!webViewLoaded)
648         return;
649
650     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
651     [[webView windowScriptObject] callWebScriptMethod:@"exceptionWasRaised" withArguments:args];
652     [args release];
653 }
654 @end