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