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