Reviewed by Darin.
[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 if ([frame caller])
91             [result addObject:@"(anonymous function)"];
92         else
93             [result addObject:@"(global scope)"];
94         frame = [frame caller];
95     }
96     return [result autorelease];
97 }
98
99 - (id)evaluateScript:(NSString *)script inCallFrame:(int)frame
100 {
101     WebScriptCallFrame *cframe = currentFrame;
102     for (unsigned count = 0; count < frame; count++)
103         cframe = [cframe caller];
104     if (!cframe)
105         return nil;
106
107     id result = [cframe evaluateWebScript:script];
108     if ([result isKindOfClass:NSClassFromString(@"WebScriptObject")])
109         return [result callWebScriptMethod:@"toString" withArguments:nil];
110     return result;
111 }
112
113 - (NSArray *)webScriptAttributeKeysForScriptObject:(WebScriptObject *)object
114 {
115     WebScriptObject *func = [object evaluateWebScript:@"(function () { var result = new Array(); for (var x in this) { result.push(x); } return result; })"];
116     [object setValue:func forKey:@"__drosera_introspection"];
117
118     NSMutableArray *result = [[NSMutableArray alloc] init];
119     WebScriptObject *variables = [object callWebScriptMethod:@"__drosera_introspection" withArguments:nil];
120     unsigned length = [variables count];
121     for (unsigned i = 0; i < length; i++) {
122         NSString *key = [variables webScriptValueAtIndex:i];
123         if (![key isEqualToString:@"__drosera_introspection"])
124             [result addObject:key];
125     }
126
127     [object removeWebScriptKey:@"__drosera_introspection"];
128
129     [result sortUsingSelector:@selector(compare:)];
130     return [result autorelease];
131 }
132
133 - (NSArray *)localScopeVariableNamesForCallFrame:(int)frame
134 {
135     WebScriptCallFrame *cframe = currentFrame;
136     for (unsigned count = 0; count < frame; count++)
137         cframe = [cframe caller];
138
139     if (![[cframe scopeChain] count])
140         return nil;
141
142     WebScriptObject *scope = [[cframe scopeChain] objectAtIndex:0]; // local is always first
143     return [self webScriptAttributeKeysForScriptObject:scope];
144 }
145
146 - (NSString *)valueForScopeVariableNamed:(NSString *)key inCallFrame:(int)frame
147 {
148     WebScriptCallFrame *cframe = currentFrame;
149     for (unsigned count = 0; count < frame; count++)
150         cframe = [cframe caller];
151
152     if (![[cframe scopeChain] count])
153         return nil;
154
155     unsigned scopeCount = [[cframe scopeChain] count];
156     for (unsigned i = 0; i < scopeCount; i++) {
157         WebScriptObject *scope = [[cframe scopeChain] objectAtIndex:i];
158         id value = [scope valueForKey:key];
159         if ([value isKindOfClass:NSClassFromString(@"WebScriptObject")])
160             return [value callWebScriptMethod:@"toString" withArguments:nil];
161         if (value && ![value isKindOfClass:[NSString class]])
162             return [NSString stringWithFormat:@"%@", value];
163         if (value)
164             return value;
165     }
166
167     return nil;
168 }
169
170 #pragma mark -
171 #pragma mark Pause & Step
172
173 - (BOOL)isPaused
174 {
175     return paused;
176 }
177
178 - (void)pause
179 {
180     paused = YES;
181     if ([[(NSDistantObject *)server connectionForProxy] isValid])
182         [server pause];
183     [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
184 }
185
186 - (void)resume
187 {
188     paused = NO;
189     if ([[(NSDistantObject *)server connectionForProxy] isValid])
190         [server resume];
191 }
192
193 - (void)stepInto
194 {
195     if ([[(NSDistantObject *)server connectionForProxy] isValid])
196         [server step];
197 }
198
199 - (void)log:(NSString *)msg
200 {
201     NSLog(@"%@", msg);
202 }
203
204 #pragma mark -
205 #pragma mark Interface Actions
206
207 - (IBAction)pause:(id)sender
208 {
209     [[webView windowScriptObject] callWebScriptMethod:@"pause" withArguments:nil];
210 }
211
212 - (IBAction)resume:(id)sender
213 {
214     [[webView windowScriptObject] callWebScriptMethod:@"resume" withArguments:nil];
215 }
216
217 - (IBAction)stepInto:(id)sender
218 {
219     [[webView windowScriptObject] callWebScriptMethod:@"stepInto" withArguments:nil];
220 }
221
222 - (IBAction)stepOver:(id)sender
223 {
224     [[webView windowScriptObject] callWebScriptMethod:@"stepOver" withArguments:nil];
225 }
226
227 - (IBAction)stepOut:(id)sender
228 {
229     [[webView windowScriptObject] callWebScriptMethod:@"stepOut" withArguments:nil];
230 }
231
232 - (IBAction)showConsole:(id)sender
233 {
234     [[webView windowScriptObject] callWebScriptMethod:@"showConsoleWindow" withArguments:nil];
235 }
236
237 #pragma mark -
238 #pragma mark Window Controller Overrides
239
240 - (NSString *)windowNibName
241 {
242     return @"Debugger";
243 }
244
245 - (void)windowDidLoad
246 {
247     [super windowDidLoad];
248
249     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationTerminating:) name:NSApplicationWillTerminateNotification object:nil];
250
251     NSString *path = [[NSBundle mainBundle] pathForResource:@"debugger" ofType:@"html" inDirectory:nil];
252     [[webView mainFrame] loadRequest:[[[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:path]] autorelease]];
253
254     NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"debugger"];
255     [toolbar setDelegate:self];
256     [toolbar setAllowsUserCustomization:YES];
257     [toolbar setAutosavesConfiguration:YES];
258     [[self window] setToolbar:toolbar];
259     [toolbar release];
260 }
261
262 - (void)windowWillClose:(NSNotification *)notification
263 {
264     [[webView windowScriptObject] removeWebScriptKey:@"DebuggerDocument"];
265
266     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:nil];
267
268     [self switchToServerNamed:nil];
269
270     [self autorelease]; // DebuggerApplication expects us to release on close
271 }
272
273 #pragma mark -
274 #pragma mark Connection Handling
275
276 - (void)switchToServerNamed:(NSString *)name
277 {
278     if (server) {
279         [[NSNotificationCenter defaultCenter] removeObserver:self name:NSConnectionDidDieNotification object:[(NSDistantObject *)server connectionForProxy]];
280         if ([[(NSDistantObject *)server connectionForProxy] isValid]) {
281             [server removeListener:self];
282             [self resume];
283         }
284     }
285
286     id old = server;
287     server = ([name length] ? [[NSConnection rootProxyForConnectionWithRegisteredName:name host:nil] retain] : nil);
288     [old release];
289
290     old = currentServerName;
291     currentServerName = [name copy];
292     [old release];
293
294     if (server) {
295         @try {
296             [(NSDistantObject *)server setProtocolForProxy:@protocol(WebScriptDebugServer)];
297             [server addListener:self];
298         } @catch (NSException *exception) {
299             [currentServerName release];
300             currentServerName = nil;
301             [server release];
302             server = nil;
303         }
304
305         if (server)
306             [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serverConnectionDidDie:) name:NSConnectionDidDieNotification object:[(NSDistantObject *)server connectionForProxy]];  
307     }
308 }
309
310 - (void)applicationTerminating:(NSNotification *)notifiction
311 {
312     if (server && [[(NSDistantObject *)server connectionForProxy] isValid]) {
313         [self switchToServerNamed:nil];
314         // call the runloop for a while to make sure our removeListener: is sent to the server
315         [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
316     }
317 }
318
319 - (void)serverConnectionDidDie:(NSNotification *)notifiction
320 {
321     [self switchToServerNamed:nil];
322 }
323
324 #pragma mark -
325 #pragma mark Toolbar Delegate
326
327 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
328 {
329     if ([itemIdentifier isEqualToString:DebuggerContinueToolbarItem]) {
330         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
331
332         [item setLabel:@"Continue"];
333         [item setPaletteLabel:@"Continue"];
334
335         [item setToolTip:@"Continue script execution"];
336         [item setImage:[NSImage imageNamed:@"continue"]];
337
338         [item setTarget:self];
339         [item setAction:@selector(resume:)];
340
341         return [item autorelease];
342     } else if ([itemIdentifier isEqualToString:DebuggerConsoleToolbarItem]) {
343         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
344
345         [item setLabel:@"Console"];
346         [item setPaletteLabel:@"Console"];
347
348         [item setToolTip:@"Console"];
349         [item setImage:[NSImage imageNamed:@"console"]];
350
351         [item setTarget:self];
352         [item setAction:@selector(showConsole:)];
353
354         return [item autorelease];
355     } else if ([itemIdentifier isEqualToString:DebuggerPauseToolbarItem]) {
356         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
357
358         [item setLabel:@"Pause"];
359         [item setPaletteLabel:@"Pause"];
360
361         [item setToolTip:@"Pause script execution"];
362         [item setImage:[NSImage imageNamed:@"pause"]];
363
364         [item setTarget:self];
365         [item setAction:@selector(pause:)];
366
367         return [item autorelease];
368     } else if ([itemIdentifier isEqualToString:DebuggerStepIntoToolbarItem]) {
369         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
370
371         [item setLabel:@"Step Into"];
372         [item setPaletteLabel:@"Step Into"];
373
374         [item setToolTip:@"Step into function call"];
375         [item setImage:[NSImage imageNamed:@"step"]];
376
377         [item setTarget:self];
378         [item setAction:@selector(stepInto:)];
379
380         return [item autorelease];
381     } else if ([itemIdentifier isEqualToString:DebuggerStepOverToolbarItem]) {
382         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
383
384         [item setLabel:@"Step Over"];
385         [item setPaletteLabel:@"Step Over"];
386
387         [item setToolTip:@"Step over function call"];
388         [item setImage:[NSImage imageNamed:@"stepOver"]];
389
390         [item setTarget:self];
391         [item setAction:@selector(stepOver:)];
392
393         return [item autorelease];
394     } else if ([itemIdentifier isEqualToString:DebuggerStepOutToolbarItem]) {
395         NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
396
397         [item setLabel:@"Step Out"];
398         [item setPaletteLabel:@"Step Over"];
399
400         [item setToolTip:@"Step out of current function"];
401         [item setImage:[NSImage imageNamed:@"stepOut"]];
402
403         [item setTarget:self];
404         [item setAction:@selector(stepOut:)];
405
406         return [item autorelease];
407     }
408
409     return nil;
410 }
411
412 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
413 {
414     return [NSArray arrayWithObjects:DebuggerContinueToolbarItem, DebuggerPauseToolbarItem,
415         NSToolbarSeparatorItemIdentifier, DebuggerStepIntoToolbarItem, DebuggerStepOutToolbarItem,
416         DebuggerStepOverToolbarItem, NSToolbarFlexibleSpaceItemIdentifier, DebuggerConsoleToolbarItem, nil];
417 }
418
419 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
420 {
421     return [NSArray arrayWithObjects:DebuggerConsoleToolbarItem, DebuggerContinueToolbarItem, DebuggerPauseToolbarItem,
422         DebuggerStepIntoToolbarItem, DebuggerStepOutToolbarItem, DebuggerStepOverToolbarItem, NSToolbarCustomizeToolbarItemIdentifier,
423         NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
424 }
425
426 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)interfaceItem
427 {
428     SEL action = [interfaceItem action];
429     if (action == @selector(pause:))
430         return ![self isPaused];
431     if (action == @selector(resume:) ||
432         action == @selector(stepOver:) ||
433         action == @selector(stepOut:) ||
434         action == @selector(stepInto:))
435         return [self isPaused];
436     return YES;
437 }
438
439 #pragma mark -
440 #pragma mark WebView UI Delegate
441
442 - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
443 {
444     WebView *newWebView = [[WebView alloc] initWithFrame:NSZeroRect frameName:nil groupName:nil];
445     [newWebView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
446     [newWebView setUIDelegate:self];
447     [newWebView setPolicyDelegate:self];
448     [newWebView setFrameLoadDelegate:self];
449     if (request)
450         [[newWebView mainFrame] loadRequest:request];
451
452     NSWindow *window = [[NSWindow alloc] initWithContentRect:NSZeroRect styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask | NSUnifiedTitleAndToolbarWindowMask) backing:NSBackingStoreBuffered defer:NO screen:[[webView window] screen]];
453     [window setReleasedWhenClosed:YES];
454     [newWebView setFrame:[[window contentView] frame]];
455     [[window contentView] addSubview:newWebView];
456     [newWebView release];
457
458     return newWebView;
459 }
460
461 - (void)webViewShow:(WebView *)sender
462 {
463     [[sender window] makeKeyAndOrderFront:sender];
464 }
465
466 - (BOOL)webViewAreToolbarsVisible:(WebView *)sender
467 {
468     return [[[sender window] toolbar] isVisible];
469 }
470
471 - (void)webView:(WebView *)sender setToolbarsVisible:(BOOL)visible
472 {
473     [[[sender window] toolbar] setVisible:visible];
474 }
475
476 - (void)webView:(WebView *)sender setResizable:(BOOL)resizable
477 {
478     [[sender window] setShowsResizeIndicator:resizable];
479     [[[sender window] standardWindowButton:NSWindowZoomButton] setEnabled:resizable];
480 }
481
482 - (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
483 {
484     NSRange range = [message rangeOfString:@"\t"];
485     NSString *title = @"Alert";
486     if (range.location != NSNotFound) {
487         title = [message substringToIndex:range.location];
488         message = [message substringFromIndex:(range.location + range.length)];
489     }
490
491     NSBeginInformationalAlertSheet(title, nil, nil, nil, [sender window], nil, NULL, NULL, NULL, message);
492 }
493
494 - (void)scriptConfirmSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(int *)contextInfo
495 {
496     *contextInfo = returnCode;
497 }
498
499 - (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
500 {
501     NSRange range = [message rangeOfString:@"\t"];
502     NSString *title = @"Alert";
503     if (range.location != NSNotFound) {
504         title = [message substringToIndex:range.location];
505         message = [message substringFromIndex:(range.location + range.length)];
506     }
507
508     int result = NSNotFound;
509     NSBeginInformationalAlertSheet(title, nil, @"Cancel", nil, [sender window], self, @selector(scriptConfirmSheetDidEnd:returnCode:contextInfo:), NULL, &result, message);
510
511     while (result == NSNotFound) {
512         NSEvent *nextEvent = [[NSApplication sharedApplication] nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
513         [[NSApplication sharedApplication] sendEvent:nextEvent];
514     }
515
516     return result;
517 }
518
519 #pragma mark -
520 #pragma mark WebView Frame Load Delegate
521
522 - (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
523 {
524     // note: this is the Debuggers's own WebView, not the one being debugged
525     if ([[sender window] isEqual:[self window]])
526         [[sender windowScriptObject] setValue:self forKey:@"DebuggerDocument"];
527 }
528
529 - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
530 {
531     // note: this is the Debuggers's own WebView, not the one being debugged
532     if ([[sender window] isEqual:[self window]])
533         webViewLoaded = YES;
534 }
535
536 - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
537 {
538     // note: this is the Debuggers's own WebViews, not the one being debugged
539     if ([frame isEqual:[sender mainFrame]]) {
540         NSDictionary *info = [[(DebuggerApplication *)[[NSApplication sharedApplication] delegate] knownServers] objectForKey:currentServerName];
541         NSString *processName = [info objectForKey:WebScriptDebugServerProcessNameKey];
542         if (info && [processName length]) {
543             NSMutableString *newTitle = [[NSMutableString alloc] initWithString:processName];
544             [newTitle appendString:@" - "];
545             [newTitle appendString:title];
546             [[sender window] setTitle:newTitle];
547             [newTitle release];
548         } else 
549             [[sender window] setTitle:title];
550     }
551 }
552
553 #pragma mark -
554 #pragma mark Debug Listener Callbacks
555
556 - (void)webView:(WebView *)view didLoadMainResourceForDataSource:(WebDataSource *)dataSource
557 {
558     NSString *documentSourceCopy = nil;
559     id <WebDocumentRepresentation> rep = [dataSource representation];
560     if ([rep canProvideDocumentSource])
561         documentSourceCopy = [[rep documentSource] copy];
562
563     if (!documentSourceCopy)
564         return;
565
566     NSString *urlCopy = [[[[dataSource response] URL] absoluteString] copy];
567     NSArray *args = [[NSArray alloc] initWithObjects:(documentSourceCopy ? documentSourceCopy : @""), (urlCopy ? urlCopy : @""), [NSNumber numberWithBool:NO], nil];
568     [[webView windowScriptObject] callWebScriptMethod:@"updateFileSource" withArguments:args];
569
570     [args release];
571     [documentSourceCopy release];
572     [urlCopy release];
573 }
574
575 - (void)webView:(WebView *)view didParseSource:(NSString *)source baseLineNumber:(unsigned)baseLine fromURL:(NSURL *)url sourceId:(int)sid forWebFrame:(WebFrame *)webFrame
576 {
577     if (!webViewLoaded)
578         return;
579
580     NSString *sourceCopy = [source copy];
581     if (!sourceCopy)
582         return;
583
584     NSString *documentSourceCopy = nil;
585     NSString *urlCopy = [[url absoluteString] copy];
586
587     WebDataSource *dataSource = [webFrame dataSource];
588     if (!url || [[[dataSource response] URL] isEqual:url]) {
589         id <WebDocumentRepresentation> rep = [dataSource representation];
590         if ([rep canProvideDocumentSource])
591             documentSourceCopy = [[rep documentSource] copy];
592         if (!urlCopy)
593             urlCopy = [[[[dataSource response] URL] absoluteString] copy];
594     }
595
596     NSArray *args = [[NSArray alloc] initWithObjects:sourceCopy, (documentSourceCopy ? documentSourceCopy : @""), (urlCopy ? urlCopy : @""), [NSNumber numberWithInt:sid], [NSNumber numberWithUnsignedInt:baseLine], nil];
597     [[webView windowScriptObject] callWebScriptMethod:@"didParseScript" withArguments:args];
598
599     [args release];
600     [sourceCopy release];
601     [documentSourceCopy release];
602     [urlCopy release];
603 }
604
605 - (void)webView:(WebView *)view failedToParseSource:(NSString *)source baseLineNumber:(unsigned)baseLine fromURL:(NSURL *)url withError:(NSError *)error forWebFrame:(WebFrame *)webFrame
606 {
607 }
608
609 - (void)webView:(WebView *)view didEnterCallFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
610 {
611     if (!webViewLoaded)
612         return;
613
614     id old = currentFrame;
615     currentFrame = [frame retain];
616     [old release];
617
618     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
619     [[webView windowScriptObject] callWebScriptMethod:@"didEnterCallFrame" withArguments:args];
620     [args release];
621 }
622
623 - (void)webView:(WebView *)view willExecuteStatement:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
624 {
625     if (!webViewLoaded)
626         return;
627
628     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
629     [[webView windowScriptObject] callWebScriptMethod:@"willExecuteStatement" withArguments:args];
630     [args release];
631 }
632
633 - (void)webView:(WebView *)view willLeaveCallFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
634 {
635     if (!webViewLoaded)
636         return;
637
638     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
639     [[webView windowScriptObject] callWebScriptMethod:@"willLeaveCallFrame" withArguments:args];
640     [args release];
641
642     id old = currentFrame;
643     currentFrame = [[frame caller] retain];
644     [old release];
645 }
646
647 - (void)webView:(WebView *)view exceptionWasRaised:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame
648 {
649     if (!webViewLoaded)
650         return;
651
652     NSArray *args = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
653     [[webView windowScriptObject] callWebScriptMethod:@"exceptionWasRaised" withArguments:args];
654     [args release];
655 }
656 @end