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