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