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