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