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