LayoutTests:
[WebKit-https.git] / WebCore / bridge / mac / FrameMac.mm
1 /*
2  * Copyright (C) 2004, 2005, 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "config.h"
27 #import "FrameMac.h"
28
29 #import "AccessibilityObjectCache.h"
30 #import "BlockExceptions.h"
31 #import "BrowserExtensionMac.h"
32 #import "CSSComputedStyleDeclaration.h"
33 #import "Cache.h"
34 #import "Cursor.h"
35 #import "DOMInternal.h"
36 #import "DOMWindow.h"
37 #import "EventNames.h"
38 #import "FloatRect.h"
39 #import "FoundationExtras.h"
40 #import "FramePrivate.h"
41 #import "GraphicsContext.h"
42 #import "HTMLDocument.h"
43 #import "HTMLFormElement.h"
44 #import "HTMLGenericFormElement.h"
45 #import "KWQEditCommand.h"
46 #import "KWQFormData.h"
47 #import "KWQPageState.h"
48 #import "Logging.h"
49 #import "MouseEventWithHitTestResults.h"
50 #import "PlatformKeyboardEvent.h"
51 #import "PlatformWheelEvent.h"
52 #import "Plugin.h"
53 #import "RegularExpression.h"
54 #import "RenderCanvas.h"
55 #import "RenderImage.h"
56 #import "RenderTableCell.h"
57 #import "RenderTheme.h"
58 #import "TextIterator.h"
59 #import "TransferJob.h"
60 #import "WebCoreFrameBridge.h"
61 #import "WebCoreViewFactory.h"
62 #import "WebDashboardRegion.h"
63 #import "csshelper.h"
64 #import "html_tableimpl.h"
65 #import "kjs_window.h"
66 #import "render_frames.h"
67 #import "render_list.h"
68 #import "visible_units.h"
69 #import <JavaScriptCore/NP_jsobject.h>
70 #import <JavaScriptCore/WebScriptObjectPrivate.h>
71 #import <JavaScriptCore/npruntime_impl.h>
72
73 #undef _KWQ_TIMING
74
75 @interface NSObject (WebPlugIn)
76 - (id)objectForWebScript;
77 - (void *)pluginScriptableObject;
78 @end
79
80 using namespace std;
81 using namespace KJS::Bindings;
82 using namespace KIO;
83
84 using KJS::JSLock;
85 using KJS::PausedTimeouts;
86 using KJS::SavedBuiltins;
87 using KJS::SavedProperties;
88
89 namespace WebCore {
90
91 using namespace EventNames;
92 using namespace HTMLNames;
93
94 NSEvent* FrameMac::_currentEvent = nil;
95
96 static NSMutableDictionary* createNSDictionary(const HashMap<String, String>& map)
97 {
98     NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:map.size()];
99     HashMap<String, String>::const_iterator end = map.end();
100     for (HashMap<String, String>::const_iterator it = map.begin(); it != end; ++it) {
101         NSString* key = it->first;
102         NSString* object = it->second;
103         [dict setObject:object forKey:key];
104     }
105     return dict;
106 }
107
108 static const unsigned int escChar = 27;
109 static SEL selectorForKeyEvent(const PlatformKeyboardEvent* event)
110 {
111     // FIXME: This helper function is for the autofill code so the bridge can pass a selector to the form delegate.  
112     // Eventually, we should move all of the autofill code down to WebKit and remove the need for this function by
113     // not relying on the selector in the new implementation.
114     String key = event->unmodifiedText();
115     if (key.length() != 1)
116         return 0;
117
118     SEL selector = NULL;
119     switch (key[0U]) {
120     case NSUpArrowFunctionKey:
121         selector = @selector(moveUp:); break;
122     case NSDownArrowFunctionKey:
123         selector = @selector(moveDown:); break;
124     case escChar:
125         selector = @selector(cancel:); break;
126     case NSTabCharacter:
127         selector = @selector(insertTab:); break;
128     case NSBackTabCharacter:
129         selector = @selector(insertBacktab:); break;
130     case NSNewlineCharacter:
131     case NSCarriageReturnCharacter:
132     case NSEnterCharacter:
133         selector = @selector(insertNewline:); break;
134         break;
135     }
136     return selector;
137 }
138
139
140 bool FrameView::isFrameView() const
141 {
142     return true;
143 }
144
145 FrameMac::FrameMac(Page* page, RenderPart* ownerRenderer)
146     : Frame(page, ownerRenderer)
147     , _bridge(nil)
148     , _mouseDownView(nil)
149     , _sendingEventToSubview(false)
150     , _mouseDownMayStartDrag(false)
151     , _mouseDownMayStartSelect(false)
152     , _activationEventNumber(0)
153     , _bindingRoot(0)
154     , _windowScriptObject(0)
155     , _windowScriptNPObject(0)
156 {
157     d->m_extension = new BrowserExtensionMac(this);
158 }
159
160 FrameMac::~FrameMac()
161 {
162     setView(0);
163     freeClipboard();
164     clearRecordedFormValues();    
165     
166     [_bridge clearFrame];
167     KWQRelease(_bridge);
168     _bridge = nil;
169 }
170
171 void FrameMac::freeClipboard()
172 {
173     if (_dragClipboard)
174         _dragClipboard->setAccessPolicy(ClipboardMac::Numb);
175 }
176
177 bool FrameMac::openURL(const KURL &url)
178 {
179     BEGIN_BLOCK_OBJC_EXCEPTIONS;
180
181     // FIXME: The lack of args here to get the reload flag from
182     // indicates a problem in how we use Frame::processObjectRequest,
183     // where we are opening the URL before the args are set up.
184     [_bridge loadURL:url.getNSURL()
185             referrer:[_bridge referrer]
186               reload:NO
187          userGesture:userGestureHint()
188               target:nil
189      triggeringEvent:nil
190                 form:nil
191           formValues:nil];
192
193     END_BLOCK_OBJC_EXCEPTIONS;
194
195     return true;
196 }
197
198 void FrameMac::openURLRequest(const ResourceRequest& request)
199 {
200     BEGIN_BLOCK_OBJC_EXCEPTIONS;
201
202     NSString *referrer;
203     String argsReferrer = request.referrer();
204     if (!argsReferrer.isEmpty())
205         referrer = argsReferrer;
206     else
207         referrer = [_bridge referrer];
208
209     [_bridge loadURL:request.url().getNSURL()
210             referrer:referrer
211               reload:request.reload
212          userGesture:userGestureHint()
213               target:request.frameName
214      triggeringEvent:nil
215                 form:nil
216           formValues:nil];
217
218     END_BLOCK_OBJC_EXCEPTIONS;
219 }
220
221
222 // Either get cached regexp or build one that matches any of the labels.
223 // The regexp we build is of the form:  (STR1|STR2|STRN)
224 RegularExpression *regExpForLabels(NSArray *labels)
225 {
226     // All the ObjC calls in this method are simple array and string
227     // calls which we can assume do not raise exceptions
228
229
230     // Parallel arrays that we use to cache regExps.  In practice the number of expressions
231     // that the app will use is equal to the number of locales is used in searching.
232     static const unsigned int regExpCacheSize = 4;
233     static NSMutableArray *regExpLabels = nil;
234     static Vector<RegularExpression*> regExps;
235     static RegularExpression wordRegExp = RegularExpression("\\w");
236
237     RegularExpression *result;
238     if (!regExpLabels)
239         regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
240     CFIndex cacheHit = [regExpLabels indexOfObject:labels];
241     if (cacheHit != NSNotFound)
242         result = regExps.at(cacheHit);
243     else {
244         DeprecatedString pattern("(");
245         unsigned int numLabels = [labels count];
246         unsigned int i;
247         for (i = 0; i < numLabels; i++) {
248             DeprecatedString label = DeprecatedString::fromNSString((NSString *)[labels objectAtIndex:i]);
249
250             bool startsWithWordChar = false;
251             bool endsWithWordChar = false;
252             if (label.length() != 0) {
253                 startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
254                 endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
255             }
256             
257             if (i != 0)
258                 pattern.append("|");
259             // Search for word boundaries only if label starts/ends with "word characters".
260             // If we always searched for word boundaries, this wouldn't work for languages
261             // such as Japanese.
262             if (startsWithWordChar) {
263                 pattern.append("\\b");
264             }
265             pattern.append(label);
266             if (endsWithWordChar) {
267                 pattern.append("\\b");
268             }
269         }
270         pattern.append(")");
271         result = new RegularExpression(pattern, false);
272     }
273
274     // add regexp to the cache, making sure it is at the front for LRU ordering
275     if (cacheHit != 0) {
276         if (cacheHit != NSNotFound) {
277             // remove from old spot
278             [regExpLabels removeObjectAtIndex:cacheHit];
279             regExps.remove(cacheHit);
280         }
281         // add to start
282         [regExpLabels insertObject:labels atIndex:0];
283         regExps.insert(0, result);
284         // trim if too big
285         if ([regExpLabels count] > regExpCacheSize) {
286             [regExpLabels removeObjectAtIndex:regExpCacheSize];
287             RegularExpression *last = regExps.last();
288             regExps.removeLast();
289             delete last;
290         }
291     }
292     return result;
293 }
294
295 NSString *FrameMac::searchForLabelsAboveCell(RegularExpression *regExp, HTMLTableCellElement *cell)
296 {
297     RenderTableCell *cellRenderer = static_cast<RenderTableCell *>(cell->renderer());
298
299     if (cellRenderer && cellRenderer->isTableCell()) {
300         RenderTableCell *cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
301
302         if (cellAboveRenderer) {
303             HTMLTableCellElement *aboveCell =
304                 static_cast<HTMLTableCellElement *>(cellAboveRenderer->element());
305
306             if (aboveCell) {
307                 // search within the above cell we found for a match
308                 for (Node *n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
309                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
310                         // For each text chunk, run the regexp
311                         DeprecatedString nodeString = n->nodeValue().deprecatedString();
312                         int pos = regExp->searchRev(nodeString);
313                         if (pos >= 0)
314                             return nodeString.mid(pos, regExp->matchedLength()).getNSString();
315                     }
316                 }
317             }
318         }
319     }
320     // Any reason in practice to search all cells in that are above cell?
321     return nil;
322 }
323
324 NSString *FrameMac::searchForLabelsBeforeElement(NSArray *labels, Element *element)
325 {
326     RegularExpression *regExp = regExpForLabels(labels);
327     // We stop searching after we've seen this many chars
328     const unsigned int charsSearchedThreshold = 500;
329     // This is the absolute max we search.  We allow a little more slop than
330     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
331     const unsigned int maxCharsSearched = 600;
332     // If the starting element is within a table, the cell that contains it
333     HTMLTableCellElement *startingTableCell = 0;
334     bool searchedCellAbove = false;
335
336     // walk backwards in the node tree, until another element, or form, or end of tree
337     int unsigned lengthSearched = 0;
338     Node *n;
339     for (n = element->traversePreviousNode();
340          n && lengthSearched < charsSearchedThreshold;
341          n = n->traversePreviousNode())
342     {
343         if (n->hasTagName(formTag)
344             || (n->isHTMLElement()
345                 && static_cast<HTMLElement *>(n)->isGenericFormElement()))
346         {
347             // We hit another form element or the start of the form - bail out
348             break;
349         } else if (n->hasTagName(tdTag) && !startingTableCell) {
350             startingTableCell = static_cast<HTMLTableCellElement *>(n);
351         } else if (n->hasTagName(trTag) && startingTableCell) {
352             NSString *result = searchForLabelsAboveCell(regExp, startingTableCell);
353             if (result) {
354                 return result;
355             }
356             searchedCellAbove = true;
357         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
358             // For each text chunk, run the regexp
359             DeprecatedString nodeString = n->nodeValue().deprecatedString();
360             // add 100 for slop, to make it more likely that we'll search whole nodes
361             if (lengthSearched + nodeString.length() > maxCharsSearched)
362                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
363             int pos = regExp->searchRev(nodeString);
364             if (pos >= 0)
365                 return nodeString.mid(pos, regExp->matchedLength()).getNSString();
366             else
367                 lengthSearched += nodeString.length();
368         }
369     }
370
371     // If we started in a cell, but bailed because we found the start of the form or the
372     // previous element, we still might need to search the row above us for a label.
373     if (startingTableCell && !searchedCellAbove) {
374          return searchForLabelsAboveCell(regExp, startingTableCell);
375     } else {
376         return nil;
377     }
378 }
379
380 NSString *FrameMac::matchLabelsAgainstElement(NSArray *labels, Element *element)
381 {
382     DeprecatedString name = element->getAttribute(nameAttr).deprecatedString();
383     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
384     name.replace(RegularExpression("[[:digit:]]"), " ");
385     name.replace('_', ' ');
386     
387     RegularExpression *regExp = regExpForLabels(labels);
388     // Use the largest match we can find in the whole name string
389     int pos;
390     int length;
391     int bestPos = -1;
392     int bestLength = -1;
393     int start = 0;
394     do {
395         pos = regExp->search(name, start);
396         if (pos != -1) {
397             length = regExp->matchedLength();
398             if (length >= bestLength) {
399                 bestPos = pos;
400                 bestLength = length;
401             }
402             start = pos+1;
403         }
404     } while (pos != -1);
405
406     if (bestPos != -1)
407         return name.mid(bestPos, bestLength).getNSString();
408     return nil;
409 }
410
411 // Searches from the beginning of the document if nothing is selected.
412 bool FrameMac::findString(NSString *string, bool forward, bool caseFlag, bool wrapFlag)
413 {
414     String target = string;
415     if (target.isEmpty())
416         return false;
417     
418     // Initially search from the start (if forward) or end (if backward) of the selection, and search to edge of document.
419     RefPtr<Range> searchRange(rangeOfContents(document()));
420     if (selection().start().node()) {
421         if (forward)
422             setStart(searchRange.get(), VisiblePosition(selection().start(), selection().affinity()));
423         else
424             setEnd(searchRange.get(), VisiblePosition(selection().end(), selection().affinity()));
425     }
426     RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
427     
428     // If we re-found the (non-empty) selected range, then search again starting just past the selected range.
429     if (selection().start().node() && *resultRange == *selection().toRange()) {
430         searchRange = rangeOfContents(document());
431         if (forward)
432             setStart(searchRange.get(), VisiblePosition(selection().end(), selection().affinity()));
433         else
434             setEnd(searchRange.get(), VisiblePosition(selection().start(), selection().affinity()));
435         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
436     }
437     
438     int exception = 0;
439     
440     // if we didn't find anything and we're wrapping, search again in the entire document (this will
441     // redundantly re-search the area already searched in some cases).
442     if (resultRange->collapsed(exception) && wrapFlag) {
443         searchRange = rangeOfContents(document());
444         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
445         // We used to return false here if we ended up with the same range that we started with
446         // (e.g., the selection was already the only instance of this text). But we decided that
447         // this should be a success case instead, so we'll just fall through in that case.
448     }
449
450     if (resultRange->collapsed(exception))
451         return false;
452
453     setSelection(SelectionController(resultRange.get(), DOWNSTREAM));
454     revealSelection();
455     return true;
456 }
457
458 void FrameMac::submitForm(const ResourceRequest& request)
459 {
460     BEGIN_BLOCK_OBJC_EXCEPTIONS;
461
462     // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
463     // We do not want to submit more than one form from the same page,
464     // nor do we want to submit a single form more than once.
465     // This flag prevents these from happening; not sure how other browsers prevent this.
466     // The flag is reset in each time we start handle a new mouse or key down event, and
467     // also in setView since this part may get reused for a page from the back/forward cache.
468     // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
469     // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
470     // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
471     // needed any more now that we reset d->m_submittedFormURL on each mouse or key down event.
472     WebCoreFrameBridge *target = request.frameName.isEmpty() ? _bridge : [_bridge findFrameNamed:request.frameName];
473     Frame *targetPart = [target impl];
474     bool willReplaceThisFrame = false;
475     for (Frame *p = this; p; p = p->tree()->parent()) {
476         if (p == targetPart) {
477             willReplaceThisFrame = true;
478             break;
479         }
480     }
481     if (willReplaceThisFrame) {
482         if (d->m_submittedFormURL == request.url())
483             return;
484         d->m_submittedFormURL = request.url();
485     }
486
487     ObjCDOMElement* submitForm = [DOMElement _elementWith:d->m_formAboutToBeSubmitted.get()];
488     NSMutableDictionary* formValues = createNSDictionary(d->m_formValuesAboutToBeSubmitted);
489     
490     if (!request.doPost()) {
491         [_bridge loadURL:request.url().getNSURL()
492                 referrer:[_bridge referrer] 
493                   reload:request.reload
494              userGesture:true
495                   target:request.frameName
496          triggeringEvent:_currentEvent
497                     form:submitForm
498               formValues:formValues];
499     } else {
500         ASSERT(request.contentType().startsWith("Content-Type: "));
501         [_bridge postWithURL:request.url().getNSURL()
502                     referrer:[_bridge referrer] 
503                       target:request.frameName
504                         data:arrayFromFormData(request.postData)
505                  contentType:request.contentType().substring(14)
506              triggeringEvent:_currentEvent
507                         form:submitForm
508                   formValues:formValues];
509     }
510     [formValues release];
511     clearRecordedFormValues();
512
513     END_BLOCK_OBJC_EXCEPTIONS;
514 }
515
516 void FrameMac::frameDetached()
517 {
518     Frame::frameDetached();
519
520     BEGIN_BLOCK_OBJC_EXCEPTIONS;
521     [Mac(this)->bridge() frameDetached];
522     END_BLOCK_OBJC_EXCEPTIONS;
523 }
524
525 void FrameMac::urlSelected(const ResourceRequest& request)
526 {
527     BEGIN_BLOCK_OBJC_EXCEPTIONS;
528
529     NSString* referrer;
530     String argsReferrer = request.referrer();
531     if (!argsReferrer.isEmpty())
532         referrer = argsReferrer;
533     else
534         referrer = [_bridge referrer];
535
536     [_bridge loadURL:request.url().getNSURL()
537             referrer:referrer
538               reload:request.reload
539          userGesture:true
540               target:request.frameName
541      triggeringEvent:_currentEvent
542                 form:nil
543           formValues:nil];
544
545     END_BLOCK_OBJC_EXCEPTIONS;
546 }
547
548 ObjectContentType FrameMac::objectContentType(const KURL& url, const String& mimeType)
549 {
550     return (ObjectContentType)[_bridge determineObjectFromMIMEType:mimeType URL:url.getNSURL()];
551 }
552
553 static NSArray* nsArray(const Vector<String>& vector)
554 {
555     unsigned len = vector.size();
556     NSMutableArray* array = [NSMutableArray arrayWithCapacity:len];
557     for (unsigned x = 0; x < len; x++)
558         [array addObject:vector[x]];
559     return array;
560 }
561
562 Plugin* FrameMac::createPlugin(Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType)
563 {
564     BEGIN_BLOCK_OBJC_EXCEPTIONS;
565
566     return new Plugin(new Widget([_bridge viewForPluginWithURL:url.getNSURL()
567                                   attributeNames:nsArray(paramNames)
568                                   attributeValues:nsArray(paramValues)
569                                   MIMEType:mimeType
570                                   DOMElement:(element ? [DOMElement _elementWith:element] : nil)]));
571
572     END_BLOCK_OBJC_EXCEPTIONS;
573     return 0;
574 }
575
576
577 Frame* FrameMac::createFrame(const KURL& url, const String& name, RenderPart* renderer, const String& referrer)
578 {
579     BEGIN_BLOCK_OBJC_EXCEPTIONS;
580     
581     BOOL allowsScrolling = YES;
582     int marginWidth = -1;
583     int marginHeight = -1;
584     if (renderer->element()->hasTagName(frameTag) || renderer->element()->hasTagName(iframeTag)) {
585         HTMLFrameElement *o = static_cast<HTMLFrameElement *>(renderer->element());
586         allowsScrolling = o->scrollingMode() != ScrollBarAlwaysOff;
587         marginWidth = o->getMarginWidth();
588         marginHeight = o->getMarginHeight();
589     }
590
591     WebCoreFrameBridge *childBridge = [_bridge createChildFrameNamed:name
592                                                              withURL:url.getNSURL()
593                                                             referrer:referrer 
594                                                           renderPart:renderer
595                                                      allowsScrolling:allowsScrolling
596                                                          marginWidth:marginWidth
597                                                         marginHeight:marginHeight];
598     return [childBridge impl];
599
600     END_BLOCK_OBJC_EXCEPTIONS;
601     return 0;
602 }
603
604 void FrameMac::setView(FrameView *view)
605 {
606     // Detach the document now, so any onUnload handlers get run - if
607     // we wait until the view is destroyed, then things won't be
608     // hooked up enough for some JavaScript calls to work.
609     if (d->m_doc && view == 0)
610         d->m_doc->detach();
611     
612     d->m_view = view;
613     
614     // Delete old PlugIn data structures
615     cleanupPluginRootObjects();
616     _bindingRoot = 0;
617     KWQRelease(_windowScriptObject);
618     _windowScriptObject = 0;
619
620     if (_windowScriptNPObject) {
621         // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window
622         // script object properly.
623         // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
624         _NPN_DeallocateObject(_windowScriptNPObject);
625         _windowScriptNPObject = 0;
626     }
627
628     // Only one form submission is allowed per view of a part.
629     // Since this part may be getting reused as a result of being
630     // pulled from the back/forward cache, reset this flag.
631     d->m_submittedFormURL = KURL();
632 }
633
634 void FrameMac::setTitle(const String &title)
635 {
636     String text = title;
637     text.replace('\\', backslashAsCurrencySymbol());
638
639     BEGIN_BLOCK_OBJC_EXCEPTIONS;
640     [_bridge setTitle:text];
641     END_BLOCK_OBJC_EXCEPTIONS;
642 }
643
644 void FrameMac::setStatusBarText(const String& status)
645 {
646     String text = status;
647     text.replace('\\', backslashAsCurrencySymbol());
648     
649     BEGIN_BLOCK_OBJC_EXCEPTIONS;
650     [_bridge setStatusText:text];
651     END_BLOCK_OBJC_EXCEPTIONS;
652 }
653
654 void FrameMac::scheduleClose()
655 {
656     if (!shouldClose())
657         return;
658     BEGIN_BLOCK_OBJC_EXCEPTIONS;
659     [_bridge closeWindowSoon];
660     END_BLOCK_OBJC_EXCEPTIONS;
661 }
662
663 void FrameMac::unfocusWindow()
664 {
665     BEGIN_BLOCK_OBJC_EXCEPTIONS;
666     [_bridge unfocusWindow];
667     END_BLOCK_OBJC_EXCEPTIONS;
668 }
669
670 String FrameMac::advanceToNextMisspelling(bool startBeforeSelection)
671 {
672     int exception = 0;
673
674     // The basic approach is to search in two phases - from the selection end to the end of the doc, and
675     // then we wrap and search from the doc start to (approximately) where we started.
676     
677     // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
678     // repeated "check spelling" commands work.
679     RefPtr<Range> searchRange(rangeOfContents(document()));
680     bool startedWithSelection = false;
681     if (selection().start().node()) {
682         startedWithSelection = true;
683         if (startBeforeSelection) {
684             VisiblePosition start(selection().start(), selection().affinity());
685             // We match AppKit's rule: Start 1 character before the selection.
686             VisiblePosition oneBeforeStart = start.previous();
687             setStart(searchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
688         } else
689             setStart(searchRange.get(), VisiblePosition(selection().end(), selection().affinity()));
690     }
691
692     // If we're not in an editable node, try to find one, make that our range to work in
693     Node *editableNode = searchRange->startContainer(exception);
694     if (!editableNode->isContentEditable()) {
695         editableNode = editableNode->nextEditable();
696         if (!editableNode) {
697             return String();
698         }
699         searchRange->setStartBefore(editableNode, exception);
700         startedWithSelection = false;   // won't need to wrap
701     }
702     
703     // topNode defines the whole range we want to operate on 
704     Node *topNode = editableNode->rootEditableElement();
705     searchRange->setEndAfter(topNode, exception);
706
707     // Make sure start of searchRange is not in the middle of a word.  Jumping back a char and then
708     // forward by a word happens to do the trick.
709     if (startedWithSelection) {
710         VisiblePosition oneBeforeStart = startVisiblePosition(searchRange.get(), DOWNSTREAM).previous();
711         if (oneBeforeStart.isNotNull()) {
712             setStart(searchRange.get(), endOfWord(oneBeforeStart));
713         } // else we were already at the start of the editable node
714     }
715     
716     if (searchRange->collapsed(exception))
717         return String();       // nothing to search in
718     
719     // Get the spell checker if it is available
720     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
721     if (checker == nil)
722         return String();
723         
724     WordAwareIterator it(searchRange.get());
725     bool wrapped = false;
726     
727     // We go to the end of our first range instead of the start of it, just to be sure
728     // we don't get foiled by any word boundary problems at the start.  It means we might
729     // do a tiny bit more searching.
730     Node *searchEndAfterWrapNode = it.range()->endContainer(exception);
731     int searchEndAfterWrapOffset = it.range()->endOffset(exception);
732
733     while (1) {
734         if (!it.atEnd()) {      // we may be starting at the end of the doc, and already by atEnd
735             const UChar* chars = it.characters();
736             int len = it.length();
737             if (len > 1 || !QChar(chars[0]).isSpace()) {
738                 NSString *chunk = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(chars) length:len freeWhenDone:NO];
739                 NSRange misspelling = [checker checkSpellingOfString:chunk startingAt:0 language:nil wrap:NO inSpellDocumentWithTag:[_bridge spellCheckerDocumentTag] wordCount:NULL];
740                 [chunk release];
741                 if (misspelling.length > 0) {
742                     // Build up result range and string.  Note the misspelling may span many text nodes,
743                     // but the CharIterator insulates us from this complexity
744                     RefPtr<Range> misspellingRange(rangeOfContents(document()));
745                     CharacterIterator chars(it.range().get());
746                     chars.advance(misspelling.location);
747                     misspellingRange->setStart(chars.range()->startContainer(exception), chars.range()->startOffset(exception), exception);
748                     DeprecatedString result = chars.string(misspelling.length);
749                     misspellingRange->setEnd(chars.range()->startContainer(exception), chars.range()->startOffset(exception), exception);
750
751                     setSelection(SelectionController(misspellingRange.get(), DOWNSTREAM));
752                     revealSelection();
753                     // Mark misspelling in document.
754                     document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
755                     return result;
756                 }
757             }
758         
759             it.advance();
760         }
761         if (it.atEnd()) {
762             if (wrapped || !startedWithSelection) {
763                 break;      // finished the second range, or we did the whole doc with the first range
764             } else {
765                 // we've gone from the selection to the end of doc, now wrap around
766                 wrapped = YES;
767                 searchRange->setStartBefore(topNode, exception);
768                 // going until the end of the very first chunk we tested is far enough
769                 searchRange->setEnd(searchEndAfterWrapNode, searchEndAfterWrapOffset, exception);
770                 it = WordAwareIterator(searchRange.get());
771             }
772         }   
773     }
774     
775     return String();
776 }
777
778 bool FrameMac::wheelEvent(NSEvent *event)
779 {
780     FrameView *v = d->m_view.get();
781
782     if (v) {
783         NSEvent *oldCurrentEvent = _currentEvent;
784         _currentEvent = KWQRetain(event);
785
786         PlatformWheelEvent qEvent(event);
787         v->handleWheelEvent(qEvent);
788
789         ASSERT(_currentEvent == event);
790         KWQRelease(event);
791         _currentEvent = oldCurrentEvent;
792
793         if (qEvent.isAccepted())
794             return true;
795     }
796
797     // FIXME: The scrolling done here should be done in the default handlers
798     // of the elements rather than here in the part.
799
800     KWQScrollDirection direction;
801     float multiplier;
802     float deltaX = [event deltaX];
803     float deltaY = [event deltaY];
804     if (deltaX < 0) {
805         direction = KWQScrollRight;
806         multiplier = -deltaX;
807     } else if (deltaX > 0) {
808         direction = KWQScrollLeft;
809         multiplier = deltaX;
810     } else if (deltaY < 0) {
811         direction = KWQScrollDown;
812         multiplier = -deltaY;
813     }  else if (deltaY > 0) {
814         direction = KWQScrollUp;
815         multiplier = deltaY;
816     } else
817         return false;
818
819     RenderObject *r = renderer();
820     if (!r)
821         return false;
822     
823     NSPoint point = [d->m_view->getDocumentView() convertPoint:[event locationInWindow] fromView:nil];
824     RenderObject::NodeInfo nodeInfo(true, true);
825     r->layer()->hitTest(nodeInfo, IntPoint(point));    
826     
827     Node *node = nodeInfo.innerNode();
828     if (!node)
829         return false;
830     
831     r = node->renderer();
832     if (!r)
833         return false;
834     
835     return r->scroll(direction, KWQScrollWheel, multiplier);
836 }
837
838 void FrameMac::startRedirectionTimer()
839 {
840     stopRedirectionTimer();
841
842     Frame::startRedirectionTimer();
843
844     // Don't report history navigations, just actual redirection.
845     if (d->m_scheduledRedirection != historyNavigationScheduled) {
846         NSTimeInterval interval = d->m_redirectionTimer.nextFireInterval();
847         NSDate *fireDate = [[NSDate alloc] initWithTimeIntervalSinceNow:interval];
848         [_bridge reportClientRedirectToURL:KURL(d->m_redirectURL).getNSURL()
849                                      delay:d->m_delayRedirect
850                                   fireDate:fireDate
851                                lockHistory:d->m_redirectLockHistory
852                                isJavaScriptFormAction:d->m_executingJavaScriptFormAction];
853         [fireDate release];
854     }
855 }
856
857 void FrameMac::stopRedirectionTimer()
858 {
859     bool wasActive = d->m_redirectionTimer.isActive();
860
861     Frame::stopRedirectionTimer();
862
863     // Don't report history navigations, just actual redirection.
864     if (wasActive && d->m_scheduledRedirection != historyNavigationScheduled)
865         [_bridge reportClientRedirectCancelled:d->m_cancelWithLoadInProgress];
866 }
867
868 String FrameMac::userAgent() const
869 {
870     BEGIN_BLOCK_OBJC_EXCEPTIONS;
871     return [_bridge userAgentForURL:url().getNSURL()];
872     END_BLOCK_OBJC_EXCEPTIONS;
873          
874     return String();
875 }
876
877 String FrameMac::mimeTypeForFileName(const String& fileName) const
878 {
879     BEGIN_BLOCK_OBJC_EXCEPTIONS;
880     return [_bridge MIMETypeForPath:fileName];
881     END_BLOCK_OBJC_EXCEPTIONS;
882
883     return String();
884 }
885
886 NSView* FrameMac::nextKeyViewInFrame(Node* node, KWQSelectionDirection direction)
887 {
888     Document* doc = document();
889     if (!doc)
890         return nil;
891     
892     for (;;) {
893         node = direction == KWQSelectingNext
894             ? doc->nextFocusNode(node) : doc->previousFocusNode(node);
895         if (!node)
896             return nil;
897         
898         RenderObject* renderer = node->renderer();
899         if (!renderer->isWidget()) {
900             static_cast<Element*>(node)->focus(); 
901             [_bridge willMakeFirstResponderForNodeFocus];
902             return [_bridge documentView];
903         }
904
905         if (Widget* widget = static_cast<RenderWidget*>(renderer)->widget()) {
906             NSView* view;
907             if (widget->isFrameView())
908                 view = Mac(static_cast<FrameView*>(widget)->frame())->nextKeyViewInFrame(0, direction);
909             else
910                 view = widget->getView();
911             if (view)
912                 return view;
913         }
914     }
915 }
916
917 NSView *FrameMac::nextKeyViewInFrameHierarchy(Node *node, KWQSelectionDirection direction)
918 {
919     NSView *next = nextKeyViewInFrame(node, direction);
920     if (!next)
921         if (FrameMac *parent = Mac(tree()->parent()))
922             next = parent->nextKeyViewInFrameHierarchy(ownerElement(), direction);
923     
924     // remove focus from currently focused node if we're giving focus to another view
925     if (next && (next != [_bridge documentView]))
926         if (Document *doc = document())
927             doc->setFocusNode(0);
928     
929     return next;
930 }
931
932 NSView *FrameMac::nextKeyView(Node *node, KWQSelectionDirection direction)
933 {
934     NSView * next;
935     BEGIN_BLOCK_OBJC_EXCEPTIONS;
936
937     next = nextKeyViewInFrameHierarchy(node, direction);
938     if (next)
939         return next;
940
941     // Look at views from the top level part up, looking for a next key view that we can use.
942
943     next = direction == KWQSelectingNext
944         ? [_bridge nextKeyViewOutsideWebFrameViews]
945         : [_bridge previousKeyViewOutsideWebFrameViews];
946
947     if (next)
948         return next;
949
950     END_BLOCK_OBJC_EXCEPTIONS;
951     
952     // If all else fails, make a loop by starting from 0.
953     return nextKeyViewInFrameHierarchy(0, direction);
954 }
955
956 NSView *FrameMac::nextKeyViewForWidget(Widget *startingWidget, KWQSelectionDirection direction)
957 {
958     // Use the event filter object to figure out which RenderWidget owns this Widget and get to the DOM.
959     // Then get the next key view in the order determined by the DOM.
960     Node *node = nodeForWidget(startingWidget);
961     ASSERT(node);
962     return Mac(frameForNode(node))->nextKeyView(node, direction);
963 }
964
965 bool FrameMac::currentEventIsMouseDownInWidget(Widget *candidate)
966 {
967     BEGIN_BLOCK_OBJC_EXCEPTIONS;
968     switch ([[NSApp currentEvent] type]) {
969         case NSLeftMouseDown:
970         case NSRightMouseDown:
971         case NSOtherMouseDown:
972             break;
973         default:
974             return NO;
975     }
976     END_BLOCK_OBJC_EXCEPTIONS;
977     
978     Node *node = nodeForWidget(candidate);
979     ASSERT(node);
980     return frameForNode(node)->d->m_view->nodeUnderMouse() == node;
981 }
982
983 bool FrameMac::currentEventIsKeyboardOptionTab()
984 {
985     BEGIN_BLOCK_OBJC_EXCEPTIONS;
986     NSEvent *evt = [NSApp currentEvent];
987     if ([evt type] != NSKeyDown) {
988         return NO;
989     }
990
991     if (([evt modifierFlags] & NSAlternateKeyMask) == 0) {
992         return NO;
993     }
994     
995     NSString *chars = [evt charactersIgnoringModifiers];
996     if ([chars length] != 1)
997         return NO;
998     
999     const unichar tabKey = 0x0009;
1000     const unichar shiftTabKey = 0x0019;
1001     unichar c = [chars characterAtIndex:0];
1002     if (c != tabKey && c != shiftTabKey)
1003         return NO;
1004     
1005     END_BLOCK_OBJC_EXCEPTIONS;
1006     return YES;
1007 }
1008
1009 bool FrameMac::handleKeyboardOptionTabInView(NSView *view)
1010 {
1011     if (FrameMac::currentEventIsKeyboardOptionTab()) {
1012         if (([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) != 0) {
1013             [[view window] selectKeyViewPrecedingView:view];
1014         } else {
1015             [[view window] selectKeyViewFollowingView:view];
1016         }
1017         return YES;
1018     }
1019     
1020     return NO;
1021 }
1022
1023 bool FrameMac::tabsToLinks() const
1024 {
1025     if ([_bridge keyboardUIMode] & WebCoreKeyboardAccessTabsToLinks)
1026         return !FrameMac::currentEventIsKeyboardOptionTab();
1027     else
1028         return FrameMac::currentEventIsKeyboardOptionTab();
1029 }
1030
1031 bool FrameMac::tabsToAllControls() const
1032 {
1033     WebCoreKeyboardUIMode keyboardUIMode = [_bridge keyboardUIMode];
1034     BOOL handlingOptionTab = FrameMac::currentEventIsKeyboardOptionTab();
1035
1036     // If tab-to-links is off, option-tab always highlights all controls
1037     if ((keyboardUIMode & WebCoreKeyboardAccessTabsToLinks) == 0 && handlingOptionTab) {
1038         return YES;
1039     }
1040     
1041     // If system preferences say to include all controls, we always include all controls
1042     if (keyboardUIMode & WebCoreKeyboardAccessFull) {
1043         return YES;
1044     }
1045     
1046     // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
1047     if (keyboardUIMode & WebCoreKeyboardAccessTabsToLinks) {
1048         return !handlingOptionTab;
1049     }
1050     
1051     return handlingOptionTab;
1052 }
1053
1054 KJS::Bindings::RootObject *FrameMac::executionContextForDOM()
1055 {
1056     return bindingRootObject();
1057 }
1058
1059 KJS::Bindings::RootObject *FrameMac::bindingRootObject()
1060 {
1061     assert(jScriptEnabled());
1062     if (!_bindingRoot) {
1063         JSLock lock;
1064         _bindingRoot = new KJS::Bindings::RootObject(0);    // The root gets deleted by JavaScriptCore.
1065         KJS::JSObject *win = KJS::Window::retrieveWindow(this);
1066         _bindingRoot->setRootObjectImp (win);
1067         _bindingRoot->setInterpreter(jScript()->interpreter());
1068         addPluginRootObject (_bindingRoot);
1069     }
1070     return _bindingRoot;
1071 }
1072
1073 WebScriptObject *FrameMac::windowScriptObject()
1074 {
1075     if (!jScriptEnabled())
1076         return 0;
1077
1078     if (!_windowScriptObject) {
1079         KJS::JSLock lock;
1080         KJS::JSObject *win = KJS::Window::retrieveWindow(this);
1081         _windowScriptObject = KWQRetainNSRelease([[WebScriptObject alloc] _initWithJSObject:win originExecutionContext:bindingRootObject() executionContext:bindingRootObject()]);
1082     }
1083
1084     return _windowScriptObject;
1085 }
1086
1087 NPObject *FrameMac::windowScriptNPObject()
1088 {
1089     if (!_windowScriptNPObject) {
1090         if (jScriptEnabled()) {
1091             // JavaScript is enabled, so there is a JavaScript window object.  Return an NPObject bound to the window
1092             // object.
1093             KJS::JSObject *win = KJS::Window::retrieveWindow(this);
1094             assert(win);
1095             _windowScriptNPObject = _NPN_CreateScriptObject(0, win, bindingRootObject(), bindingRootObject());
1096         } else {
1097             // JavaScript is not enabled, so we cannot bind the NPObject to the JavaScript window object.
1098             // Instead, we create an NPObject of a different class, one which is not bound to a JavaScript object.
1099             _windowScriptNPObject = _NPN_CreateNoScriptObject();
1100         }
1101     }
1102
1103     return _windowScriptNPObject;
1104 }
1105
1106 void FrameMac::partClearedInBegin()
1107 {
1108     if (jScriptEnabled())
1109         [_bridge windowObjectCleared];
1110 }
1111
1112 void FrameMac::openURLFromPageCache(KWQPageState *state)
1113 {
1114     // It's safe to assume none of the KWQPageState methods will raise
1115     // exceptions, since KWQPageState is implemented by WebCore and
1116     // does not throw
1117
1118     Document *doc = [state document];
1119     Node *mousePressNode = [state mousePressNode];
1120     KURL *kurl = [state URL];
1121     SavedProperties *windowProperties = [state windowProperties];
1122     SavedProperties *locationProperties = [state locationProperties];
1123     SavedBuiltins *interpreterBuiltins = [state interpreterBuiltins];
1124     PausedTimeouts *timeouts = [state pausedTimeouts];
1125     
1126     cancelRedirection();
1127
1128     // We still have to close the previous part page.
1129     closeURL();
1130             
1131     d->m_bComplete = false;
1132     
1133     // Don't re-emit the load event.
1134     d->m_bLoadEventEmitted = true;
1135     
1136     // delete old status bar msg's from kjs (if it _was_ activated on last URL)
1137     if (jScriptEnabled()) {
1138         d->m_kjsStatusBarText = String();
1139         d->m_kjsDefaultStatusBarText = String();
1140     }
1141
1142     ASSERT(kurl);
1143     
1144     d->m_url = *kurl;
1145     
1146     // initializing m_url to the new url breaks relative links when opening such a link after this call and _before_ begin() is called (when the first
1147     // data arrives) (Simon)
1148     if (url().protocol().startsWith("http") && !url().host().isEmpty() && url().path().isEmpty())
1149         d->m_url.setPath("/");
1150     
1151     // copy to m_workingURL after fixing url() above
1152     d->m_workingURL = url();
1153         
1154     started();
1155     
1156     // -----------begin-----------
1157     clear();
1158
1159     doc->setInPageCache(NO);
1160
1161     d->m_bCleared = false;
1162     d->m_bComplete = false;
1163     d->m_bLoadEventEmitted = false;
1164     d->m_referrer = url().url();
1165     
1166     setView(doc->view());
1167     
1168     d->m_doc = doc;
1169     d->m_mousePressNode = mousePressNode;
1170     d->m_decoder = doc->decoder();
1171
1172     updatePolicyBaseURL();
1173
1174     { // scope the lock
1175         JSLock lock;
1176         restoreWindowProperties(windowProperties);
1177         restoreLocationProperties(locationProperties);
1178         restoreInterpreterBuiltins(*interpreterBuiltins);
1179     }
1180
1181     resumeTimeouts(timeouts);
1182     
1183     checkCompleted();
1184 }
1185
1186 WebCoreFrameBridge *FrameMac::bridgeForWidget(const Widget *widget)
1187 {
1188     ASSERT_ARG(widget, widget);
1189     
1190     FrameMac *frame = Mac(frameForWidget(widget));
1191     ASSERT(frame);
1192     return frame->bridge();
1193 }
1194
1195 NSView *FrameMac::documentViewForNode(Node *node)
1196 {
1197     WebCoreFrameBridge *bridge = Mac(frameForNode(node))->bridge();
1198     return [bridge documentView];
1199 }
1200
1201 void FrameMac::saveDocumentState()
1202 {
1203     // Do not save doc state if the page has a password field and a form that would be submitted
1204     // via https
1205     if (!(d->m_doc && d->m_doc->hasPasswordField() && d->m_doc->hasSecureForm())) {
1206         BEGIN_BLOCK_OBJC_EXCEPTIONS;
1207         [_bridge saveDocumentState];
1208         END_BLOCK_OBJC_EXCEPTIONS;
1209     }
1210 }
1211
1212 void FrameMac::restoreDocumentState()
1213 {
1214     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1215     [_bridge restoreDocumentState];
1216     END_BLOCK_OBJC_EXCEPTIONS;
1217 }
1218
1219 String FrameMac::incomingReferrer() const
1220 {
1221     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1222     return [_bridge incomingReferrer];
1223     END_BLOCK_OBJC_EXCEPTIONS;
1224
1225     return String();
1226 }
1227
1228 void FrameMac::runJavaScriptAlert(const String& message)
1229 {
1230     String text = message;
1231     text.replace('\\', backslashAsCurrencySymbol());
1232     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1233     [_bridge runJavaScriptAlertPanelWithMessage:text];
1234     END_BLOCK_OBJC_EXCEPTIONS;
1235 }
1236
1237 bool FrameMac::runJavaScriptConfirm(const String& message)
1238 {
1239     String text = message;
1240     text.replace('\\', backslashAsCurrencySymbol());
1241
1242     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1243     return [_bridge runJavaScriptConfirmPanelWithMessage:text];
1244     END_BLOCK_OBJC_EXCEPTIONS;
1245
1246     return false;
1247 }
1248
1249 bool FrameMac::runJavaScriptPrompt(const String& prompt, const String& defaultValue, String& result)
1250 {
1251     String promptText = prompt;
1252     promptText.replace('\\', backslashAsCurrencySymbol());
1253     String defaultValueText = defaultValue;
1254     defaultValueText.replace('\\', backslashAsCurrencySymbol());
1255
1256     bool ok;
1257     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1258     NSString *returnedText = nil;
1259
1260     ok = [_bridge runJavaScriptTextInputPanelWithPrompt:prompt
1261         defaultText:defaultValue returningText:&returnedText];
1262
1263     if (ok) {
1264         result = String(returnedText);
1265         result.replace(backslashAsCurrencySymbol(), '\\');
1266     }
1267
1268     return ok;
1269     END_BLOCK_OBJC_EXCEPTIONS;
1270     
1271     return false;
1272 }
1273
1274 bool FrameMac::locationbarVisible()
1275 {
1276     return [_bridge areToolbarsVisible];
1277 }
1278
1279 bool FrameMac::menubarVisible()
1280 {
1281     // The menubar is always on in Mac OS X UI
1282     return true;
1283 }
1284
1285 bool FrameMac::personalbarVisible()
1286 {
1287     return [_bridge areToolbarsVisible];
1288 }
1289
1290 bool FrameMac::statusbarVisible()
1291 {
1292     return [_bridge isStatusbarVisible];
1293 }
1294
1295 bool FrameMac::toolbarVisible()
1296 {
1297     return [_bridge areToolbarsVisible];
1298 }
1299
1300 void FrameMac::addMessageToConsole(const String &message, unsigned lineNumber, const String &sourceURL)
1301 {
1302     NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
1303         (NSString *)message, @"message",
1304         [NSNumber numberWithInt: lineNumber], @"lineNumber",
1305         (NSString *)sourceURL, @"sourceURL",
1306         NULL];
1307     [_bridge addMessageToConsole:dictionary];
1308 }
1309
1310 void FrameMac::createEmptyDocument()
1311 {
1312     // Although it's not completely clear from the name of this function,
1313     // it does nothing if we already have a document, and just creates an
1314     // empty one if we have no document at all.
1315     if (!d->m_doc) {
1316         BEGIN_BLOCK_OBJC_EXCEPTIONS;
1317         [_bridge loadEmptyDocumentSynchronously];
1318         END_BLOCK_OBJC_EXCEPTIONS;
1319
1320         updateBaseURLForEmptyDocument();
1321     }
1322 }
1323
1324 bool FrameMac::keyEvent(NSEvent *event)
1325 {
1326     bool result;
1327     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1328
1329     ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
1330
1331     // Check for cases where we are too early for events -- possible unmatched key up
1332     // from pressing return in the location bar.
1333     Document *doc = document();
1334     if (!doc) {
1335         return false;
1336     }
1337     Node *node = doc->focusNode();
1338     if (!node) {
1339         if (doc->isHTMLDocument())
1340             node = doc->body();
1341         else
1342             node = doc->documentElement();
1343         if (!node)
1344             return false;
1345     }
1346     
1347     if ([event type] == NSKeyDown) {
1348         prepareForUserAction();
1349     }
1350
1351     NSEvent *oldCurrentEvent = _currentEvent;
1352     _currentEvent = KWQRetain(event);
1353
1354     PlatformKeyboardEvent qEvent(event);
1355     result = !EventTargetNodeCast(node)->dispatchKeyEvent(qEvent);
1356
1357     // We want to send both a down and a press for the initial key event.
1358     // To get KHTML to do this, we send a second KeyPress with "is repeat" set to true,
1359     // which causes it to send a press to the DOM.
1360     // That's not a great hack; it would be good to do this in a better way.
1361     if ([event type] == NSKeyDown && ![event isARepeat]) {
1362         PlatformKeyboardEvent repeatEvent(event, true);
1363         if (!EventTargetNodeCast(node)->dispatchKeyEvent(repeatEvent))
1364             result = true;
1365     }
1366
1367     ASSERT(_currentEvent == event);
1368     KWQRelease(event);
1369     _currentEvent = oldCurrentEvent;
1370
1371     return result;
1372
1373     END_BLOCK_OBJC_EXCEPTIONS;
1374
1375     return false;
1376 }
1377
1378 void FrameMac::handleMousePressEvent(const MouseEventWithHitTestResults& event)
1379 {
1380     bool singleClick = [_currentEvent clickCount] <= 1;
1381
1382     // If we got the event back, that must mean it wasn't prevented,
1383     // so it's allowed to start a drag or selection.
1384     _mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode());
1385     
1386     // Careful that the drag starting logic stays in sync with eventMayStartDrag()
1387     _mouseDownMayStartDrag = singleClick;
1388
1389     d->m_mousePressNode = event.targetNode();
1390     
1391     if (!passWidgetMouseDownEventToWidget(event, false)) {
1392         // We don't do this at the start of mouse down handling (before calling into WebCore),
1393         // because we don't want to do it until we know we didn't hit a widget.
1394         NSView *view = d->m_view->getDocumentView();
1395
1396         if (singleClick) {
1397             BEGIN_BLOCK_OBJC_EXCEPTIONS;
1398             if ([_bridge firstResponder] != view) {
1399                 [_bridge makeFirstResponder:view];
1400             }
1401             END_BLOCK_OBJC_EXCEPTIONS;
1402         }
1403
1404         Frame::handleMousePressEvent(event);
1405     }
1406 }
1407
1408 bool FrameMac::passMouseDownEventToWidget(Widget* widget)
1409 {
1410     // FIXME: this method always returns true
1411
1412     if (!widget) {
1413         LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
1414         return true;
1415     }
1416
1417     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1418     
1419     NSView *nodeView = widget->getView();
1420     ASSERT(nodeView);
1421     ASSERT([nodeView superview]);
1422     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[_currentEvent locationInWindow] fromView:nil]];
1423     if (view == nil) {
1424         LOG_ERROR("KHTML says we hit a RenderWidget, but AppKit doesn't agree we hit the corresponding NSView");
1425         return true;
1426     }
1427     
1428     if ([_bridge firstResponder] == view) {
1429         // In the case where we just became first responder, we should send the mouseDown:
1430         // to the NSTextField, not the NSTextField's editor. This code makes sure that happens.
1431         // If we don't do this, we see a flash of selected text when clicking in a text field.
1432         if (![_bridge wasFirstResponderAtMouseDownTime:view] && [view isKindOfClass:[NSTextView class]]) {
1433             NSView *superview = view;
1434             while (superview != nodeView) {
1435                 superview = [superview superview];
1436                 ASSERT(superview);
1437                 if ([superview isKindOfClass:[NSControl class]]) {
1438                     NSControl *control = static_cast<NSControl *>(superview);
1439                     if ([control currentEditor] == view) {
1440                         view = superview;
1441                     }
1442                     break;
1443                 }
1444             }
1445         }
1446     } else {
1447         // Normally [NSWindow sendEvent:] handles setting the first responder.
1448         // But in our case, the event was sent to the view representing the entire web page.
1449         if ([_currentEvent clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) {
1450             [_bridge makeFirstResponder:view];
1451         }
1452     }
1453
1454     // We need to "defer loading" and defer timers while we are tracking the mouse.
1455     // That's because we don't want the new page to load while the user is holding the mouse down.
1456     
1457     BOOL wasDeferringLoading = [_bridge defersLoading];
1458     if (!wasDeferringLoading)
1459         [_bridge setDefersLoading:YES];
1460     BOOL wasDeferringTimers = isDeferringTimers();
1461     if (!wasDeferringTimers)
1462         setDeferringTimers(true);
1463
1464     ASSERT(!_sendingEventToSubview);
1465     _sendingEventToSubview = true;
1466     [view mouseDown:_currentEvent];
1467     _sendingEventToSubview = false;
1468     
1469     if (!wasDeferringTimers)
1470         setDeferringTimers(false);
1471     if (!wasDeferringLoading)
1472         [_bridge setDefersLoading:NO];
1473
1474     // Remember which view we sent the event to, so we can direct the release event properly.
1475     _mouseDownView = view;
1476     _mouseDownWasInSubframe = false;
1477
1478     END_BLOCK_OBJC_EXCEPTIONS;
1479
1480     return true;
1481 }
1482
1483 bool FrameMac::lastEventIsMouseUp() const
1484 {
1485     // Many AK widgets run their own event loops and consume events while the mouse is down.
1486     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
1487     // the khtml state with this mouseUp, which khtml never saw.  This method lets us detect
1488     // that state.
1489
1490     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1491     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
1492     if (_currentEvent != currentEventAfterHandlingMouseDown) {
1493         if ([currentEventAfterHandlingMouseDown type] == NSLeftMouseUp) {
1494             return true;
1495         }
1496     }
1497     END_BLOCK_OBJC_EXCEPTIONS;
1498
1499     return false;
1500 }
1501     
1502 // Note that this does the same kind of check as [target isDescendantOf:superview].
1503 // There are two differences: This is a lot slower because it has to walk the whole
1504 // tree, and this works in cases where the target has already been deallocated.
1505 static bool findViewInSubviews(NSView *superview, NSView *target)
1506 {
1507     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1508     NSEnumerator *e = [[superview subviews] objectEnumerator];
1509     NSView *subview;
1510     while ((subview = [e nextObject])) {
1511         if (subview == target || findViewInSubviews(subview, target)) {
1512             return true;
1513         }
1514     }
1515     END_BLOCK_OBJC_EXCEPTIONS;
1516     
1517     return false;
1518 }
1519
1520 NSView *FrameMac::mouseDownViewIfStillGood()
1521 {
1522     // Since we have no way of tracking the lifetime of _mouseDownView, we have to assume that
1523     // it could be deallocated already. We search for it in our subview tree; if we don't find
1524     // it, we set it to nil.
1525     NSView *mouseDownView = _mouseDownView;
1526     if (!mouseDownView) {
1527         return nil;
1528     }
1529     FrameView *topFrameView = d->m_view.get();
1530     NSView *topView = topFrameView ? topFrameView->getView() : nil;
1531     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
1532         _mouseDownView = nil;
1533         return nil;
1534     }
1535     return mouseDownView;
1536 }
1537
1538 bool FrameMac::eventMayStartDrag(NSEvent *event) const
1539 {
1540     // This is a pre-flight check of whether the event might lead to a drag being started.  Be careful
1541     // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we set
1542     // _mouseDownMayStartDrag in handleMousePressEvent
1543     
1544     if ([event type] != NSLeftMouseDown || [event clickCount] != 1) {
1545         return false;
1546     }
1547     
1548     BOOL DHTMLFlag, UAFlag;
1549     [_bridge allowDHTMLDrag:&DHTMLFlag UADrag:&UAFlag];
1550     if (!DHTMLFlag && !UAFlag) {
1551         return false;
1552     }
1553
1554     NSPoint loc = [event locationInWindow];
1555     IntPoint mouseDownPos = d->m_view->viewportToContents(IntPoint(loc));
1556     RenderObject::NodeInfo nodeInfo(true, false);
1557     renderer()->layer()->hitTest(nodeInfo, mouseDownPos);
1558     bool srcIsDHTML;
1559     return nodeInfo.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, mouseDownPos.x(), mouseDownPos.y(), srcIsDHTML);
1560 }
1561
1562 // The link drag hysteresis is much larger than the others because there
1563 // needs to be enough space to cancel the link press without starting a link drag,
1564 // and because dragging links is rare.
1565 const float LinkDragHysteresis = 40.0;
1566 const float ImageDragHysteresis = 5.0;
1567 const float TextDragHysteresis = 3.0;
1568 const float GeneralDragHysteresis = 3.0;
1569 const float TextDragDelay = 0.15;
1570
1571 bool FrameMac::dragHysteresisExceeded(float dragLocationX, float dragLocationY) const
1572 {
1573     IntPoint dragViewportLocation((int)dragLocationX, (int)dragLocationY);
1574     IntPoint dragLocation = d->m_view->viewportToContents(dragViewportLocation);
1575     IntSize delta = dragLocation - m_mouseDownPos;
1576     
1577     float threshold = GeneralDragHysteresis;
1578     if (_dragSrcIsImage)
1579         threshold = ImageDragHysteresis;
1580     else if (_dragSrcIsLink)
1581         threshold = LinkDragHysteresis;
1582     else if (_dragSrcInSelection)
1583         threshold = TextDragHysteresis;
1584
1585     return fabsf(delta.width()) >= threshold || fabsf(delta.height()) >= threshold;
1586 }
1587
1588 void FrameMac::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
1589 {
1590     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1591
1592     if ([_currentEvent type] == NSLeftMouseDragged) {
1593         NSView *view = mouseDownViewIfStillGood();
1594
1595         if (view) {
1596             _sendingEventToSubview = true;
1597             [view mouseDragged:_currentEvent];
1598             _sendingEventToSubview = false;
1599             return;
1600         }
1601
1602         // Careful that the drag starting logic stays in sync with eventMayStartDrag()
1603     
1604         if (_mouseDownMayStartDrag && !_dragSrc) {
1605             BOOL tempFlag1, tempFlag2;
1606             [_bridge allowDHTMLDrag:&tempFlag1 UADrag:&tempFlag2];
1607             _dragSrcMayBeDHTML = tempFlag1;
1608             _dragSrcMayBeUA = tempFlag2;
1609             if (!_dragSrcMayBeDHTML && !_dragSrcMayBeUA) {
1610                 _mouseDownMayStartDrag = false;     // no element is draggable
1611             }
1612         }
1613         
1614         if (_mouseDownMayStartDrag && !_dragSrc) {
1615             // try to find an element that wants to be dragged
1616             RenderObject::NodeInfo nodeInfo(true, false);
1617             renderer()->layer()->hitTest(nodeInfo, m_mouseDownPos);
1618             Node *node = nodeInfo.innerNode();
1619             _dragSrc = (node && node->renderer()) ? node->renderer()->draggableNode(_dragSrcMayBeDHTML, _dragSrcMayBeUA, m_mouseDownPos.x(), m_mouseDownPos.y(), _dragSrcIsDHTML) : 0;
1620             if (!_dragSrc) {
1621                 _mouseDownMayStartDrag = false;     // no element is draggable
1622             } else {
1623                 // remember some facts about this source, while we have a NodeInfo handy
1624                 node = nodeInfo.URLElement();
1625                 _dragSrcIsLink = node && node->isLink();
1626
1627                 node = nodeInfo.innerNonSharedNode();
1628                 _dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
1629                 
1630                 _dragSrcInSelection = isPointInsideSelection(m_mouseDownPos);
1631             }                
1632         }
1633         
1634         // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
1635         // or else we bail on the dragging stuff and allow selection to occur
1636         if (_mouseDownMayStartDrag && _dragSrcInSelection && [_currentEvent timestamp] - _mouseDownTimestamp < TextDragDelay) {
1637             _mouseDownMayStartDrag = false;
1638             // ...but if this was the first click in the window, we don't even want to start selection
1639             if (_activationEventNumber == [_currentEvent eventNumber]) {
1640                 _mouseDownMayStartSelect = false;
1641             }
1642         }
1643
1644         if (_mouseDownMayStartDrag) {
1645             // We are starting a text/image/url drag, so the cursor should be an arrow
1646             d->m_view->setCursor(pointerCursor());
1647             
1648             NSPoint dragLocation = [_currentEvent locationInWindow];
1649             if (dragHysteresisExceeded(dragLocation.x, dragLocation.y)) {
1650                 
1651                 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
1652                 d->m_view->invalidateClick();
1653
1654                 NSImage *dragImage = nil;       // we use these values if WC is out of the loop
1655                 NSPoint dragLoc = NSZeroPoint;
1656                 NSDragOperation srcOp = NSDragOperationNone;                
1657                 BOOL wcWrotePasteboard = NO;
1658                 if (_dragSrcMayBeDHTML) {
1659                     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
1660                     // Must be done before ondragstart adds types and data to the pboard,
1661                     // also done for security, as it erases data from the last drag
1662                     [pasteboard declareTypes:[NSArray array] owner:nil];
1663                     
1664                     freeClipboard();    // would only happen if we missed a dragEnd.  Do it anyway, just
1665                                         // to make sure it gets numbified
1666                     _dragClipboard = new ClipboardMac(true, pasteboard, ClipboardMac::Writable, this);
1667                     
1668                     // If this is drag of an element, get set up to generate a default image.  Otherwise
1669                     // WebKit will generate the default, the element doesn't override.
1670                     if (_dragSrcIsDHTML) {
1671                         int srcX, srcY;
1672                         _dragSrc->renderer()->absolutePosition(srcX, srcY);
1673                         IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY);
1674                         _dragClipboard->setDragImageElement(_dragSrc.get(), IntPoint() + delta);
1675                     } 
1676
1677                     _mouseDownMayStartDrag = dispatchDragSrcEvent(dragstartEvent, m_mouseDown);
1678                     // Invalidate clipboard here against anymore pasteboard writing for security.  The drag
1679                     // image can still be changed as we drag, but not the pasteboard data.
1680                     _dragClipboard->setAccessPolicy(ClipboardMac::ImageWritable);
1681                     
1682                     if (_mouseDownMayStartDrag) {
1683                         // gather values from DHTML element, if it set any
1684                         _dragClipboard->sourceOperation(&srcOp);
1685
1686                         NSArray *types = [pasteboard types];
1687                         wcWrotePasteboard = types && [types count] > 0;
1688
1689                         if (_dragSrcMayBeDHTML) {
1690                             dragImage = _dragClipboard->dragNSImage(&dragLoc);
1691                         }
1692                         
1693                         // Yuck, dragSourceMovedTo() can be called as a result of kicking off the drag with
1694                         // dragImage!  Because of that dumb reentrancy, we may think we've not started the
1695                         // drag when that happens.  So we have to assume it's started before we kick it off.
1696                         _dragClipboard->setDragHasStarted();
1697                     }
1698                 }
1699                 
1700                 if (_mouseDownMayStartDrag) {
1701                     BOOL startedDrag = [_bridge startDraggingImage:dragImage at:dragLoc operation:srcOp event:_currentEvent sourceIsDHTML:_dragSrcIsDHTML DHTMLWroteData:wcWrotePasteboard];
1702                     if (!startedDrag && _dragSrcMayBeDHTML) {
1703                         // WebKit canned the drag at the last minute - we owe _dragSrc a DRAGEND event
1704                         PlatformMouseEvent event;
1705                         dispatchDragSrcEvent(dragendEvent, event);
1706                         _mouseDownMayStartDrag = false;
1707                     }
1708                 } 
1709
1710                 if (!_mouseDownMayStartDrag) {
1711                     // something failed to start the drag, cleanup
1712                     freeClipboard();
1713                     _dragSrc = 0;
1714                 }
1715             }
1716
1717             // No more default handling (like selection), whether we're past the hysteresis bounds or not
1718             return;
1719         }
1720         if (!_mouseDownMayStartSelect) {
1721             return;
1722         }
1723
1724         // Don't allow dragging or click handling after we've started selecting.
1725         _mouseDownMayStartDrag = false;
1726         d->m_view->invalidateClick();
1727
1728         Node* node = event.targetNode();
1729         RenderLayer* layer = 0;
1730         if (node && node->renderer())
1731             layer = node->renderer()->enclosingLayer();
1732             
1733         // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
1734         // Otherwise, let the bridge handle it so the view can scroll itself.
1735         while (layer && !layer->shouldAutoscroll())
1736             layer = layer->parent();
1737         if (layer)
1738             handleAutoscroll(layer);
1739         else {
1740             if (!d->m_autoscrollTimer.isActive())
1741                 startAutoscrollTimer();
1742             [_bridge handleAutoscrollForMouseDragged:_currentEvent];
1743         }
1744             
1745     } else {
1746         // If we allowed the other side of the bridge to handle a drag
1747         // last time, then m_bMousePressed might still be set. So we
1748         // clear it now to make sure the next move after a drag
1749         // doesn't look like a drag.
1750         d->m_bMousePressed = false;
1751     }
1752
1753     Frame::handleMouseMoveEvent(event);
1754
1755     END_BLOCK_OBJC_EXCEPTIONS;
1756 }
1757
1758 // Returns whether caller should continue with "the default processing", which is the same as 
1759 // the event handler NOT setting the return value to false
1760 bool FrameMac::dispatchCPPEvent(const AtomicString &eventType, ClipboardMac::AccessPolicy policy)
1761 {
1762     Node* target = d->m_selection.start().element();
1763     if (!target && document())
1764         target = document()->body();
1765     if (!target)
1766         return true;
1767
1768     RefPtr<ClipboardMac> clipboard = new ClipboardMac(false, [NSPasteboard generalPasteboard], (ClipboardMac::AccessPolicy)policy);
1769
1770     ExceptionCode ec = 0;
1771     RefPtr<Event> evt = new ClipboardEvent(eventType, true, true, clipboard.get());
1772     EventTargetNodeCast(target)->dispatchEvent(evt, ec, true);
1773     bool noDefaultProcessing = evt->defaultPrevented();
1774
1775     // invalidate clipboard here for security
1776     clipboard->setAccessPolicy(ClipboardMac::Numb);
1777
1778     return !noDefaultProcessing;
1779 }
1780
1781 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
1782 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
1783 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
1784 // normally selectable to implement copy/paste (like divs, or a document body).
1785
1786 bool FrameMac::mayCut()
1787 {
1788     return !dispatchCPPEvent(beforecutEvent, ClipboardMac::Numb);
1789 }
1790
1791 bool FrameMac::mayCopy()
1792 {
1793     return !dispatchCPPEvent(beforecopyEvent, ClipboardMac::Numb);
1794 }
1795
1796 bool FrameMac::mayPaste()
1797 {
1798     return !dispatchCPPEvent(beforepasteEvent, ClipboardMac::Numb);
1799 }
1800
1801 bool FrameMac::tryCut()
1802 {
1803     // Must be done before oncut adds types and data to the pboard,
1804     // also done for security, as it erases data from the last copy/paste.
1805     [[NSPasteboard generalPasteboard] declareTypes:[NSArray array] owner:nil];
1806
1807     return !dispatchCPPEvent(cutEvent, ClipboardMac::Writable);
1808 }
1809
1810 bool FrameMac::tryCopy()
1811 {
1812     // Must be done before oncopy adds types and data to the pboard,
1813     // also done for security, as it erases data from the last copy/paste.
1814     [[NSPasteboard generalPasteboard] declareTypes:[NSArray array] owner:nil];
1815
1816     return !dispatchCPPEvent(copyEvent, ClipboardMac::Writable);
1817 }
1818
1819 bool FrameMac::tryPaste()
1820 {
1821     return !dispatchCPPEvent(pasteEvent, ClipboardMac::Readable);
1822 }
1823
1824 void FrameMac::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1825 {
1826     NSView *view = mouseDownViewIfStillGood();
1827     if (!view) {
1828         // If this was the first click in the window, we don't even want to clear the selection.
1829         // This case occurs when the user clicks on a draggable element, since we have to process
1830         // the mouse down and drag events to see if we might start a drag.  For other first clicks
1831         // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
1832         // ignored upstream of this layer.
1833         if (_activationEventNumber != [_currentEvent eventNumber])
1834             Frame::handleMouseReleaseEvent(event);
1835         return;
1836     }
1837     stopAutoscrollTimer();
1838     
1839     _sendingEventToSubview = true;
1840     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1841     [view mouseUp:_currentEvent];
1842     END_BLOCK_OBJC_EXCEPTIONS;
1843     _sendingEventToSubview = false;
1844 }
1845
1846 bool FrameMac::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframePart)
1847 {
1848     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1849
1850     switch ([_currentEvent type]) {
1851         case NSMouseMoved: {
1852             ASSERT(subframePart);
1853             [Mac(subframePart)->bridge() mouseMoved:_currentEvent];
1854             return true;
1855         }
1856         
1857         case NSLeftMouseDown: {
1858             Node *node = event.targetNode();
1859             if (!node) {
1860                 return false;
1861             }
1862             RenderObject *renderer = node->renderer();
1863             if (!renderer || !renderer->isWidget()) {
1864                 return false;
1865             }
1866             Widget *widget = static_cast<RenderWidget *>(renderer)->widget();
1867             if (!widget || !widget->isFrameView())
1868                 return false;
1869             if (!passWidgetMouseDownEventToWidget(static_cast<RenderWidget *>(renderer))) {
1870                 return false;
1871             }
1872             _mouseDownWasInSubframe = true;
1873             return true;
1874         }
1875         case NSLeftMouseUp: {
1876             if (!_mouseDownWasInSubframe) {
1877                 return false;
1878             }
1879             NSView *view = mouseDownViewIfStillGood();
1880             if (!view) {
1881                 return false;
1882             }
1883             ASSERT(!_sendingEventToSubview);
1884             _sendingEventToSubview = true;
1885             [view mouseUp:_currentEvent];
1886             _sendingEventToSubview = false;
1887             return true;
1888         }
1889         case NSLeftMouseDragged: {
1890             if (!_mouseDownWasInSubframe) {
1891                 return false;
1892             }
1893             NSView *view = mouseDownViewIfStillGood();
1894             if (!view) {
1895                 return false;
1896             }
1897             ASSERT(!_sendingEventToSubview);
1898             _sendingEventToSubview = true;
1899             [view mouseDragged:_currentEvent];
1900             _sendingEventToSubview = false;
1901             return true;
1902         }
1903         default:
1904             return false;
1905     }
1906     END_BLOCK_OBJC_EXCEPTIONS;
1907
1908     return false;
1909 }
1910
1911 bool FrameMac::passWheelEventToChildWidget(Node *node)
1912 {
1913     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1914         
1915     if ([_currentEvent type] != NSScrollWheel || _sendingEventToSubview || !node) 
1916         return false;
1917     else {
1918         RenderObject *renderer = node->renderer();
1919         if (!renderer || !renderer->isWidget())
1920             return false;
1921         Widget *widget = static_cast<RenderWidget *>(renderer)->widget();
1922         if (!widget)
1923             return false;
1924             
1925         NSView *nodeView = widget->getView();
1926         ASSERT(nodeView);
1927         ASSERT([nodeView superview]);
1928         NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[_currentEvent locationInWindow] fromView:nil]];
1929     
1930         ASSERT(view);
1931         _sendingEventToSubview = true;
1932         [view scrollWheel:_currentEvent];
1933         _sendingEventToSubview = false;
1934         return true;
1935     }
1936             
1937     END_BLOCK_OBJC_EXCEPTIONS;
1938     return false;
1939 }
1940
1941 void FrameMac::mouseDown(NSEvent *event)
1942 {
1943     FrameView *v = d->m_view.get();
1944     if (!v || _sendingEventToSubview)
1945         return;
1946
1947     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1948
1949     prepareForUserAction();
1950
1951     _mouseDownView = nil;
1952     _dragSrc = 0;
1953     
1954     NSEvent *oldCurrentEvent = _currentEvent;
1955     _currentEvent = KWQRetain(event);
1956     m_mouseDown = PlatformMouseEvent(event);
1957     NSPoint loc = [event locationInWindow];
1958     m_mouseDownPos = d->m_view->viewportToContents(IntPoint(loc));
1959     _mouseDownTimestamp = [event timestamp];
1960
1961     _mouseDownMayStartDrag = false;
1962     _mouseDownMayStartSelect = false;
1963
1964     v->handleMousePressEvent(event);
1965     
1966     ASSERT(_currentEvent == event);
1967     KWQRelease(event);
1968     _currentEvent = oldCurrentEvent;
1969
1970     END_BLOCK_OBJC_EXCEPTIONS;
1971 }
1972
1973 void FrameMac::mouseDragged(NSEvent *event)
1974 {
1975     FrameView *v = d->m_view.get();
1976     if (!v || _sendingEventToSubview) {
1977         return;
1978     }
1979
1980     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1981
1982     NSEvent *oldCurrentEvent = _currentEvent;
1983     _currentEvent = KWQRetain(event);
1984
1985     v->handleMouseMoveEvent(event);
1986     
1987     ASSERT(_currentEvent == event);
1988     KWQRelease(event);
1989     _currentEvent = oldCurrentEvent;
1990
1991     END_BLOCK_OBJC_EXCEPTIONS;
1992 }
1993
1994 void FrameMac::mouseUp(NSEvent *event)
1995 {
1996     FrameView *v = d->m_view.get();
1997     if (!v || _sendingEventToSubview)
1998         return;
1999
2000     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2001
2002     NSEvent *oldCurrentEvent = _currentEvent;
2003     _currentEvent = KWQRetain(event);
2004
2005     // Our behavior here is a little different that Qt. Qt always sends
2006     // a mouse release event, even for a double click. To correct problems
2007     // in khtml's DOM click event handling we do not send a release here
2008     // for a double click. Instead we send that event from FrameView's
2009     // handleMouseDoubleClickEvent. Note also that the third click of
2010     // a triple click is treated as a single click, but the fourth is then
2011     // treated as another double click. Hence the "% 2" below.
2012     int clickCount = [event clickCount];
2013     if (clickCount > 0 && clickCount % 2 == 0)
2014         v->handleMouseDoubleClickEvent(event);
2015     else
2016         v->handleMouseReleaseEvent(event);
2017     
2018     ASSERT(_currentEvent == event);
2019     KWQRelease(event);
2020     _currentEvent = oldCurrentEvent;
2021     
2022     _mouseDownView = nil;
2023
2024     END_BLOCK_OBJC_EXCEPTIONS;
2025 }
2026
2027 /*
2028  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
2029  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
2030  is done, this routine is used to fix things up.  When a mouse down started us tracking in
2031  the widget, we post a fake mouse up to balance the mouse down we started with. When a 
2032  key down started us tracking in the widget, we post a fake key up to balance things out.
2033  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
2034  be over after the tracking is done.
2035  */
2036 void FrameMac::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
2037 {
2038     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2039
2040     _sendingEventToSubview = false;
2041     int eventType = [initiatingEvent type];
2042     if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
2043         NSEvent *fakeEvent = nil;
2044         if (eventType == NSLeftMouseDown) {
2045             fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
2046                                     location:[initiatingEvent locationInWindow]
2047                                 modifierFlags:[initiatingEvent modifierFlags]
2048                                     timestamp:[initiatingEvent timestamp]
2049                                 windowNumber:[initiatingEvent windowNumber]
2050                                         context:[initiatingEvent context]
2051                                     eventNumber:[initiatingEvent eventNumber]
2052                                     clickCount:[initiatingEvent clickCount]
2053                                     pressure:[initiatingEvent pressure]];
2054         
2055             mouseUp(fakeEvent);
2056         }
2057         else { // eventType == NSKeyDown
2058             fakeEvent = [NSEvent keyEventWithType:NSKeyUp
2059                                     location:[initiatingEvent locationInWindow]
2060                                modifierFlags:[initiatingEvent modifierFlags]
2061                                    timestamp:[initiatingEvent timestamp]
2062                                 windowNumber:[initiatingEvent windowNumber]
2063                                      context:[initiatingEvent context]
2064                                   characters:[initiatingEvent characters] 
2065                  charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
2066                                    isARepeat:[initiatingEvent isARepeat] 
2067                                      keyCode:[initiatingEvent keyCode]];
2068             keyEvent(fakeEvent);
2069         }
2070         // FIXME:  We should really get the current modifierFlags here, but there's no way to poll
2071         // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
2072         // no up-to-date cache of them anywhere.
2073         fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
2074                                        location:[[_bridge window] convertScreenToBase:[NSEvent mouseLocation]]
2075                                   modifierFlags:[initiatingEvent modifierFlags]
2076                                       timestamp:[initiatingEvent timestamp]
2077                                    windowNumber:[initiatingEvent windowNumber]
2078                                         context:[initiatingEvent context]
2079                                     eventNumber:0
2080                                      clickCount:0
2081                                        pressure:0];
2082         mouseMoved(fakeEvent);
2083     }
2084     
2085     END_BLOCK_OBJC_EXCEPTIONS;
2086 }
2087
2088 void FrameMac::mouseMoved(NSEvent *event)
2089 {
2090     FrameView *v = d->m_view.get();
2091     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
2092     // These happen because WebKit sometimes has to fake up moved events.
2093     if (!v || d->m_bMousePressed || _sendingEventToSubview)
2094         return;
2095     
2096     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2097
2098     NSEvent *oldCurrentEvent = _currentEvent;
2099     _currentEvent = KWQRetain(event);
2100     
2101     v->handleMouseMoveEvent(event);
2102     
2103     ASSERT(_currentEvent == event);
2104     KWQRelease(event);
2105     _currentEvent = oldCurrentEvent;
2106
2107     END_BLOCK_OBJC_EXCEPTIONS;
2108 }
2109
2110 // Called as we walk up the element chain for nodes with CSS property -webkit-user-drag == auto
2111 bool FrameMac::shouldDragAutoNode(Node* node, const IntPoint& point) const
2112 {
2113     // We assume that WebKit only cares about dragging things that can be leaf nodes (text, images, urls).
2114     // This saves a bunch of expensive calls (creating WC and WK element dicts) as we walk farther up
2115     // the node hierarchy, and we also don't have to cook up a way to ask WK about non-leaf nodes
2116     // (since right now WK just hit-tests using a cached lastMouseDown).
2117     if (!node->hasChildNodes() && d->m_view) {
2118         NSPoint eventLoc = d->m_view->contentsToViewport(point);
2119         return [_bridge mayStartDragAtEventLocation:eventLoc];
2120     } else
2121         return NO;
2122 }
2123
2124 bool FrameMac::sendContextMenuEvent(NSEvent *event)
2125 {
2126     Document* doc = d->m_doc.get();
2127     FrameView* v = d->m_view.get();
2128     if (!doc || !v)
2129         return false;
2130
2131     bool swallowEvent;
2132     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2133
2134     NSEvent *oldCurrentEvent = _currentEvent;
2135     _currentEvent = KWQRetain(event);
2136     
2137     PlatformMouseEvent mouseEvent(event);
2138
2139     IntPoint viewportPos = v->viewportToContents(mouseEvent.pos());
2140     MouseEventWithHitTestResults mev = doc->prepareMouseEvent(false, true, false, viewportPos, mouseEvent);
2141
2142     swallowEvent = v->dispatchMouseEvent(contextmenuEvent, mev.targetNode(), true, 0, mouseEvent, true);
2143     if (!swallowEvent && !isPointInsideSelection(viewportPos) &&
2144         ([_bridge selectWordBeforeMenuEvent] || [_bridge isEditable] || mev.targetNode()->isContentEditable())) {
2145         _mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2146         selectClosestWordFromMouseEvent(mouseEvent, mev.targetNode());
2147     }
2148
2149     ASSERT(_currentEvent == event);
2150     KWQRelease(event);
2151     _currentEvent = oldCurrentEvent;
2152
2153     return swallowEvent;
2154
2155     END_BLOCK_OBJC_EXCEPTIONS;
2156
2157     return false;
2158 }
2159
2160 struct ListItemInfo {
2161     unsigned start;
2162     unsigned end;
2163 };
2164
2165 NSFileWrapper *FrameMac::fileWrapperForElement(Element *e)
2166 {
2167     NSFileWrapper *wrapper = nil;
2168     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2169     
2170     const AtomicString& attr = e->getAttribute(srcAttr);
2171     if (!attr.isEmpty()) {
2172         NSURL *URL = completeURL(attr.deprecatedString()).getNSURL();
2173         wrapper = [_bridge fileWrapperForURL:URL];
2174     }    
2175     if (!wrapper) {
2176         RenderImage *renderer = static_cast<RenderImage *>(e->renderer());
2177         if (renderer->cachedImage() && !renderer->cachedImage()->isErrorImage()) {
2178             wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:(NSData*)(renderer->cachedImage()->image()->getTIFFRepresentation())];
2179             [wrapper setPreferredFilename:@"image.tiff"];
2180             [wrapper autorelease];
2181         }
2182     }
2183
2184     return wrapper;
2185
2186     END_BLOCK_OBJC_EXCEPTIONS;
2187
2188     return nil;
2189 }
2190
2191 static Element *listParent(Element *item)
2192 {
2193     while (!item->hasTagName(ulTag) && !item->hasTagName(olTag)) {
2194         item = static_cast<Element *>(item->parentNode());
2195         if (!item)
2196             break;
2197     }
2198     return item;
2199 }
2200
2201 static Node* isTextFirstInListItem(Node *e)
2202 {
2203     if (!e->isTextNode())
2204         return 0;
2205     Node* par = e->parentNode();
2206     while (par) {
2207         if (par->firstChild() != e)
2208             return 0;
2209         if (par->hasTagName(liTag))
2210             return par;
2211         e = par;
2212         par = par->parentNode();
2213     }
2214     return 0;
2215 }
2216
2217 // FIXME: This collosal function needs to be refactored into maintainable smaller bits.
2218
2219 #define BULLET_CHAR 0x2022
2220 #define SQUARE_CHAR 0x25AA
2221 #define CIRCLE_CHAR 0x25E6
2222
2223 NSAttributedString *FrameMac::attributedString(Node *_start, int startOffset, Node *endNode, int endOffset)
2224 {
2225     ListItemInfo info;
2226     NSMutableAttributedString *result;
2227     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2228
2229     Node * _startNode = _start;
2230
2231     if (!_startNode)
2232         return nil;
2233
2234     result = [[[NSMutableAttributedString alloc] init] autorelease];
2235
2236     bool hasNewLine = true;
2237     bool addedSpace = true;
2238     NSAttributedString *pendingStyledSpace = nil;
2239     bool hasParagraphBreak = true;
2240     const Element *linkStartNode = 0;
2241     unsigned linkStartLocation = 0;
2242     DeprecatedPtrList<Element> listItems;
2243     DeprecatedValueList<ListItemInfo> listItemLocations;
2244     float maxMarkerWidth = 0;
2245     
2246     Node *n = _startNode;
2247     
2248     // If the first item is the entire text of a list item, use the list item node as the start of the 
2249     // selection, not the text node.  The user's intent was probably to select the list.
2250     if (n->isTextNode() && startOffset == 0) {
2251         Node *startListNode = isTextFirstInListItem(_startNode);
2252         if (startListNode){
2253             _startNode = startListNode;
2254             n = _startNode;
2255         }
2256     }
2257     
2258     while (n) {
2259         RenderObject *renderer = n->renderer();
2260         if (renderer) {
2261             RenderStyle *style = renderer->style();
2262             NSFont *font = style->font().getNSFont();
2263             bool needSpace = pendingStyledSpace != nil;
2264             if (n->isTextNode()) {
2265                 if (hasNewLine) {
2266                     addedSpace = true;
2267                     needSpace = false;
2268                     [pendingStyledSpace release];
2269                     pendingStyledSpace = nil;
2270                     hasNewLine = false;
2271                 }
2272                 DeprecatedString text;
2273                 DeprecatedString str = n->nodeValue().deprecatedString();
2274                 int start = (n == _startNode) ? startOffset : -1;
2275                 int end = (n == endNode) ? endOffset : -1;
2276                 if (renderer->isText()) {
2277                     if (!style->collapseWhiteSpace()) {
2278                         if (needSpace && !addedSpace) {
2279                             if (text.isEmpty() && linkStartLocation == [result length])
2280                                 ++linkStartLocation;
2281                             [result appendAttributedString:pendingStyledSpace];
2282                         }
2283                         int runStart = (start == -1) ? 0 : start;
2284                         int runEnd = (end == -1) ? str.length() : end;
2285                         text += str.mid(runStart, runEnd-runStart);
2286                         [pendingStyledSpace release];
2287                         pendingStyledSpace = nil;
2288                         addedSpace = u_charDirection(str[runEnd - 1].unicode()) == U_WHITE_SPACE_NEUTRAL;
2289                     }
2290                     else {
2291                         RenderText* textObj = static_cast<RenderText*>(renderer);
2292                         if (!textObj->firstTextBox() && str.length() > 0 && !addedSpace) {
2293                             // We have no runs, but we do have a length.  This means we must be
2294                             // whitespace that collapsed away at the end of a line.
2295                             text += ' ';
2296                             addedSpace = true;
2297                         }
2298                         else {
2299                             addedSpace = false;
2300                             for (InlineTextBox* box = textObj->firstTextBox(); box; box = box->nextTextBox()) {
2301                                 int runStart = (start == -1) ? box->m_start : start;
2302                                 int runEnd = (end == -1) ? box->m_start + box->m_len : end;
2303                                 runEnd = min(runEnd, box->m_start + box->m_len);
2304                                 if (runStart >= box->m_start &&
2305                                     runStart < box->m_start + box->m_len) {
2306                                     if (box == textObj->firstTextBox() && box->m_start == runStart && runStart > 0)
2307                                         needSpace = true; // collapsed space at the start
2308                                     if (needSpace && !addedSpace) {
2309                                         if (pendingStyledSpace != nil) {
2310                                             if (text.isEmpty() && linkStartLocation == [result length])
2311                                                 ++linkStartLocation;
2312                                             [result appendAttributedString:pendingStyledSpace];
2313                                         } else
2314                                             text += ' ';
2315                                     }
2316                                     DeprecatedString runText = str.mid(runStart, runEnd - runStart);
2317                                     runText.replace('\n', ' ');
2318                                     text += runText;
2319                                     int nextRunStart = box->nextTextBox() ? box->nextTextBox()->m_start : str.length(); // collapsed space between runs or at the end
2320                                     needSpace = nextRunStart > runEnd;
2321                                     [pendingStyledSpace release];
2322                                     pendingStyledSpace = nil;
2323                                     addedSpace = u_charDirection(str[runEnd - 1].unicode()) == U_WHITE_SPACE_NEUTRAL;
2324                                     start = -1;
2325                                 }
2326                                 if (end != -1 && runEnd >= end)
2327                                     break;
2328                             }
2329                         }
2330                     }
2331                 }
2332                 
2333                 text.replace('\\', renderer->backslashAsCurrencySymbol());
2334     
2335                 if (text.length() > 0 || needSpace) {
2336                     NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
2337                     [attrs setObject:font forKey:NSFontAttributeName];
2338                     if (style && style->color().isValid() && style->color().alpha() != 0)
2339                         [attrs setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
2340                     if (style && style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
2341                         [attrs setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
2342
2343                     if (text.length() > 0) {
2344                         hasParagraphBreak = false;
2345                         NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString() attributes:attrs];
2346                         [result appendAttributedString: partialString];                
2347                         [partialString release];
2348                     }
2349
2350                     if (needSpace) {
2351                         [pendingStyledSpace release];
2352                         pendingStyledSpace = [[NSAttributedString alloc] initWithString:@" " attributes:attrs];
2353                     }
2354
2355                     [attrs release];
2356                 }
2357             } else {
2358                 // This is our simple HTML -> ASCII transformation:
2359                 DeprecatedString text;
2360                 if (n->hasTagName(aTag)) {
2361                     // Note the start of the <a> element.  We will add the NSLinkAttributeName
2362                     // attribute to the attributed string when navigating to the next sibling 
2363                     // of this node.
2364                     linkStartLocation = [result length];
2365                     linkStartNode = static_cast<Element*>(n);
2366                 } else if (n->hasTagName(brTag)) {
2367                     text += "\n";
2368                     hasNewLine = true;
2369                 } else if (n->hasTagName(liTag)) {
2370                     DeprecatedString listText;
2371                     Element *itemParent = listParent(static_cast<Element *>(n));
2372                     
2373                     if (!hasNewLine)
2374                         listText += '\n';
2375                     hasNewLine = true;
2376
2377                     listItems.append(static_cast<Element*>(n));
2378                     info.start = [result length];
2379                     info.end = 0;
2380                     listItemLocations.append (info);
2381                     
2382                     listText += '\t';
2383                     if (itemParent && renderer->isListItem()) {
2384                         RenderListItem *listRenderer = static_cast<RenderListItem*>(renderer);
2385
2386                         maxMarkerWidth = MAX([font pointSize], maxMarkerWidth);
2387                         switch(style->listStyleType()) {
2388                             case DISC:
2389                                 listText += ((QChar)BULLET_CHAR);
2390                                 break;
2391                             case CIRCLE:
2392                                 listText += ((QChar)CIRCLE_CHAR);
2393                                 break;
2394                             case SQUARE:
2395                                 listText += ((QChar)SQUARE_CHAR);
2396                                 break;
2397                             case LNONE:
2398                                 break;
2399                             default:
2400                                 DeprecatedString marker = listRenderer->markerStringValue();
2401                                 listText += marker;
2402                                 // Use AppKit metrics.  Will be rendered by AppKit.
2403                                 float markerWidth = [marker.getNSString() sizeWithAttributes:[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]].width;
2404                                 maxMarkerWidth = MAX(markerWidth, maxMarkerWidth);
2405                         }
2406
2407                         listText += ' ';
2408                         listText += '\t';
2409
2410                         NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
2411                         [attrs setObject:font forKey:NSFontAttributeName];
2412                         if (style && style->color().isValid())
2413                             [attrs setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
2414                         if (style && style->backgroundColor().isValid())
2415                             [attrs setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
2416
2417                         NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:listText.getNSString() attributes:attrs];
2418                         [attrs release];
2419                         [result appendAttributedString: partialString];                
2420                         [partialString release];
2421                     }
2422                 } else if (n->hasTagName(olTag) || n->hasTagName(ulTag)) {
2423                     if (!hasNewLine)
2424                         text += "\n";
2425                     hasNewLine = true;
2426                 } else if (n->hasTagName(blockquoteTag)
2427                         || n->hasTagName(ddTag)
2428                         || n->hasTagName(divTag)
2429                         || n->hasTagName(dlTag)
2430                         || n->hasTagName(dtTag)
2431                         || n->hasTagName(hrTag)
2432                         || n->hasTagName(listingTag)
2433                         || n->hasTagName(preTag)
2434                         || n->hasTagName(tdTag)
2435                         || n->hasTagName(thTag)) {
2436                     if (!hasNewLine)
2437                         text += '\n';
2438                     hasNewLine = true;
2439                 } else if (n->hasTagName(h1Tag)
2440                         || n->hasTagName(h2Tag)
2441                         || n->hasTagName(h3Tag)
2442                         || n->hasTagName(h4Tag)
2443                         || n->hasTagName(h5Tag)
2444                         || n->hasTagName(h6Tag)
2445                         || n->hasTagName(pTag)
2446                         || n->hasTagName(trTag)) {
2447                     if (!hasNewLine)
2448                         text += '\n';
2449                     
2450                     // In certain cases, emit a paragraph break.
2451                     int bottomMargin = renderer->collapsedMarginBottom();
2452                     int fontSize = style->fontDescription().computedPixelSize();
2453                     if (bottomMargin * 2 >= fontSize) {
2454                         if (!hasParagraphBreak) {
2455                             text += '\n';
2456                             hasParagraphBreak = true;
2457                         }
2458                     }
2459                     
2460                     hasNewLine = true;
2461                 }
2462                 else if (n->hasTagName(imgTag)) {
2463                     if (pendingStyledSpace != nil) {
2464                         if (linkStartLocation == [result length])
2465                             ++linkStartLocation;
2466                         [result appendAttributedString:pendingStyledSpace];
2467                         [pendingStyledSpace release];
2468                         pendingStyledSpace = nil;
2469                     }
2470                     NSFileWrapper *fileWrapper = fileWrapperForElement(static_cast<Element *>(n));
2471                     NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
2472                     NSAttributedString *iString = [NSAttributedString attributedStringWithAttachment:attachment];
2473                     [result appendAttributedString: iString];
2474                     [attachment release];
2475                 }
2476
2477                 NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2478                 [result appendAttributedString: partialString];
2479                 [partialString release];
2480             }
2481         }
2482
2483         if (n == endNode)
2484             break;
2485
2486         Node *next = n->firstChild();
2487         if (!next)
2488             next = n->nextSibling();
2489
2490         while (!next && n->parentNode()) {
2491             DeprecatedString text;
2492             n = n->parentNode();
2493             if (n == endNode)
2494                 break;
2495             next = n->nextSibling();
2496
2497             if (n->hasTagName(aTag)) {
2498                 // End of a <a> element.  Create an attributed string NSLinkAttributeName attribute
2499                 // for the range of the link.  Note that we create the attributed string from the DOM, which
2500                 // will have corrected any illegally nested <a> elements.
2501                 if (linkStartNode && n == linkStartNode) {
2502                     String href = parseURL(linkStartNode->getAttribute(hrefAttr));
2503                     KURL kURL = Mac(linkStartNode->document()->frame())->completeURL(href.deprecatedString());
2504                     
2505                     NSURL *URL = kURL.getNSURL();
2506                     NSRange tempRange = { linkStartLocation, [result length]-linkStartLocation }; // workaround for 4213314
2507                     [result addAttribute:NSLinkAttributeName value:URL range:tempRange];
2508                     linkStartNode = 0;
2509                 }
2510             }
2511             else if (n->hasTagName(olTag) || n->hasTagName(ulTag)) {
2512                 if (!hasNewLine)
2513                     text += '\n';
2514                 hasNewLine = true;
2515             } else if (n->hasTagName(liTag)) {
2516                 
2517                 int i, count = listItems.count();
2518                 for (i = 0; i < count; i++){
2519                     if (listItems.at(i) == n){
2520                         listItemLocations[i].end = [result length];
2521                         break;
2522                     }
2523                 }
2524                 if (!hasNewLine)
2525                     text += '\n';
2526                 hasNewLine = true;
2527             } else if (n->hasTagName(blockquoteTag) ||
2528                        n->hasTagName(ddTag) ||
2529                        n->hasTagName(divTag) ||
2530                        n->hasTagName(dlTag) ||
2531                        n->hasTagName(dtTag) ||
2532                        n->hasTagName(hrTag) ||
2533                        n->hasTagName(listingTag) ||
2534                        n->hasTagName(preTag) ||
2535                        n->hasTagName(tdTag) ||
2536                        n->hasTagName(thTag)) {
2537                 if (!hasNewLine)
2538                     text += '\n';
2539                 hasNewLine = true;
2540             } else if (n->hasTagName(pTag) ||
2541                        n->hasTagName(trTag) ||
2542                        n->hasTagName(h1Tag) ||
2543                        n->hasTagName(h2Tag) ||
2544                        n->hasTagName(h3Tag) ||
2545                        n->hasTagName(h4Tag) ||
2546                        n->hasTagName(h5Tag) ||
2547                        n->hasTagName(h6Tag)) {
2548                 if (!hasNewLine)
2549                     text += '\n';
2550                 // An extra newline is needed at the start, not the end, of these types of tags,
2551                 // so don't add another here.
2552                 hasNewLine = true;
2553             }
2554             
2555             NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2556             [result appendAttributedString:partialString];
2557             [partialString release];
2558         }
2559
2560         n = next;
2561     }
2562     
2563     [pendingStyledSpace release];
2564     
2565     // Apply paragraph styles from outside in.  This ensures that nested lists correctly
2566     // override their parent's paragraph style.
2567     {
2568         unsigned i, count = listItems.count();
2569         Element *e;
2570
2571 #ifdef POSITION_LIST
2572         Node *containingBlock;
2573         int containingBlockX, containingBlockY;
2574         
2575         // Determine the position of the outermost containing block.  All paragraph
2576         // styles and tabs should be relative to this position.  So, the horizontal position of 
2577         // each item in the list (in the resulting attributed string) will be relative to position 
2578         // of the outermost containing block.
2579         if (count > 0){
2580             containingBlock = _startNode;
2581             while (containingBlock->renderer()->isInline()){
2582                 containingBlock = containingBlock->parentNode();
2583             }
2584             containingBlock->renderer()->absolutePosition(containingBlockX, containingBlockY);
2585         }
2586 #endif
2587         
2588         for (i = 0; i < count; i++){
2589             e = listItems.at(i);
2590             info = listItemLocations[i];
2591             
2592             if (info.end < info.start)
2593                 info.end = [result length];
2594                 
2595             RenderObject *r = e->renderer();
2596             RenderStyle *style = r->style();
2597
2598             int rx;
2599             NSFont *font = style->font().getNSFont();
2600             float pointSize = [font pointSize];
2601
2602 #ifdef POSITION_LIST
2603             int ry;
2604             r->absolutePosition(rx, ry);
2605             rx -= containingBlockX;
2606             
2607             // Ensure that the text is indented at least enough to allow for the markers.
2608             rx = MAX(rx, (int)maxMarkerWidth);
2609 #else
2610             rx = (int)MAX(maxMarkerWidth, pointSize);
2611 #endif
2612
2613             // The bullet text will be right aligned at the first tab marker, followed
2614             // by a space, followed by the list item text.  The space is arbitrarily
2615             // picked as pointSize*2/3.  The space on the first line of the text item
2616             // is established by a left aligned tab, on subsequent lines it's established
2617             // by the head indent.
2618             NSMutableParagraphStyle *mps = [[NSMutableParagraphStyle alloc] init];
2619             [mps setFirstLineHeadIndent: 0];
2620             [mps setHeadIndent: rx];
2621             [mps setTabStops:[NSArray arrayWithObjects:
2622                         [[[NSTextTab alloc] initWithType:NSRightTabStopType location:rx-(pointSize*2/3)] autorelease],
2623                         [[[NSTextTab alloc] initWithType:NSLeftTabStopType location:rx] autorelease],
2624                         nil]];
2625             NSRange tempRange = { info.start, info.end-info.start }; // workaround for 4213314
2626             [result addAttribute:NSParagraphStyleAttributeName value:mps range:tempRange];
2627             [mps release];
2628         }
2629     }
2630
2631     return result;
2632
2633     END_BLOCK_OBJC_EXCEPTIONS;
2634
2635     return nil;
2636 }
2637
2638 NSImage *FrameMac::imageFromRect(NSRect rect) const
2639 {
2640     NSView *view = d->m_view->getDocumentView();
2641     if (!view)
2642         return nil;
2643     
2644     NSImage *resultImage;
2645     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2646     
2647     NSRect bounds = [view bounds];
2648     resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
2649
2650     if (rect.size.width != 0 && rect.size.height != 0) {
2651         [resultImage setFlipped:YES];
2652         [resultImage lockFocus];
2653
2654         CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
2655
2656         CGContextSaveGState(context);
2657         CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
2658         [view drawRect:rect];
2659         CGContextRestoreGState(context);
2660
2661         [resultImage unlockFocus];
2662         [resultImage setFlipped:NO];
2663     }
2664
2665     return resultImage;
2666
2667     END_BLOCK_OBJC_EXCEPTIONS;
2668     
2669     return nil;
2670 }
2671
2672 NSImage *FrameMac::selectionImage() const
2673 {
2674     d->m_drawSelectionOnly = true;  // invoke special drawing mode
2675     NSImage *result = imageFromRect(visibleSelectionRect());
2676     d->m_drawSelectionOnly = false;
2677     return result;
2678 }
2679
2680 NSImage *FrameMac::snapshotDragImage(Node *node, NSRect *imageRect, NSRect *elementRect) const
2681 {
2682     RenderObject *renderer = node->renderer();
2683     if (!renderer)
2684         return nil;
2685     
2686     renderer->updateDragState(true);    // mark dragged nodes (so they pick up the right CSS)
2687     d->m_doc->updateLayout();        // forces style recalc - needed since changing the drag state might
2688                                         // imply new styles, plus JS could have changed other things
2689     IntRect topLevelRect;
2690     NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
2691
2692     d->m_elementToDraw = node;              // invoke special sub-tree drawing mode
2693     NSImage *result = imageFromRect(paintingRect);
2694     renderer->updateDragState(false);
2695     d->m_doc->updateLayout();
2696     d->m_elementToDraw = 0;
2697
2698     if (elementRect)
2699         *elementRect = topLevelRect;
2700     if (imageRect)
2701         *imageRect = paintingRect;
2702     return result;
2703 }
2704
2705 NSFont *FrameMac::fontForSelection(bool *hasMultipleFonts) const
2706 {
2707     if (hasMultipleFonts)
2708         *hasMultipleFonts = false;
2709
2710     if (!d->m_selection.isRange()) {
2711         Node *nodeToRemove;
2712         RenderStyle *style = styleForSelectionStart(nodeToRemove); // sets nodeToRemove
2713
2714         NSFont *result = 0;
2715         if (style)
2716             result = style->font().getNSFont();
2717         
2718         if (nodeToRemove) {
2719             ExceptionCode ec;
2720             nodeToRemove->remove(ec);
2721             ASSERT(ec == 0);
2722         }
2723
2724         return result;
2725     }
2726
2727     NSFont *font = nil;
2728
2729     RefPtr<Range> range = d->m_selection.toRange();
2730     Node *startNode = range->editingStartPosition().node();
2731     if (startNode != nil) {
2732         Node *pastEnd = range->pastEndNode();
2733         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
2734         // unreproducible case where this didn't happen, so check for nil also.
2735         for (Node *n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
2736             RenderObject *renderer = n->renderer();
2737             if (!renderer)
2738                 continue;
2739             // FIXME: Are there any node types that have renderers, but that we should be skipping?
2740             NSFont *f = renderer->style()->font().getNSFont();
2741             if (!font) {
2742                 font = f;
2743                 if (!hasMultipleFonts)
2744                     break;
2745             } else if (font != f) {
2746                 *hasMultipleFonts = true;
2747                 break;
2748             }
2749         }
2750     }
2751
2752     return font;
2753 }
2754
2755 NSDictionary *FrameMac::fontAttributesForSelectionStart() const
2756 {
2757     Node *nodeToRemove;
2758     RenderStyle *style = styleForSelectionStart(nodeToRemove);
2759     if (!style)
2760         return nil;
2761
2762     NSMutableDictionary *result = [NSMutableDictionary dictionary];
2763
2764     if (style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
2765         [result setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
2766
2767     if (style->font().getNSFont())
2768         [result setObject:style->font().getNSFont() forKey:NSFontAttributeName];
2769
2770     if (style->color().isValid() && style->color() != Color::black)
2771         [result setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
2772
2773     ShadowData *shadow = style->textShadow();
2774     if (shadow) {
2775         NSShadow *s = [[NSShadow alloc] init];
2776         [s setShadowOffset:NSMakeSize(shadow->x, shadow->y)];
2777         [s setShadowBlurRadius:shadow->blur];
2778         [s setShadowColor:nsColor(shadow->color)];
2779         [result setObject:s forKey:NSShadowAttributeName];
2780     }
2781
2782     int decoration = style->textDecorationsInEffect();
2783     if (decoration & LINE_THROUGH)
2784         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
2785
2786     int superscriptInt = 0;
2787     switch (style->verticalAlign()) {
2788         case BASELINE:
2789         case BOTTOM:
2790         case BASELINE_MIDDLE:
2791         case LENGTH:
2792         case MIDDLE:
2793         case TEXT_BOTTOM:
2794         case TEXT_TOP:
2795         case TOP:
2796             break;
2797         case SUB:
2798             superscriptInt = -1;
2799             break;
2800         case SUPER:
2801             superscriptInt = 1;
2802             break;
2803     }
2804     if (superscriptInt)
2805         [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];
2806
2807     if (decoration & UNDERLINE)
2808         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
2809
2810     if (nodeToRemove) {
2811         ExceptionCode ec = 0;
2812         nodeToRemove->remove(ec);
2813         ASSERT(ec == 0);
2814     }
2815
2816     return result;
2817 }
2818
2819 NSWritingDirection FrameMac::baseWritingDirectionForSelectionStart() const
2820 {
2821     NSWritingDirection result = NSWritingDirectionLeftToRight;
2822
2823     Position pos = VisiblePosition(d->m_selection.start(), d->m_selection.affinity()).deepEquivalent();
2824     Node *node = pos.node();
2825     if (!node || !node->renderer() || !node->renderer()->containingBlock())
2826         return result;
2827     RenderStyle *style = node->renderer()->containingBlock()->style();
2828     if (!style)
2829         return result;
2830         
2831     switch (style->direction()) {
2832         case LTR:
2833             result = NSWritingDirectionLeftToRight;
2834             break;
2835         case RTL:
2836             result = NSWritingDirectionRightToLeft;
2837             break;
2838     }
2839
2840     return result;
2841 }
2842
2843 void FrameMac::tokenizerProcessedData()
2844 {
2845     if (d->m_doc)
2846         checkCompleted();
2847     [_bridge tokenizerProcessedData];
2848 }
2849
2850 void FrameMac::setBridge(WebCoreFrameBridge *bridge)
2851
2852     if (_bridge == bridge)
2853         return;
2854
2855     KWQRetain(bridge);
2856     KWQRelease(_bridge);
2857     _bridge = bridge;
2858 }
2859
2860 String FrameMac::overrideMediaType() const
2861 {
2862     NSString *overrideType = [_bridge overrideMediaType];
2863     if (overrideType)
2864         return overrideType;
2865     return String();
2866 }
2867
2868 void FrameMac::setDisplaysWithFocusAttributes(bool flag)
2869 {
2870     if (d->m_isFocused == flag)
2871         return;
2872     
2873     Frame::setDisplaysWithFocusAttributes(flag);
2874     Document *doc = document();
2875     // Mac Specific: Changing the tint of controls from clear to aqua/graphite and vice versa.  We
2876     // do a "fake" paint.  When the theme gets a paint call, it can then do an invalidate.
2877     if (doc && d->m_view && d->m_view->getDocumentView() && theme()->supportsControlTints() && renderer()) {
2878         doc->updateLayout(); // Ensure layout is up to date.
2879         IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
2880         GraphicsContext context(0);
2881         context.setUpdatingControlTints(true);
2882         paint(&context, visibleRect);
2883     }
2884 }
2885
2886 NSColor *FrameMac::bodyBackgroundColor() const
2887 {
2888     if (document() && document()->body() && document()->body()->renderer()) {
2889         Color bgColor = document()->body()->renderer()->style()->backgroundColor();
2890         if (bgColor.isValid())
2891             return nsColor(bgColor);
2892     }
2893     return nil;
2894 }
2895
2896 WebCoreKeyboardUIMode FrameMac::keyboardUIMode() const
2897 {
2898     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2899     return [_bridge keyboardUIMode];
2900     END_BLOCK_OBJC_EXCEPTIONS;
2901
2902     return WebCoreKeyboardAccessDefault;
2903 }
2904
2905 void FrameMac::didTellBridgeAboutLoad(const String& URL)
2906 {
2907     urlsBridgeKnowsAbout.add(URL.impl());
2908 }
2909
2910 bool FrameMac::haveToldBridgeAboutLoad(const String& URL)
2911 {
2912     return urlsBridgeKnowsAbout.contains(URL.impl());
2913 }
2914
2915 void FrameMac::clear()
2916 {
2917     urlsBridgeKnowsAbout.clear();
2918     setMarkedTextRange(0, nil, nil);
2919     Frame::clear();
2920 }
2921
2922 void FrameMac::print()
2923 {
2924     [Mac(this)->_bridge print];
2925 }
2926
2927 KJS::Bindings::Instance *FrameMac::getAppletInstanceForWidget(Widget *widget)
2928 {
2929     NSView *aView = widget->getView();
2930     if (!aView)
2931         return 0;
2932     jobject applet;
2933     
2934     // Get a pointer to the actual Java applet instance.
2935     if ([_bridge respondsToSelector:@selector(getAppletInView:)])
2936         applet = [_bridge getAppletInView:aView];
2937     else
2938         applet = [_bridge pollForAppletInView:aView];
2939     
2940     if (applet) {
2941         // Wrap the Java instance in a language neutral binding and hand
2942         // off ownership to the APPLET element.
2943         KJS::Bindings::RootObject *executionContext = KJS::Bindings::RootObject::findRootObjectForNativeHandleFunction ()(aView);
2944         KJS::Bindings::Instance *instance = KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::JavaLanguage, applet, executionContext);        
2945         return instance;
2946     }
2947     
2948     return 0;
2949 }
2950
2951 static KJS::Bindings::Instance *getInstanceForView(NSView *aView)
2952 {
2953     if ([aView respondsToSelector:@selector(objectForWebScript)]){
2954         id object = [aView objectForWebScript];
2955         if (object) {
2956             KJS::Bindings::RootObject *executionContext = KJS::Bindings::RootObject::findRootObjectForNativeHandleFunction ()(aView);
2957             return KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::ObjectiveCLanguage, object, executionContext);
2958         }
2959     }
2960     else if ([aView respondsToSelector:@selector(pluginScriptableObject)]){
2961         void *object = [aView pluginScriptableObject];
2962         if (object) {
2963             KJS::Bindings::RootObject *executionContext = KJS::Bindings::RootObject::findRootObjectForNativeHandleFunction ()(aView);
2964             return KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::CLanguage, object, executionContext);
2965         }
2966     }
2967     return 0;
2968 }
2969
2970 KJS::Bindings::Instance *FrameMac::getEmbedInstanceForWidget(Widget *widget)
2971 {
2972     return getInstanceForView(widget->getView());
2973 }
2974
2975 KJS::Bindings::Instance *FrameMac::getObjectInstanceForWidget(Widget *widget)
2976 {
2977     return getInstanceForView(widget->getView());
2978 }
2979
2980 void FrameMac::addPluginRootObject(KJS::Bindings::RootObject *root)
2981 {
2982     m_rootObjects.append(root);
2983 }
2984
2985 void FrameMac::cleanupPluginRootObjects()
2986 {
2987     JSLock lock;
2988
2989     unsigned count = m_rootObjects.size();
2990     for (unsigned i = 0; i < count; i++)
2991         m_rootObjects[i]->removeAllNativeReferences();
2992     m_rootObjects.clear();
2993 }
2994
2995 void FrameMac::registerCommandForUndoOrRedo(const EditCommandPtr &cmd, bool isRedo)
2996 {
2997     ASSERT(cmd.get());
2998     KWQEditCommand *kwq = [KWQEditCommand commandWithEditCommand:cmd.get()];
2999     NSUndoManager *undoManager = [_bridge undoManager];
3000     [undoManager registerUndoWithTarget:_bridge selector:(isRedo ? @selector(redoEditing:) : @selector(undoEditing:)) object:kwq];
3001     NSString *actionName = [_bridge nameForUndoAction:static_cast<WebUndoAction>(cmd.editingAction())];
3002     if (actionName)
3003         [undoManager setActionName:actionName];
3004     _haveUndoRedoOperations = YES;
3005 }
3006
3007 void FrameMac::registerCommandForUndo(const EditCommandPtr &cmd)
3008 {
3009     registerCommandForUndoOrRedo(cmd, NO);
3010 }
3011
3012 void FrameMac::registerCommandForRedo(const EditCommandPtr &cmd)
3013 {
3014     registerCommandForUndoOrRedo(cmd, YES);
3015 }
3016
3017 void FrameMac::clearUndoRedoOperations()
3018 {
3019     if (_haveUndoRedoOperations) {
3020         [[_bridge undoManager] removeAllActionsWithTarget:_bridge];
3021         _haveUndoRedoOperations = NO;
3022     }
3023 }
3024
3025 void FrameMac::issueUndoCommand()
3026 {
3027     if (canUndo())
3028         [[_bridge undoManager] undo];
3029 }
3030
3031 void FrameMac::issueRedoCommand()
3032 {
3033     if (canRedo())
3034         [[_bridge undoManager] redo];
3035 }
3036
3037 void FrameMac::issueCutCommand()
3038 {
3039     [_bridge issueCutCommand];
3040 }
3041
3042 void FrameMac::issueCopyCommand()
3043 {
3044     [_bridge issueCopyCommand];
3045 }
3046
3047 void FrameMac::issuePasteCommand()
3048 {
3049     [_bridge issuePasteCommand];
3050 }
3051
3052 void FrameMac::issuePasteAndMatchStyleCommand()
3053 {
3054     [_bridge issuePasteAndMatchStyleCommand];
3055 }
3056
3057 void FrameMac::issueTransposeCommand()
3058 {
3059     [_bridge issueTransposeCommand];
3060 }
3061
3062 bool FrameMac::canUndo() const
3063 {
3064     return [[Mac(this)->_bridge undoManager] canUndo];
3065 }
3066
3067 bool FrameMac::canRedo() const
3068 {
3069     return [[Mac(this)->_bridge undoManager] canRedo];
3070 }
3071
3072 bool FrameMac::canPaste() const
3073 {
3074     return [Mac(this)->_bridge canPaste];
3075 }
3076
3077 void FrameMac::markMisspellingsInAdjacentWords(const VisiblePosition &p)
3078 {
3079     if (![_bridge isContinuousSpellCheckingEnabled])
3080         return;
3081     markMisspellings(SelectionController(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)));
3082 }
3083
3084 void FrameMac::markMisspellings(const SelectionController &selection)
3085 {
3086     // This function is called with a selection already expanded to word boundaries.
3087     // Might be nice to assert that here.
3088
3089     if (![_bridge isContinuousSpellCheckingEnabled])
3090         return;
3091
3092     RefPtr<Range> searchRange(selection.toRange());
3093     if (!searchRange || searchRange->isDetached())
3094         return;
3095     
3096     // If we're not in an editable node, bail.
3097     int exception = 0;
3098     Node *editableNode = searchRange->startContainer(exception);
3099     if (!editableNode->isContentEditable())
3100         return;
3101     
3102     // Get the spell checker if it is available
3103     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
3104     if (checker == nil)
3105         return;
3106     
3107     WordAwareIterator it(searchRange.get());
3108     
3109     while (!it.atEnd()) {      // we may be starting at the end of the doc, and already by atEnd
3110         const UChar* chars = it.characters();
3111         int len = it.length();
3112         if (len > 1 || !QChar(chars[0]).isSpace()) {
3113             NSString *chunk = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(chars) length:len freeWhenDone:NO];
3114             int startIndex = 0;
3115             // Loop over the chunk to find each misspelling in it.
3116             while (startIndex < len) {
3117                 NSRange misspelling = [checker checkSpellingOfString:chunk startingAt:startIndex language:nil wrap:NO inSpellDocumentWithTag:[_bridge spellCheckerDocumentTag] wordCount:NULL];
3118                 if (misspelling.length == 0)
3119                     break;
3120                 else {
3121                     // Build up result range and string.  Note the misspelling may span many text nodes,
3122                     // but the CharIterator insulates us from this complexity
3123                     RefPtr<Range> misspellingRange(rangeOfContents(document()));
3124                     CharacterIterator chars(it.range().get());
3125                     chars.advance(misspelling.location);
3126                     misspellingRange->setStart(chars.range()->startContainer(exception), chars.range()->startOffset(exception), exception);
3127                     chars.advance(misspelling.length);
3128                     misspellingRange->setEnd(chars.range()->startContainer(exception), chars.range()->startOffset(exception), exception);
3129                     // Mark misspelling in document.
3130                     document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
3131                     startIndex = misspelling.location + misspelling.length;
3132                 }
3133             }
3134             [chunk release];
3135         }
3136     
3137         it.advance();
3138     }
3139 }
3140
3141 void FrameMac::respondToChangedSelection(const SelectionController &oldSelection, bool closeTyping)
3142 {
3143     if (document()) {
3144         if ([_bridge isContinuousSpellCheckingEnabled]) {
3145             SelectionController oldAdjacentWords = SelectionController();
3146             
3147             // If this is a change in selection resulting from a delete operation, oldSelection may no longer
3148             // be in the document.
3149             if (oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
3150                 VisiblePosition oldStart(oldSelection.start(), oldSelection.affinity());
3151                 oldAdjacentWords = SelectionController(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));   
3152             }
3153
3154             VisiblePosition newStart(selection().start(), selection().affinity());
3155             SelectionController newAdjacentWords(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
3156
3157             if (oldAdjacentWords != newAdjacentWords) {
3158                 // Mark misspellings in the portion that was previously unmarked because of
3159                 // the proximity of the start of the selection. We only spell check words in
3160                 // the vicinity of the start of the old selection because the spelling checker
3161                 // is not fast enough to do a lot of spelling checking implicitly. This matches
3162                 // AppKit. This function is really the only code that knows that rule. The
3163                 // markMisspellings function is prepared to handler larger ranges.
3164
3165                 // When typing we check spelling elsewhere, so don't redo it here.
3166                 if (closeTyping)
3167                     markMisspellings(oldAdjacentWords);
3168
3169                 // This only erases a marker in the first word of the selection.
3170                 // Perhaps peculiar, but it matches AppKit.
3171                 document()->removeMarkers(newAdjacentWords.toRange().get(), DocumentMarker::Spelling);
3172             }
3173         } else
3174             // When continuous spell checking is off, no markers appear after the selection changes.
3175             document()->removeMarkers(DocumentMarker::Spelling);
3176     }
3177
3178     [_bridge respondToChangedSelection];
3179 }
3180
3181 bool FrameMac::shouldChangeSelection(const SelectionController &oldSelection, const SelectionController &newSelection, EAffinity affinity, bool stillSelecting) const
3182 {
3183     return [_bridge shouldChangeSelectedDOMRange:[DOMRange _rangeWith:oldSelection.toRange().get()]
3184                                       toDOMRange:[DOMRange _rangeWith:newSelection.toRange().get()]
3185                                         affinity:static_cast<NSSelectionAffinity>(affinity)
3186                                   stillSelecting:stillSelecting];
3187 }
3188
3189 void FrameMac::respondToChangedContents()
3190 {
3191     if (AccessibilityObjectCache::accessibilityEnabled())
3192         renderer()->document()->getAccObjectCache()->postNotificationToTopWebArea(renderer(), "AXValueChanged");
3193     [_bridge respondToChangedContents];
3194 }
3195
3196 bool FrameMac::isContentEditable() const
3197 {
3198     return Frame::isContentEditable() || [_bridge isEditable];
3199 }
3200
3201 bool FrameMac::shouldBeginEditing(const Range *range) const
3202 {
3203     ASSERT(range);
3204     return [_bridge shouldBeginEditing:[DOMRange _rangeWith:const_cast<Range *>(range)]];
3205 }
3206
3207 bool FrameMac::shouldEndEditing(const Range *range) const
3208 {
3209     ASSERT(range);
3210     return [_bridge shouldEndEditing:[DOMRange _rangeWith:const_cast<Range *>(range)]];
3211 }
3212
3213 void FrameMac::didBeginEditing() const
3214 {
3215     [_bridge didBeginEditing];
3216 }
3217
3218 void FrameMac::didEndEditing() const
3219 {
3220     [_bridge didEndEditing];
3221 }
3222
3223 void FrameMac::textFieldDidBeginEditing(Element* input)
3224 {
3225     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3226     [_bridge textFieldDidBeginEditing:(DOMHTMLInputElement *)[DOMElement _elementWith:input]];
3227     END_BLOCK_OBJC_EXCEPTIONS;
3228 }
3229
3230 void FrameMac::textFieldDidEndEditing(Element* input)
3231 {
3232     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3233     [_bridge textFieldDidEndEditing:(DOMHTMLInputElement *)[DOMElement _elementWith:input]];
3234     END_BLOCK_OBJC_EXCEPTIONS;
3235 }
3236
3237 void FrameMac::textDidChangeInTextField(Element* input)
3238 {
3239     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3240     [_bridge textDidChangeInTextField:(DOMHTMLInputElement *)[DOMElement _elementWith:input]];
3241     END_BLOCK_OBJC_EXCEPTIONS;
3242 }
3243
3244 bool FrameMac::doTextFieldCommandFromEvent(Element* input, const PlatformKeyboardEvent* event)
3245 {
3246     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3247     return [_bridge textField:(DOMHTMLInputElement *)[DOMElement _elementWith:input] doCommandBySelector:selectorForKeyEvent(event)];
3248     END_BLOCK_OBJC_EXCEPTIONS;
3249     return false;
3250 }
3251
3252 void FrameMac::textWillBeDeletedInTextField(Element* input)
3253 {
3254     // We're using the deleteBackward selector for all deletion operations since the autofill code treats all deletions the same way.
3255     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3256     [_bridge textField:(DOMHTMLInputElement *)[DOMElement _elementWith:input] doCommandBySelector:@selector(deleteBackward:)];
3257     END_BLOCK_OBJC_EXCEPTIONS;
3258 }
3259
3260 static DeprecatedValueList<MarkedTextUnderline> convertAttributesToUnderlines(const Range *markedTextRange, NSArray *attributes, NSArray *ranges)
3261 {
3262     DeprecatedValueList<MarkedTextUnderline> result;
3263
3264     int exception = 0;
3265     int baseOffset = markedTextRange->startOffset(exception);
3266
3267     unsigned length = [attributes count];
3268     ASSERT([ranges count] == length);
3269
3270     for (unsigned i = 0; i < length; i++) {
3271         NSNumber *style = [[attributes objectAtIndex:i] objectForKey:NSUnderlineStyleAttributeName];
3272         if (!style)
3273             continue;
3274         NSRange range = [[ranges objectAtIndex:i] rangeValue];
3275         NSColor *color = [[attributes objectAtIndex:i] objectForKey:NSUnderlineColorAttributeName];
3276         Color qColor = Color::black;
3277         if (color) {
3278             NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
3279             qColor = Color(makeRGBA((int)(255 * [deviceColor redComponent]),
3280                                     (int)(255 * [deviceColor blueComponent]),
3281                                     (int)(255 * [deviceColor greenComponent]),
3282                                     (int)(255 * [deviceColor alphaComponent])));
3283         }
3284
3285         result.append(MarkedTextUnderline(range.location + baseOffset, 
3286                                           range.location + baseOffset + range.length, 
3287                                           qColor,
3288                                           [style intValue] > 1));
3289     }
3290
3291     return result;
3292 }
3293
3294 void FrameMac::setMarkedTextRange(const Range *range, NSArray *attributes, NSArray *ranges)
3295 {
3296     int exception = 0;
3297
3298     ASSERT(!range || range->startContainer(exception) == range->endContainer(exception));
3299     ASSERT(!range || range->collapsed(exception) || range->startContainer(exception)->isTextNode());
3300
3301     if (attributes == nil) {
3302         d->m_markedTextUsesUnderlines = false;
3303         d->m_markedTextUnderlines.clear();
3304     } else {
3305         d->m_markedTextUsesUnderlines = true;
3306         d->m_markedTextUnderlines = convertAttributesToUnderlines(range, attributes, ranges);
3307     }
3308
3309     if (m_markedTextRange.get() && document() && m_markedTextRange->startContainer(exception)->renderer())
3310         m_markedTextRange->startContainer(exception)->renderer()->repaint();
3311
3312     if (range && range->collapsed(exception))
3313         m_markedTextRange = 0;
3314     else
3315         m_markedTextRange = const_cast<Range *>(range);
3316
3317     if (m_markedTextRange.get() && document() && m_markedTextRange->startContainer(exception)->renderer())
3318         m_markedTextRange->startContainer(exception)->renderer()->repaint();
3319 }
3320
3321 bool FrameMac::canGoBackOrForward(int distance) const
3322 {
3323     return [_bridge canGoBackOrForward:distance];
3324 }
3325
3326 void FrameMac::didFirstLayout()
3327 {
3328     [_bridge didFirstLayout];
3329 }
3330
3331 NSMutableDictionary *FrameMac::dashboardRegionsDictionary()
3332 {
3333     Document *doc = document();
3334     if (!doc)
3335         return nil;
3336
3337     const DeprecatedValueList<DashboardRegionValue> regions = doc->dashboardRegions();
3338     unsigned i, count = regions.count();
3339
3340     // Convert the DeprecatedValueList<DashboardRegionValue> into a NSDictionary of WebDashboardRegions
3341     NSMutableDictionary *webRegions = [[[NSMutableDictionary alloc] initWithCapacity:count] autorelease];
3342     for (i = 0; i < count; i++) {
3343         DashboardRegionValue region = regions[i];
3344
3345         if (region.type == StyleDashboardRegion::None)
3346             continue;
3347         
3348         NSString *label = region.label;
3349         WebDashboardRegionType type = WebDashboardRegionTypeNone;
3350         if (region.type == StyleDashboardRegion::Circle)
3351             type = WebDashboardRegionTypeCircle;
3352         else if (region.type == StyleDashboardRegion::Rectangle)
3353             type = WebDashboardRegionTypeRectangle;
3354         NSMutableArray *regionValues = [webRegions objectForKey:label];
3355         if (!regionValues) {
3356             regionValues = [NSMutableArray array];
3357             [webRegions setObject:regionValues forKey:label];
3358         }
3359         
3360         WebDashboardRegion *webRegion = [[[WebDashboardRegion alloc] initWithRect:region.bounds clip:region.clip type:type] autorelease];
3361         [regionValues addObject:webRegion];
3362     }
3363     
3364     return webRegions;
3365 }
3366
3367 void FrameMac::dashboardRegionsChanged()
3368 {
3369     NSMutableDictionary *webRegions = dashboardRegionsDictionary();
3370     [_bridge dashboardRegionsChanged:webRegions];
3371 }
3372
3373 bool FrameMac::isCharacterSmartReplaceExempt(const QChar &c, bool isPreviousChar)
3374 {
3375     return [_bridge isCharacterSmartReplaceExempt:c.unicode() isPreviousCharacter:isPreviousChar];
3376 }
3377
3378 void FrameMac::handledOnloadEvents()
3379 {
3380     [_bridge handledOnloadEvents];
3381 }
3382
3383 bool FrameMac::shouldClose()
3384 {
3385     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3386
3387     if (![_bridge canRunBeforeUnloadConfirmPanel])
3388         return true;
3389
3390     RefPtr<Document> doc = document();
3391     if (!doc)
3392         return true;
3393     HTMLElement* body = doc->body();
3394     if (!body)
3395         return true;
3396
3397     RefPtr<BeforeUnloadEvent> event = new BeforeUnloadEvent;
3398     event->setTarget(doc.get());
3399     doc->handleWindowEvent(event.get(), false);
3400
3401     if (!event->defaultPrevented() && doc)
3402         doc->defaultEventHandler(event.get());
3403     if (event->result().isNull())
3404         return true;
3405
3406     String text = event->result();
3407     text.replace('\\', backslashAsCurrencySymbol());
3408
3409     return [_bridge runBeforeUnloadConfirmPanelWithMessage:text];
3410
3411     END_BLOCK_OBJC_EXCEPTIONS;
3412
3413     return true;
3414 }
3415
3416 void FrameMac::dragSourceMovedTo(const PlatformMouseEvent& event)
3417 {
3418     if (_dragSrc && _dragSrcMayBeDHTML)
3419         // for now we don't care if event handler cancels default behavior, since there is none
3420         dispatchDragSrcEvent(dragEvent, event);
3421 }
3422
3423 void FrameMac::dragSourceEndedAt(const PlatformMouseEvent& event, NSDragOperation operation)
3424 {
3425     if (_dragSrc && _dragSrcMayBeDHTML) {
3426         _dragClipboard->setDestinationOperation(operation);
3427         // for now we don't care if event handler cancels default behavior, since there is none
3428         dispatchDragSrcEvent(dragendEvent, event);
3429     }
3430     freeClipboard();
3431     _dragSrc = 0;
3432 }
3433
3434 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3435 bool FrameMac::dispatchDragSrcEvent(const AtomicString &eventType, const PlatformMouseEvent& event) const
3436 {
3437     bool noDefaultProc = d->m_view->dispatchDragEvent(eventType, _dragSrc.get(), event, _dragClipboard.get());
3438     return !noDefaultProc;
3439 }
3440
3441 void Frame::setNeedsReapplyStyles()
3442 {
3443     [Mac(this)->bridge() setNeedsReapplyStyles];
3444 }
3445
3446 }