a0ff89a7e1f9776dea8d5a68608da719cf310a6d
[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 Widget* FrameMac::createJavaAppletWidget(const IntSize& size, Element* element, const HashMap<String, String>& args)
1087 {
1088     Widget* result = new Widget;
1089     
1090     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1091     
1092     NSMutableArray *attributeNames = [[NSMutableArray alloc] init];
1093     NSMutableArray *attributeValues = [[NSMutableArray alloc] init];
1094     
1095     DeprecatedString baseURLString;
1096     HashMap<String, String>::const_iterator end = args.end();
1097     for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
1098         if (it->first.lower() == "baseurl")
1099             baseURLString = it->second.deprecatedString();
1100         [attributeNames addObject:it->first];
1101         [attributeValues addObject:it->second];
1102     }
1103     
1104     if (baseURLString.isEmpty())
1105         baseURLString = document()->baseURL();
1106
1107     result->setView([_bridge viewForJavaAppletWithFrame:NSMakeRect(0, 0, size.width(), size.height())
1108                                          attributeNames:attributeNames
1109                                         attributeValues:attributeValues
1110                                                 baseURL:completeURL(baseURLString).getNSURL()
1111                                              DOMElement:[DOMElement _elementWith:element]]);
1112     [attributeNames release];
1113     [attributeValues release];
1114     view()->addChild(result);
1115     
1116     END_BLOCK_OBJC_EXCEPTIONS;
1117     
1118     return result;
1119 }
1120
1121 void FrameMac::partClearedInBegin()
1122 {
1123     if (jScriptEnabled())
1124         [_bridge windowObjectCleared];
1125 }
1126
1127 void FrameMac::openURLFromPageCache(WebCorePageState *state)
1128 {
1129     // It's safe to assume none of the WebCorePageState methods will raise
1130     // exceptions, since WebCorePageState is implemented by WebCore and
1131     // does not throw
1132
1133     Document *doc = [state document];
1134     Node *mousePressNode = [state mousePressNode];
1135     KURL *kurl = [state URL];
1136     SavedProperties *windowProperties = [state windowProperties];
1137     SavedProperties *locationProperties = [state locationProperties];
1138     SavedBuiltins *interpreterBuiltins = [state interpreterBuiltins];
1139     PausedTimeouts *timeouts = [state pausedTimeouts];
1140     
1141     cancelRedirection();
1142
1143     // We still have to close the previous part page.
1144     closeURL();
1145             
1146     d->m_bComplete = false;
1147     
1148     // Don't re-emit the load event.
1149     d->m_bLoadEventEmitted = true;
1150     
1151     // delete old status bar msg's from kjs (if it _was_ activated on last URL)
1152     if (jScriptEnabled()) {
1153         d->m_kjsStatusBarText = String();
1154         d->m_kjsDefaultStatusBarText = String();
1155     }
1156
1157     ASSERT(kurl);
1158     
1159     d->m_url = *kurl;
1160     
1161     // 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
1162     // data arrives) (Simon)
1163     if (url().protocol().startsWith("http") && !url().host().isEmpty() && url().path().isEmpty())
1164         d->m_url.setPath("/");
1165     
1166     // copy to m_workingURL after fixing url() above
1167     d->m_workingURL = url();
1168         
1169     started();
1170     
1171     // -----------begin-----------
1172     clear();
1173
1174     doc->setInPageCache(NO);
1175
1176     d->m_bCleared = false;
1177     d->m_bComplete = false;
1178     d->m_bLoadEventEmitted = false;
1179     d->m_referrer = url().url();
1180     
1181     setView(doc->view());
1182     
1183     d->m_doc = doc;
1184     d->m_mousePressNode = mousePressNode;
1185     d->m_decoder = doc->decoder();
1186
1187     updatePolicyBaseURL();
1188
1189     { // scope the lock
1190         JSLock lock;
1191         restoreWindowProperties(windowProperties);
1192         restoreLocationProperties(locationProperties);
1193         restoreInterpreterBuiltins(*interpreterBuiltins);
1194     }
1195
1196     resumeTimeouts(timeouts);
1197     
1198     checkCompleted();
1199 }
1200
1201 WebCoreFrameBridge *FrameMac::bridgeForWidget(const Widget *widget)
1202 {
1203     ASSERT_ARG(widget, widget);
1204     
1205     FrameMac *frame = Mac(frameForWidget(widget));
1206     ASSERT(frame);
1207     return frame->bridge();
1208 }
1209
1210 NSView *FrameMac::documentViewForNode(Node *node)
1211 {
1212     WebCoreFrameBridge *bridge = Mac(frameForNode(node))->bridge();
1213     return [bridge documentView];
1214 }
1215
1216 void FrameMac::saveDocumentState()
1217 {
1218     // Do not save doc state if the page has a password field and a form that would be submitted
1219     // via https
1220     if (!(d->m_doc && d->m_doc->hasPasswordField() && d->m_doc->hasSecureForm())) {
1221         BEGIN_BLOCK_OBJC_EXCEPTIONS;
1222         [_bridge saveDocumentState];
1223         END_BLOCK_OBJC_EXCEPTIONS;
1224     }
1225 }
1226
1227 void FrameMac::restoreDocumentState()
1228 {
1229     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1230     [_bridge restoreDocumentState];
1231     END_BLOCK_OBJC_EXCEPTIONS;
1232 }
1233
1234 String FrameMac::incomingReferrer() const
1235 {
1236     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1237     return [_bridge incomingReferrer];
1238     END_BLOCK_OBJC_EXCEPTIONS;
1239
1240     return String();
1241 }
1242
1243 void FrameMac::runJavaScriptAlert(const String& message)
1244 {
1245     String text = message;
1246     text.replace('\\', backslashAsCurrencySymbol());
1247     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1248     [_bridge runJavaScriptAlertPanelWithMessage:text];
1249     END_BLOCK_OBJC_EXCEPTIONS;
1250 }
1251
1252 bool FrameMac::runJavaScriptConfirm(const String& message)
1253 {
1254     String text = message;
1255     text.replace('\\', backslashAsCurrencySymbol());
1256
1257     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1258     return [_bridge runJavaScriptConfirmPanelWithMessage:text];
1259     END_BLOCK_OBJC_EXCEPTIONS;
1260
1261     return false;
1262 }
1263
1264 bool FrameMac::runJavaScriptPrompt(const String& prompt, const String& defaultValue, String& result)
1265 {
1266     String promptText = prompt;
1267     promptText.replace('\\', backslashAsCurrencySymbol());
1268     String defaultValueText = defaultValue;
1269     defaultValueText.replace('\\', backslashAsCurrencySymbol());
1270
1271     bool ok;
1272     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1273     NSString *returnedText = nil;
1274
1275     ok = [_bridge runJavaScriptTextInputPanelWithPrompt:prompt
1276         defaultText:defaultValue returningText:&returnedText];
1277
1278     if (ok) {
1279         result = String(returnedText);
1280         result.replace(backslashAsCurrencySymbol(), '\\');
1281     }
1282
1283     return ok;
1284     END_BLOCK_OBJC_EXCEPTIONS;
1285     
1286     return false;
1287 }
1288
1289 bool FrameMac::shouldInterruptJavaScript()
1290 {
1291     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1292     return [_bridge shouldInterruptJavaScript];
1293     END_BLOCK_OBJC_EXCEPTIONS;
1294     
1295     return false;
1296 }
1297
1298 bool FrameMac::locationbarVisible()
1299 {
1300     return [_bridge areToolbarsVisible];
1301 }
1302
1303 bool FrameMac::menubarVisible()
1304 {
1305     // The menubar is always on in Mac OS X UI
1306     return true;
1307 }
1308
1309 bool FrameMac::personalbarVisible()
1310 {
1311     return [_bridge areToolbarsVisible];
1312 }
1313
1314 bool FrameMac::statusbarVisible()
1315 {
1316     return [_bridge isStatusbarVisible];
1317 }
1318
1319 bool FrameMac::toolbarVisible()
1320 {
1321     return [_bridge areToolbarsVisible];
1322 }
1323
1324 void FrameMac::addMessageToConsole(const String &message, unsigned lineNumber, const String &sourceURL)
1325 {
1326     NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
1327         (NSString *)message, @"message",
1328         [NSNumber numberWithInt: lineNumber], @"lineNumber",
1329         (NSString *)sourceURL, @"sourceURL",
1330         NULL];
1331     [_bridge addMessageToConsole:dictionary];
1332 }
1333
1334 void FrameMac::createEmptyDocument()
1335 {
1336     // Although it's not completely clear from the name of this function,
1337     // it does nothing if we already have a document, and just creates an
1338     // empty one if we have no document at all.
1339     if (!d->m_doc) {
1340         BEGIN_BLOCK_OBJC_EXCEPTIONS;
1341         [_bridge loadEmptyDocumentSynchronously];
1342         END_BLOCK_OBJC_EXCEPTIONS;
1343
1344         updateBaseURLForEmptyDocument();
1345     }
1346 }
1347
1348 bool FrameMac::keyEvent(NSEvent *event)
1349 {
1350     bool result;
1351     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1352
1353     ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
1354
1355     // Check for cases where we are too early for events -- possible unmatched key up
1356     // from pressing return in the location bar.
1357     Document *doc = document();
1358     if (!doc) {
1359         return false;
1360     }
1361     Node *node = doc->focusNode();
1362     if (!node) {
1363         if (doc->isHTMLDocument())
1364             node = doc->body();
1365         else
1366             node = doc->documentElement();
1367         if (!node)
1368             return false;
1369     }
1370     
1371     if ([event type] == NSKeyDown) {
1372         prepareForUserAction();
1373     }
1374
1375     NSEvent *oldCurrentEvent = _currentEvent;
1376     _currentEvent = HardRetain(event);
1377
1378     PlatformKeyboardEvent qEvent(event);
1379     result = !EventTargetNodeCast(node)->dispatchKeyEvent(qEvent);
1380
1381     // We want to send both a down and a press for the initial key event.
1382     // To get KHTML to do this, we send a second KeyPress with "is repeat" set to true,
1383     // which causes it to send a press to the DOM.
1384     // That's not a great hack; it would be good to do this in a better way.
1385     if ([event type] == NSKeyDown && ![event isARepeat]) {
1386         PlatformKeyboardEvent repeatEvent(event, true);
1387         if (!EventTargetNodeCast(node)->dispatchKeyEvent(repeatEvent))
1388             result = true;
1389     }
1390
1391     ASSERT(_currentEvent == event);
1392     HardRelease(event);
1393     _currentEvent = oldCurrentEvent;
1394
1395     return result;
1396
1397     END_BLOCK_OBJC_EXCEPTIONS;
1398
1399     return false;
1400 }
1401
1402 void FrameMac::handleMousePressEvent(const MouseEventWithHitTestResults& event)
1403 {
1404     bool singleClick = [_currentEvent clickCount] <= 1;
1405
1406     // If we got the event back, that must mean it wasn't prevented,
1407     // so it's allowed to start a drag or selection.
1408     _mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode());
1409     
1410     // Careful that the drag starting logic stays in sync with eventMayStartDrag()
1411     _mouseDownMayStartDrag = singleClick;
1412
1413     d->m_mousePressNode = event.targetNode();
1414
1415     _mouseDownMayStartAutoscroll = d->m_mousePressNode && d->m_mousePressNode->renderer() && d->m_mousePressNode->renderer()->shouldAutoscroll();
1416     
1417     if (!passWidgetMouseDownEventToWidget(event)) {
1418         // We don't do this at the start of mouse down handling (before calling into WebCore),
1419         // because we don't want to do it until we know we didn't hit a widget.
1420         NSView *view = d->m_view->getDocumentView();
1421
1422         if (singleClick) {
1423             BEGIN_BLOCK_OBJC_EXCEPTIONS;
1424             if ([_bridge firstResponder] != view) {
1425                 [_bridge makeFirstResponder:view];
1426             }
1427             END_BLOCK_OBJC_EXCEPTIONS;
1428         }
1429
1430         Frame::handleMousePressEvent(event);
1431     }
1432 }
1433
1434 bool FrameMac::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
1435 {
1436     // Figure out which view to send the event to.
1437     RenderObject *target = event.targetNode() ? event.targetNode()->renderer() : 0;
1438     if (!target || !target->isWidget())
1439         return false;
1440     
1441     // Doubleclick events don't exist in Cocoa.  Since passWidgetMouseDownEventToWidget will
1442     // just pass _currentEvent down to the widget,  we don't want to call it for events that
1443     // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
1444     // part of the pressed/released handling.
1445     return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget());
1446 }
1447
1448 bool FrameMac::passWidgetMouseDownEventToWidget(RenderWidget *renderWidget)
1449 {
1450     return passMouseDownEventToWidget(renderWidget->widget());
1451 }
1452
1453 bool FrameMac::passMouseDownEventToWidget(Widget* widget)
1454 {
1455     // FIXME: this method always returns true
1456
1457     if (!widget) {
1458         LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
1459         return true;
1460     }
1461
1462     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1463     
1464     NSView *nodeView = widget->getView();
1465     ASSERT(nodeView);
1466     ASSERT([nodeView superview]);
1467     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[_currentEvent locationInWindow] fromView:nil]];
1468     if (view == nil) {
1469         LOG_ERROR("KHTML says we hit a RenderWidget, but AppKit doesn't agree we hit the corresponding NSView");
1470         return true;
1471     }
1472     
1473     if ([_bridge firstResponder] == view) {
1474         // In the case where we just became first responder, we should send the mouseDown:
1475         // to the NSTextField, not the NSTextField's editor. This code makes sure that happens.
1476         // If we don't do this, we see a flash of selected text when clicking in a text field.
1477         // FIXME: This is the only caller of textViewWasFirstResponderAtMouseDownTime. When we
1478         // eliminate all use of NSTextField/NSTextView in form fields we can eliminate this code,
1479         // and textViewWasFirstResponderAtMouseDownTime:, and the instance variable WebHTMLView
1480         // keeps solely to support textViewWasFirstResponderAtMouseDownTime:.
1481         if ([view isKindOfClass:[NSTextView class]] && ![_bridge textViewWasFirstResponderAtMouseDownTime:(NSTextView *)view]) {
1482             NSView *superview = view;
1483             while (superview != nodeView) {
1484                 superview = [superview superview];
1485                 ASSERT(superview);
1486                 if ([superview isKindOfClass:[NSControl class]]) {
1487                     NSControl *control = static_cast<NSControl*>(superview);
1488                     if ([control currentEditor] == view) {
1489                         view = superview;
1490                     }
1491                     break;
1492                 }
1493             }
1494         }
1495     } else {
1496         // Normally [NSWindow sendEvent:] handles setting the first responder.
1497         // But in our case, the event was sent to the view representing the entire web page.
1498         if ([_currentEvent clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) {
1499             [_bridge makeFirstResponder:view];
1500         }
1501     }
1502
1503     // We need to "defer loading" and defer timers while we are tracking the mouse.
1504     // That's because we don't want the new page to load while the user is holding the mouse down.
1505     
1506     BOOL wasDeferringLoading = [_bridge defersLoading];
1507     if (!wasDeferringLoading)
1508         [_bridge setDefersLoading:YES];
1509     BOOL wasDeferringTimers = isDeferringTimers();
1510     if (!wasDeferringTimers)
1511         setDeferringTimers(true);
1512
1513     ASSERT(!_sendingEventToSubview);
1514     _sendingEventToSubview = true;
1515     [view mouseDown:_currentEvent];
1516     _sendingEventToSubview = false;
1517     
1518     if (!wasDeferringTimers)
1519         setDeferringTimers(false);
1520     if (!wasDeferringLoading)
1521         [_bridge setDefersLoading:NO];
1522
1523     // Remember which view we sent the event to, so we can direct the release event properly.
1524     _mouseDownView = view;
1525     _mouseDownWasInSubframe = false;
1526
1527     END_BLOCK_OBJC_EXCEPTIONS;
1528
1529     return true;
1530 }
1531
1532 bool FrameMac::lastEventIsMouseUp() const
1533 {
1534     // Many AK widgets run their own event loops and consume events while the mouse is down.
1535     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
1536     // the khtml state with this mouseUp, which khtml never saw.  This method lets us detect
1537     // that state.
1538
1539     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1540     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
1541     if (_currentEvent != currentEventAfterHandlingMouseDown) {
1542         if ([currentEventAfterHandlingMouseDown type] == NSLeftMouseUp) {
1543             return true;
1544         }
1545     }
1546     END_BLOCK_OBJC_EXCEPTIONS;
1547
1548     return false;
1549 }
1550     
1551 // Note that this does the same kind of check as [target isDescendantOf:superview].
1552 // There are two differences: This is a lot slower because it has to walk the whole
1553 // tree, and this works in cases where the target has already been deallocated.
1554 static bool findViewInSubviews(NSView *superview, NSView *target)
1555 {
1556     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1557     NSEnumerator *e = [[superview subviews] objectEnumerator];
1558     NSView *subview;
1559     while ((subview = [e nextObject])) {
1560         if (subview == target || findViewInSubviews(subview, target)) {
1561             return true;
1562         }
1563     }
1564     END_BLOCK_OBJC_EXCEPTIONS;
1565     
1566     return false;
1567 }
1568
1569 NSView *FrameMac::mouseDownViewIfStillGood()
1570 {
1571     // Since we have no way of tracking the lifetime of _mouseDownView, we have to assume that
1572     // it could be deallocated already. We search for it in our subview tree; if we don't find
1573     // it, we set it to nil.
1574     NSView *mouseDownView = _mouseDownView;
1575     if (!mouseDownView) {
1576         return nil;
1577     }
1578     FrameView *topFrameView = d->m_view.get();
1579     NSView *topView = topFrameView ? topFrameView->getView() : nil;
1580     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
1581         _mouseDownView = nil;
1582         return nil;
1583     }
1584     return mouseDownView;
1585 }
1586
1587 bool FrameMac::eventMayStartDrag(NSEvent *event) const
1588 {
1589     // This is a pre-flight check of whether the event might lead to a drag being started.  Be careful
1590     // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we set
1591     // _mouseDownMayStartDrag in handleMousePressEvent
1592     
1593     if ([event type] != NSLeftMouseDown || [event clickCount] != 1) {
1594         return false;
1595     }
1596     
1597     BOOL DHTMLFlag, UAFlag;
1598     [_bridge allowDHTMLDrag:&DHTMLFlag UADrag:&UAFlag];
1599     if (!DHTMLFlag && !UAFlag) {
1600         return false;
1601     }
1602
1603     NSPoint loc = [event locationInWindow];
1604     IntPoint mouseDownPos = d->m_view->windowToContents(IntPoint(loc));
1605     RenderObject::NodeInfo nodeInfo(true, false);
1606     renderer()->layer()->hitTest(nodeInfo, mouseDownPos);
1607     bool srcIsDHTML;
1608     return nodeInfo.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, mouseDownPos.x(), mouseDownPos.y(), srcIsDHTML);
1609 }
1610
1611 // The link drag hysteresis is much larger than the others because there
1612 // needs to be enough space to cancel the link press without starting a link drag,
1613 // and because dragging links is rare.
1614 const float LinkDragHysteresis = 40.0;
1615 const float ImageDragHysteresis = 5.0;
1616 const float TextDragHysteresis = 3.0;
1617 const float GeneralDragHysteresis = 3.0;
1618 const float TextDragDelay = 0.15;
1619
1620 bool FrameMac::dragHysteresisExceeded(float dragLocationX, float dragLocationY) const
1621 {
1622     IntPoint dragViewportLocation((int)dragLocationX, (int)dragLocationY);
1623     IntPoint dragLocation = d->m_view->windowToContents(dragViewportLocation);
1624     IntSize delta = dragLocation - m_mouseDownPos;
1625     
1626     float threshold = GeneralDragHysteresis;
1627     if (_dragSrcIsImage)
1628         threshold = ImageDragHysteresis;
1629     else if (_dragSrcIsLink)
1630         threshold = LinkDragHysteresis;
1631     else if (_dragSrcInSelection)
1632         threshold = TextDragHysteresis;
1633
1634     return fabsf(delta.width()) >= threshold || fabsf(delta.height()) >= threshold;
1635 }
1636
1637 void FrameMac::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
1638 {
1639     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1640
1641     if ([_currentEvent type] == NSLeftMouseDragged) {
1642         NSView *view = mouseDownViewIfStillGood();
1643
1644         if (view) {
1645             _sendingEventToSubview = true;
1646             [view mouseDragged:_currentEvent];
1647             _sendingEventToSubview = false;
1648             return;
1649         }
1650
1651         // Careful that the drag starting logic stays in sync with eventMayStartDrag()
1652     
1653         if (_mouseDownMayStartDrag && !_dragSrc) {
1654             BOOL tempFlag1, tempFlag2;
1655             [_bridge allowDHTMLDrag:&tempFlag1 UADrag:&tempFlag2];
1656             _dragSrcMayBeDHTML = tempFlag1;
1657             _dragSrcMayBeUA = tempFlag2;
1658             if (!_dragSrcMayBeDHTML && !_dragSrcMayBeUA) {
1659                 _mouseDownMayStartDrag = false;     // no element is draggable
1660             }
1661         }
1662         
1663         if (_mouseDownMayStartDrag && !_dragSrc) {
1664             // try to find an element that wants to be dragged
1665             RenderObject::NodeInfo nodeInfo(true, false);
1666             renderer()->layer()->hitTest(nodeInfo, m_mouseDownPos);
1667             Node *node = nodeInfo.innerNode();
1668             _dragSrc = (node && node->renderer()) ? node->renderer()->draggableNode(_dragSrcMayBeDHTML, _dragSrcMayBeUA, m_mouseDownPos.x(), m_mouseDownPos.y(), _dragSrcIsDHTML) : 0;
1669             if (!_dragSrc) {
1670                 _mouseDownMayStartDrag = false;     // no element is draggable
1671             } else {
1672                 // remember some facts about this source, while we have a NodeInfo handy
1673                 node = nodeInfo.URLElement();
1674                 _dragSrcIsLink = node && node->isLink();
1675
1676                 node = nodeInfo.innerNonSharedNode();
1677                 _dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
1678                 
1679                 _dragSrcInSelection = isPointInsideSelection(m_mouseDownPos);
1680             }                
1681         }
1682         
1683         // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
1684         // or else we bail on the dragging stuff and allow selection to occur
1685         if (_mouseDownMayStartDrag && _dragSrcInSelection && [_currentEvent timestamp] - _mouseDownTimestamp < TextDragDelay) {
1686             _mouseDownMayStartDrag = false;
1687             // ...but if this was the first click in the window, we don't even want to start selection
1688             if (_activationEventNumber == [_currentEvent eventNumber]) {
1689                 _mouseDownMayStartSelect = false;
1690             }
1691         }
1692
1693         if (_mouseDownMayStartDrag) {
1694             // We are starting a text/image/url drag, so the cursor should be an arrow
1695             d->m_view->setCursor(pointerCursor());
1696             
1697             NSPoint dragLocation = [_currentEvent locationInWindow];
1698             if (dragHysteresisExceeded(dragLocation.x, dragLocation.y)) {
1699                 
1700                 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
1701                 d->m_view->invalidateClick();
1702
1703                 NSImage *dragImage = nil;       // we use these values if WC is out of the loop
1704                 NSPoint dragLoc = NSZeroPoint;
1705                 NSDragOperation srcOp = NSDragOperationNone;                
1706                 BOOL wcWrotePasteboard = NO;
1707                 if (_dragSrcMayBeDHTML) {
1708                     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
1709                     // Must be done before ondragstart adds types and data to the pboard,
1710                     // also done for security, as it erases data from the last drag
1711                     [pasteboard declareTypes:[NSArray array] owner:nil];
1712                     
1713                     freeClipboard();    // would only happen if we missed a dragEnd.  Do it anyway, just
1714                                         // to make sure it gets numbified
1715                     _dragClipboard = new ClipboardMac(true, pasteboard, ClipboardMac::Writable, this);
1716                     
1717                     // If this is drag of an element, get set up to generate a default image.  Otherwise
1718                     // WebKit will generate the default, the element doesn't override.
1719                     if (_dragSrcIsDHTML) {
1720                         int srcX, srcY;
1721                         _dragSrc->renderer()->absolutePosition(srcX, srcY);
1722                         IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY);
1723                         _dragClipboard->setDragImageElement(_dragSrc.get(), IntPoint() + delta);
1724                     } 
1725
1726                     _mouseDownMayStartDrag = dispatchDragSrcEvent(dragstartEvent, m_mouseDown) && mayCopy();
1727                     // Invalidate clipboard here against anymore pasteboard writing for security.  The drag
1728                     // image can still be changed as we drag, but not the pasteboard data.
1729                     _dragClipboard->setAccessPolicy(ClipboardMac::ImageWritable);
1730                     
1731                     if (_mouseDownMayStartDrag) {
1732                         // gather values from DHTML element, if it set any
1733                         _dragClipboard->sourceOperation(&srcOp);
1734
1735                         NSArray *types = [pasteboard types];
1736                         wcWrotePasteboard = types && [types count] > 0;
1737
1738                         if (_dragSrcMayBeDHTML) {
1739                             dragImage = _dragClipboard->dragNSImage(&dragLoc);
1740                         }
1741                         
1742                         // Yuck, dragSourceMovedTo() can be called as a result of kicking off the drag with
1743                         // dragImage!  Because of that dumb reentrancy, we may think we've not started the
1744                         // drag when that happens.  So we have to assume it's started before we kick it off.
1745                         _dragClipboard->setDragHasStarted();
1746                     }
1747                 }
1748                 
1749                 if (_mouseDownMayStartDrag) {
1750                     BOOL startedDrag = [_bridge startDraggingImage:dragImage at:dragLoc operation:srcOp event:_currentEvent sourceIsDHTML:_dragSrcIsDHTML DHTMLWroteData:wcWrotePasteboard];
1751                     if (!startedDrag && _dragSrcMayBeDHTML) {
1752                         // WebKit canned the drag at the last minute - we owe _dragSrc a DRAGEND event
1753                         PlatformMouseEvent event(PlatformMouseEvent::currentEvent);
1754                         dispatchDragSrcEvent(dragendEvent, event);
1755                         _mouseDownMayStartDrag = false;
1756                     }
1757                 } 
1758
1759                 if (!_mouseDownMayStartDrag) {
1760                     // something failed to start the drag, cleanup
1761                     freeClipboard();
1762                     _dragSrc = 0;
1763                 }
1764             }
1765
1766             // No more default handling (like selection), whether we're past the hysteresis bounds or not
1767             return;
1768         }
1769         if (!_mouseDownMayStartSelect && !_mouseDownMayStartAutoscroll) {
1770             return;
1771         }
1772
1773         // Don't allow dragging or click handling after we've started selecting.
1774         _mouseDownMayStartDrag = false;
1775         d->m_view->invalidateClick();
1776
1777         Node* node = event.targetNode();
1778         RenderObject* renderer = 0;
1779         if (node)
1780             renderer = node->renderer();
1781             
1782         // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
1783         // Otherwise, let the bridge handle it so the view can scroll itself.
1784         while (renderer && !renderer->shouldAutoscroll())
1785             renderer = renderer->parent();
1786         if (renderer)
1787             handleAutoscroll(renderer);
1788         else {
1789             if (!d->m_autoscrollTimer.isActive())
1790                 startAutoscrollTimer();
1791             [_bridge handleAutoscrollForMouseDragged:_currentEvent];
1792         }
1793             
1794     } else {
1795         // If we allowed the other side of the bridge to handle a drag
1796         // last time, then m_bMousePressed might still be set. So we
1797         // clear it now to make sure the next move after a drag
1798         // doesn't look like a drag.
1799         d->m_bMousePressed = false;
1800     }
1801
1802     Frame::handleMouseMoveEvent(event);
1803
1804     END_BLOCK_OBJC_EXCEPTIONS;
1805 }
1806
1807 // Returns whether caller should continue with "the default processing", which is the same as 
1808 // the event handler NOT setting the return value to false
1809 bool FrameMac::dispatchCPPEvent(const AtomicString &eventType, ClipboardMac::AccessPolicy policy)
1810 {
1811     Node* target = selectionController()->start().element();
1812     if (!target && document())
1813         target = document()->body();
1814     if (!target)
1815         return true;
1816     if (target->isShadowNode())
1817         target = target->shadowParentNode();
1818     
1819     RefPtr<ClipboardMac> clipboard = new ClipboardMac(false, [NSPasteboard generalPasteboard], (ClipboardMac::AccessPolicy)policy);
1820
1821     ExceptionCode ec = 0;
1822     RefPtr<Event> evt = new ClipboardEvent(eventType, true, true, clipboard.get());
1823     EventTargetNodeCast(target)->dispatchEvent(evt, ec, true);
1824     bool noDefaultProcessing = evt->defaultPrevented();
1825
1826     // invalidate clipboard here for security
1827     clipboard->setAccessPolicy(ClipboardMac::Numb);
1828
1829     return !noDefaultProcessing;
1830 }
1831
1832 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
1833 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
1834 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
1835 // normally selectable to implement copy/paste (like divs, or a document body).
1836
1837 bool FrameMac::mayDHTMLCut()
1838 {
1839     return mayCopy() && !dispatchCPPEvent(beforecutEvent, ClipboardMac::Numb);
1840 }
1841
1842 bool FrameMac::mayDHTMLCopy()
1843 {
1844     return mayCopy() && !dispatchCPPEvent(beforecopyEvent, ClipboardMac::Numb);
1845 }
1846
1847 bool FrameMac::mayDHTMLPaste()
1848 {
1849     return !dispatchCPPEvent(beforepasteEvent, ClipboardMac::Numb);
1850 }
1851
1852 bool FrameMac::tryDHTMLCut()
1853 {
1854     if (!mayCopy())
1855         return false;
1856
1857     // Must be done before oncut adds types and data to the pboard,
1858     // also done for security, as it erases data from the last copy/paste.
1859     [[NSPasteboard generalPasteboard] declareTypes:[NSArray array] owner:nil];
1860
1861     return !dispatchCPPEvent(cutEvent, ClipboardMac::Writable);
1862 }
1863
1864 bool FrameMac::tryDHTMLCopy()
1865 {
1866     if (!mayCopy())
1867         return false;
1868
1869     // Must be done before oncopy adds types and data to the pboard,
1870     // also done for security, as it erases data from the last copy/paste.
1871     [[NSPasteboard generalPasteboard] declareTypes:[NSArray array] owner:nil];
1872
1873     return !dispatchCPPEvent(copyEvent, ClipboardMac::Writable);
1874 }
1875
1876 bool FrameMac::tryDHTMLPaste()
1877 {
1878     return !dispatchCPPEvent(pasteEvent, ClipboardMac::Readable);
1879 }
1880
1881 void FrameMac::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1882 {
1883     NSView *view = mouseDownViewIfStillGood();
1884     if (!view) {
1885         // If this was the first click in the window, we don't even want to clear the selection.
1886         // This case occurs when the user clicks on a draggable element, since we have to process
1887         // the mouse down and drag events to see if we might start a drag.  For other first clicks
1888         // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
1889         // ignored upstream of this layer.
1890         if (_activationEventNumber != [_currentEvent eventNumber])
1891             Frame::handleMouseReleaseEvent(event);
1892         return;
1893     }
1894     stopAutoscrollTimer();
1895     
1896     _sendingEventToSubview = true;
1897     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1898     [view mouseUp:_currentEvent];
1899     END_BLOCK_OBJC_EXCEPTIONS;
1900     _sendingEventToSubview = false;
1901 }
1902
1903 bool FrameMac::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframePart)
1904 {
1905     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1906
1907     switch ([_currentEvent type]) {
1908         case NSMouseMoved: {
1909             ASSERT(subframePart);
1910             [Mac(subframePart)->bridge() mouseMoved:_currentEvent];
1911             return true;
1912         }
1913         
1914         case NSLeftMouseDown: {
1915             Node *node = event.targetNode();
1916             if (!node) {
1917                 return false;
1918             }
1919             RenderObject *renderer = node->renderer();
1920             if (!renderer || !renderer->isWidget()) {
1921                 return false;
1922             }
1923             Widget *widget = static_cast<RenderWidget*>(renderer)->widget();
1924             if (!widget || !widget->isFrameView())
1925                 return false;
1926             if (!passWidgetMouseDownEventToWidget(static_cast<RenderWidget*>(renderer))) {
1927                 return false;
1928             }
1929             _mouseDownWasInSubframe = true;
1930             return true;
1931         }
1932         case NSLeftMouseUp: {
1933             if (!_mouseDownWasInSubframe) {
1934                 return false;
1935             }
1936             NSView *view = mouseDownViewIfStillGood();
1937             if (!view) {
1938                 return false;
1939             }
1940             ASSERT(!_sendingEventToSubview);
1941             _sendingEventToSubview = true;
1942             [view mouseUp:_currentEvent];
1943             _sendingEventToSubview = false;
1944             return true;
1945         }
1946         case NSLeftMouseDragged: {
1947             if (!_mouseDownWasInSubframe) {
1948                 return false;
1949             }
1950             NSView *view = mouseDownViewIfStillGood();
1951             if (!view) {
1952                 return false;
1953             }
1954             ASSERT(!_sendingEventToSubview);
1955             _sendingEventToSubview = true;
1956             [view mouseDragged:_currentEvent];
1957             _sendingEventToSubview = false;
1958             return true;
1959         }
1960         default:
1961             return false;
1962     }
1963     END_BLOCK_OBJC_EXCEPTIONS;
1964
1965     return false;
1966 }
1967
1968 bool FrameMac::passWheelEventToWidget(Widget* widget)
1969 {
1970     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1971         
1972     if ([_currentEvent type] != NSScrollWheel || _sendingEventToSubview || !widget) 
1973         return false;
1974     else {
1975         NSView *nodeView = widget->getView();
1976         ASSERT(nodeView);
1977         ASSERT([nodeView superview]);
1978         NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[_currentEvent locationInWindow] fromView:nil]];
1979     
1980         ASSERT(view);
1981         _sendingEventToSubview = true;
1982         [view scrollWheel:_currentEvent];
1983         _sendingEventToSubview = false;
1984         return true;
1985     }
1986             
1987     END_BLOCK_OBJC_EXCEPTIONS;
1988     return false;
1989 }
1990
1991 void FrameMac::mouseDown(NSEvent *event)
1992 {
1993     FrameView *v = d->m_view.get();
1994     if (!v || _sendingEventToSubview)
1995         return;
1996
1997     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1998
1999     prepareForUserAction();
2000
2001     _mouseDownView = nil;
2002     _dragSrc = 0;
2003     
2004     NSEvent *oldCurrentEvent = _currentEvent;
2005     _currentEvent = HardRetain(event);
2006     m_mouseDown = PlatformMouseEvent(event);
2007     NSPoint loc = [event locationInWindow];
2008     m_mouseDownPos = d->m_view->windowToContents(IntPoint(loc));
2009     _mouseDownTimestamp = [event timestamp];
2010
2011     _mouseDownMayStartDrag = false;
2012     _mouseDownMayStartSelect = false;
2013     _mouseDownMayStartAutoscroll = false;
2014
2015     v->handleMousePressEvent(event);
2016     
2017     ASSERT(_currentEvent == event);
2018     HardRelease(event);
2019     _currentEvent = oldCurrentEvent;
2020
2021     END_BLOCK_OBJC_EXCEPTIONS;
2022 }
2023
2024 void FrameMac::mouseDragged(NSEvent *event)
2025 {
2026     FrameView *v = d->m_view.get();
2027     if (!v || _sendingEventToSubview) {
2028         return;
2029     }
2030
2031     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2032
2033     NSEvent *oldCurrentEvent = _currentEvent;
2034     _currentEvent = HardRetain(event);
2035
2036     v->handleMouseMoveEvent(event);
2037     
2038     ASSERT(_currentEvent == event);
2039     HardRelease(event);
2040     _currentEvent = oldCurrentEvent;
2041
2042     END_BLOCK_OBJC_EXCEPTIONS;
2043 }
2044
2045 void FrameMac::mouseUp(NSEvent *event)
2046 {
2047     FrameView *v = d->m_view.get();
2048     if (!v || _sendingEventToSubview)
2049         return;
2050
2051     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2052
2053     NSEvent *oldCurrentEvent = _currentEvent;
2054     _currentEvent = HardRetain(event);
2055
2056     // Our behavior here is a little different that Qt. Qt always sends
2057     // a mouse release event, even for a double click. To correct problems
2058     // in khtml's DOM click event handling we do not send a release here
2059     // for a double click. Instead we send that event from FrameView's
2060     // handleMouseDoubleClickEvent. Note also that the third click of
2061     // a triple click is treated as a single click, but the fourth is then
2062     // treated as another double click. Hence the "% 2" below.
2063     int clickCount = [event clickCount];
2064     if (clickCount > 0 && clickCount % 2 == 0)
2065         v->handleMouseDoubleClickEvent(event);
2066     else
2067         v->handleMouseReleaseEvent(event);
2068     
2069     ASSERT(_currentEvent == event);
2070     HardRelease(event);
2071     _currentEvent = oldCurrentEvent;
2072     
2073     _mouseDownView = nil;
2074
2075     END_BLOCK_OBJC_EXCEPTIONS;
2076 }
2077
2078 /*
2079  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
2080  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
2081  is done, this routine is used to fix things up.  When a mouse down started us tracking in
2082  the widget, we post a fake mouse up to balance the mouse down we started with. When a 
2083  key down started us tracking in the widget, we post a fake key up to balance things out.
2084  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
2085  be over after the tracking is done.
2086  */
2087 void FrameMac::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
2088 {
2089     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2090
2091     _sendingEventToSubview = false;
2092     int eventType = [initiatingEvent type];
2093     if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
2094         NSEvent *fakeEvent = nil;
2095         if (eventType == NSLeftMouseDown) {
2096             fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
2097                                     location:[initiatingEvent locationInWindow]
2098                                 modifierFlags:[initiatingEvent modifierFlags]
2099                                     timestamp:[initiatingEvent timestamp]
2100                                 windowNumber:[initiatingEvent windowNumber]
2101                                         context:[initiatingEvent context]
2102                                     eventNumber:[initiatingEvent eventNumber]
2103                                     clickCount:[initiatingEvent clickCount]
2104                                     pressure:[initiatingEvent pressure]];
2105         
2106             mouseUp(fakeEvent);
2107         }
2108         else { // eventType == NSKeyDown
2109             fakeEvent = [NSEvent keyEventWithType:NSKeyUp
2110                                     location:[initiatingEvent locationInWindow]
2111                                modifierFlags:[initiatingEvent modifierFlags]
2112                                    timestamp:[initiatingEvent timestamp]
2113                                 windowNumber:[initiatingEvent windowNumber]
2114                                      context:[initiatingEvent context]
2115                                   characters:[initiatingEvent characters] 
2116                  charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
2117                                    isARepeat:[initiatingEvent isARepeat] 
2118                                      keyCode:[initiatingEvent keyCode]];
2119             keyEvent(fakeEvent);
2120         }
2121         // FIXME:  We should really get the current modifierFlags here, but there's no way to poll
2122         // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
2123         // no up-to-date cache of them anywhere.
2124         fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
2125                                        location:[[_bridge window] convertScreenToBase:[NSEvent mouseLocation]]
2126                                   modifierFlags:[initiatingEvent modifierFlags]
2127                                       timestamp:[initiatingEvent timestamp]
2128                                    windowNumber:[initiatingEvent windowNumber]
2129                                         context:[initiatingEvent context]
2130                                     eventNumber:0
2131                                      clickCount:0
2132                                        pressure:0];
2133         mouseMoved(fakeEvent);
2134     }
2135     
2136     END_BLOCK_OBJC_EXCEPTIONS;
2137 }
2138
2139 void FrameMac::mouseMoved(NSEvent *event)
2140 {
2141     FrameView *v = d->m_view.get();
2142     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
2143     // These happen because WebKit sometimes has to fake up moved events.
2144     if (!v || d->m_bMousePressed || _sendingEventToSubview)
2145         return;
2146     
2147     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2148
2149     NSEvent *oldCurrentEvent = _currentEvent;
2150     _currentEvent = HardRetain(event);
2151     
2152     v->handleMouseMoveEvent(event);
2153     
2154     ASSERT(_currentEvent == event);
2155     HardRelease(event);
2156     _currentEvent = oldCurrentEvent;
2157
2158     END_BLOCK_OBJC_EXCEPTIONS;
2159 }
2160
2161 // Called as we walk up the element chain for nodes with CSS property -webkit-user-drag == auto
2162 bool FrameMac::shouldDragAutoNode(Node* node, const IntPoint& point) const
2163 {
2164     // We assume that WebKit only cares about dragging things that can be leaf nodes (text, images, urls).
2165     // This saves a bunch of expensive calls (creating WC and WK element dicts) as we walk farther up
2166     // the node hierarchy, and we also don't have to cook up a way to ask WK about non-leaf nodes
2167     // (since right now WK just hit-tests using a cached lastMouseDown).
2168     if (!node->hasChildNodes() && d->m_view) {
2169         NSPoint eventLoc = d->m_view->contentsToWindow(point);
2170         return [_bridge mayStartDragAtEventLocation:eventLoc];
2171     } else
2172         return NO;
2173 }
2174
2175 bool FrameMac::sendContextMenuEvent(NSEvent *event)
2176 {
2177     Document* doc = d->m_doc.get();
2178     FrameView* v = d->m_view.get();
2179     if (!doc || !v)
2180         return false;
2181
2182     bool swallowEvent;
2183     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2184
2185     NSEvent *oldCurrentEvent = _currentEvent;
2186     _currentEvent = HardRetain(event);
2187     
2188     PlatformMouseEvent mouseEvent(event);
2189
2190     IntPoint viewportPos = v->windowToContents(mouseEvent.pos());
2191     MouseEventWithHitTestResults mev = doc->prepareMouseEvent(false, true, false, viewportPos, mouseEvent);
2192
2193     swallowEvent = v->dispatchMouseEvent(contextmenuEvent, mev.targetNode(), true, 0, mouseEvent, true);
2194     if (!swallowEvent && !isPointInsideSelection(viewportPos) &&
2195             ([_bridge selectWordBeforeMenuEvent] || [_bridge isEditable]
2196                 || (mev.targetNode() && mev.targetNode()->isContentEditable()))) {
2197         _mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2198         selectClosestWordFromMouseEvent(mouseEvent, mev.targetNode());
2199     }
2200
2201     ASSERT(_currentEvent == event);
2202     HardRelease(event);
2203     _currentEvent = oldCurrentEvent;
2204
2205     return swallowEvent;
2206
2207     END_BLOCK_OBJC_EXCEPTIONS;
2208
2209     return false;
2210 }
2211
2212 struct ListItemInfo {
2213     unsigned start;
2214     unsigned end;
2215 };
2216
2217 NSFileWrapper *FrameMac::fileWrapperForElement(Element *e)
2218 {
2219     NSFileWrapper *wrapper = nil;
2220     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2221     
2222     const AtomicString& attr = e->getAttribute(srcAttr);
2223     if (!attr.isEmpty()) {
2224         NSURL *URL = completeURL(attr.deprecatedString()).getNSURL();
2225         wrapper = [_bridge fileWrapperForURL:URL];
2226     }    
2227     if (!wrapper) {
2228         RenderImage *renderer = static_cast<RenderImage*>(e->renderer());
2229         if (renderer->cachedImage() && !renderer->cachedImage()->isErrorImage()) {
2230             wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:(NSData*)(renderer->cachedImage()->image()->getTIFFRepresentation())];
2231             [wrapper setPreferredFilename:@"image.tiff"];
2232             [wrapper autorelease];
2233         }
2234     }
2235
2236     return wrapper;
2237
2238     END_BLOCK_OBJC_EXCEPTIONS;
2239
2240     return nil;
2241 }
2242
2243 static Element *listParent(Element *item)
2244 {
2245     while (!item->hasTagName(ulTag) && !item->hasTagName(olTag)) {
2246         item = static_cast<Element*>(item->parentNode());
2247         if (!item)
2248             break;
2249     }
2250     return item;
2251 }
2252
2253 static Node* isTextFirstInListItem(Node *e)
2254 {
2255     if (!e->isTextNode())
2256         return 0;
2257     Node* par = e->parentNode();
2258     while (par) {
2259         if (par->firstChild() != e)
2260             return 0;
2261         if (par->hasTagName(liTag))
2262             return par;
2263         e = par;
2264         par = par->parentNode();
2265     }
2266     return 0;
2267 }
2268
2269 // FIXME: Enhance TextIterator to optionally add attributes, then just call through to that.
2270
2271 #define BULLET_CHAR 0x2022
2272 #define SQUARE_CHAR 0x25AA
2273 #define CIRCLE_CHAR 0x25E6
2274
2275 NSAttributedString *FrameMac::attributedString(Node *startNode, int startOffset, Node *endNode, int endOffset)
2276 {
2277     ListItemInfo info;
2278     NSMutableAttributedString *result;
2279     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2280
2281     Range range(document(), startNode, startOffset, endNode, endOffset);
2282     if (!range.boundaryPointsValid())
2283         return nil;
2284     
2285     Node* firstNode = range.startNode();
2286     if (!firstNode)
2287         return nil;
2288     Node* pastEndNode = range.pastEndNode();
2289     
2290     result = [[[NSMutableAttributedString alloc] init] autorelease];
2291     
2292     bool hasNewLine = true;
2293     bool addedSpace = true;
2294     NSAttributedString *pendingStyledSpace = nil;
2295     bool hasParagraphBreak = true;
2296     const Element *linkStartNode = 0;
2297     unsigned linkStartLocation = 0;
2298     Vector<Element*> listItems;
2299     Vector<ListItemInfo> listItemLocations;
2300     float maxMarkerWidth = 0;
2301     
2302     Node *currentNode = firstNode;
2303     
2304     // If the first item is the entire text of a list item, use the list item node as the start of the 
2305     // selection, not the text node.  The user's intent was probably to select the list.
2306     if (currentNode->isTextNode() && startOffset == 0) {
2307         Node *startListNode = isTextFirstInListItem(firstNode);
2308         if (startListNode){
2309             firstNode = startListNode;
2310             currentNode = firstNode;
2311         }
2312     }
2313     
2314     while (currentNode && currentNode != pastEndNode) {
2315         RenderObject *renderer = currentNode->renderer();
2316         if (renderer) {
2317             RenderStyle *style = renderer->style();
2318             NSFont *font = style->font().primaryFont()->getNSFont();
2319             bool needSpace = pendingStyledSpace != nil;
2320             if (currentNode->isTextNode()) {
2321                 if (hasNewLine) {
2322                     addedSpace = true;
2323                     needSpace = false;
2324                     [pendingStyledSpace release];
2325                     pendingStyledSpace = nil;
2326                     hasNewLine = false;
2327                 }
2328                 DeprecatedString text;
2329                 DeprecatedString str = currentNode->nodeValue().deprecatedString();
2330                 int start = (currentNode == firstNode) ? startOffset : -1;
2331                 int end = (currentNode == endNode) ? endOffset : -1;
2332                 if (renderer->isText()) {
2333                     if (!style->collapseWhiteSpace()) {
2334                         if (needSpace && !addedSpace) {
2335                             if (text.isEmpty() && linkStartLocation == [result length])
2336                                 ++linkStartLocation;
2337                             [result appendAttributedString:pendingStyledSpace];
2338                         }
2339                         int runStart = (start == -1) ? 0 : start;
2340                         int runEnd = (end == -1) ? str.length() : end;
2341                         text += str.mid(runStart, runEnd-runStart);
2342                         [pendingStyledSpace release];
2343                         pendingStyledSpace = nil;
2344                         addedSpace = u_charDirection(str[runEnd - 1].unicode()) == U_WHITE_SPACE_NEUTRAL;
2345                     }
2346                     else {
2347                         RenderText* textObj = static_cast<RenderText*>(renderer);
2348                         if (!textObj->firstTextBox() && str.length() > 0 && !addedSpace) {
2349                             // We have no runs, but we do have a length.  This means we must be
2350                             // whitespace that collapsed away at the end of a line.
2351                             text += ' ';
2352                             addedSpace = true;
2353                         }
2354                         else {
2355                             addedSpace = false;
2356                             for (InlineTextBox* box = textObj->firstTextBox(); box; box = box->nextTextBox()) {
2357                                 int runStart = (start == -1) ? box->m_start : start;
2358                                 int runEnd = (end == -1) ? box->m_start + box->m_len : end;
2359                                 runEnd = min(runEnd, box->m_start + box->m_len);
2360                                 if (runStart >= box->m_start &&
2361                                     runStart < box->m_start + box->m_len) {
2362                                     if (box == textObj->firstTextBox() && box->m_start == runStart && runStart > 0)
2363                                         needSpace = true; // collapsed space at the start
2364                                     if (needSpace && !addedSpace) {
2365                                         if (pendingStyledSpace != nil) {
2366                                             if (text.isEmpty() && linkStartLocation == [result length])
2367                                                 ++linkStartLocation;
2368                                             [result appendAttributedString:pendingStyledSpace];
2369                                         } else
2370                                             text += ' ';
2371                                     }
2372                                     DeprecatedString runText = str.mid(runStart, runEnd - runStart);
2373                                     runText.replace('\n', ' ');
2374                                     text += runText;
2375                                     int nextRunStart = box->nextTextBox() ? box->nextTextBox()->m_start : str.length(); // collapsed space between runs or at the end
2376                                     needSpace = nextRunStart > runEnd;
2377                                     [pendingStyledSpace release];
2378                                     pendingStyledSpace = nil;
2379                                     addedSpace = u_charDirection(str[runEnd - 1].unicode()) == U_WHITE_SPACE_NEUTRAL;
2380                                     start = -1;
2381                                 }
2382                                 if (end != -1 && runEnd >= end)
2383                                     break;
2384                             }
2385                         }
2386                     }
2387                 }
2388                 
2389                 text.replace('\\', renderer->backslashAsCurrencySymbol());
2390     
2391                 if (text.length() > 0 || needSpace) {
2392                     NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
2393                     [attrs setObject:font forKey:NSFontAttributeName];
2394                     if (style && style->color().isValid() && style->color().alpha() != 0)
2395                         [attrs setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
2396                     if (style && style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
2397                         [attrs setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
2398
2399                     if (text.length() > 0) {
2400                         hasParagraphBreak = false;
2401                         NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString() attributes:attrs];
2402                         [result appendAttributedString: partialString];                
2403                         [partialString release];
2404                     }
2405
2406                     if (needSpace) {
2407                         [pendingStyledSpace release];
2408                         pendingStyledSpace = [[NSAttributedString alloc] initWithString:@" " attributes:attrs];
2409                     }
2410
2411                     [attrs release];
2412                 }
2413             } else {
2414                 // This is our simple HTML -> ASCII transformation:
2415                 DeprecatedString text;
2416                 if (currentNode->hasTagName(aTag)) {
2417                     // Note the start of the <a> element.  We will add the NSLinkAttributeName
2418                     // attribute to the attributed string when navigating to the next sibling 
2419                     // of this node.
2420                     linkStartLocation = [result length];
2421                     linkStartNode = static_cast<Element*>(currentNode);
2422                 } else if (currentNode->hasTagName(brTag)) {
2423                     text += "\n";
2424                     hasNewLine = true;
2425                 } else if (currentNode->hasTagName(liTag)) {
2426                     DeprecatedString listText;
2427                     Element *itemParent = listParent(static_cast<Element*>(currentNode));
2428                     
2429                     if (!hasNewLine)
2430                         listText += '\n';
2431                     hasNewLine = true;
2432
2433                     listItems.append(static_cast<Element*>(currentNode));
2434                     info.start = [result length];
2435                     info.end = 0;
2436                     listItemLocations.append (info);
2437                     
2438                     listText += '\t';
2439                     if (itemParent && renderer->isListItem()) {
2440                         RenderListItem* listRenderer = static_cast<RenderListItem*>(renderer);
2441
2442                         maxMarkerWidth = MAX([font pointSize], maxMarkerWidth);
2443                         switch(style->listStyleType()) {
2444                             case DISC:
2445                                 listText += ((DeprecatedChar)BULLET_CHAR);
2446                                 break;
2447                             case CIRCLE:
2448                                 listText += ((DeprecatedChar)CIRCLE_CHAR);
2449                                 break;
2450                             case SQUARE:
2451                                 listText += ((DeprecatedChar)SQUARE_CHAR);
2452                                 break;
2453                             case LNONE:
2454                                 break;
2455                             default:
2456                                 DeprecatedString marker = listRenderer->markerStringValue();
2457                                 listText += marker;
2458                                 // Use AppKit metrics.  Will be rendered by AppKit.
2459                                 float markerWidth = [marker.getNSString() sizeWithAttributes:[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]].width;
2460                                 maxMarkerWidth = MAX(markerWidth, maxMarkerWidth);
2461                         }
2462
2463                         listText += ' ';
2464                         listText += '\t';
2465
2466                         NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
2467                         [attrs setObject:font forKey:NSFontAttributeName];
2468                         if (style && style->color().isValid())
2469                             [attrs setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
2470                         if (style && style->backgroundColor().isValid())
2471                             [attrs setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
2472
2473                         NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:listText.getNSString() attributes:attrs];
2474                         [attrs release];
2475                         [result appendAttributedString: partialString];                
2476                         [partialString release];
2477                     }
2478                 } else if (currentNode->hasTagName(olTag) || currentNode->hasTagName(ulTag)) {
2479                     if (!hasNewLine)
2480                         text += "\n";
2481                     hasNewLine = true;
2482                 } else if (currentNode->hasTagName(blockquoteTag)
2483                         || currentNode->hasTagName(ddTag)
2484                         || currentNode->hasTagName(divTag)
2485                         || currentNode->hasTagName(dlTag)
2486                         || currentNode->hasTagName(dtTag)
2487                         || currentNode->hasTagName(hrTag)
2488                         || currentNode->hasTagName(listingTag)
2489                         || currentNode->hasTagName(preTag)
2490                         || currentNode->hasTagName(tdTag)
2491                         || currentNode->hasTagName(thTag)) {
2492                     if (!hasNewLine)
2493                         text += '\n';
2494                     hasNewLine = true;
2495                 } else if (currentNode->hasTagName(h1Tag)
2496                         || currentNode->hasTagName(h2Tag)
2497                         || currentNode->hasTagName(h3Tag)
2498                         || currentNode->hasTagName(h4Tag)
2499                         || currentNode->hasTagName(h5Tag)
2500                         || currentNode->hasTagName(h6Tag)
2501                         || currentNode->hasTagName(pTag)
2502                         || currentNode->hasTagName(trTag)) {
2503                     if (!hasNewLine)
2504                         text += '\n';
2505                     
2506                     // In certain cases, emit a paragraph break.
2507                     int bottomMargin = renderer->collapsedMarginBottom();
2508                     int fontSize = style->fontDescription().computedPixelSize();
2509                     if (bottomMargin * 2 >= fontSize) {
2510                         if (!hasParagraphBreak) {
2511                             text += '\n';
2512                             hasParagraphBreak = true;
2513                         }
2514                     }
2515                     
2516                     hasNewLine = true;
2517                 }
2518                 else if (currentNode->hasTagName(imgTag)) {
2519                     if (pendingStyledSpace != nil) {
2520                         if (linkStartLocation == [result length])
2521                             ++linkStartLocation;
2522                         [result appendAttributedString:pendingStyledSpace];
2523                         [pendingStyledSpace release];
2524                         pendingStyledSpace = nil;
2525                     }
2526                     NSFileWrapper *fileWrapper = fileWrapperForElement(static_cast<Element*>(currentNode));
2527                     NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
2528                     NSAttributedString *iString = [NSAttributedString attributedStringWithAttachment:attachment];
2529                     [result appendAttributedString: iString];
2530                     [attachment release];
2531                 }
2532
2533                 NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2534                 [result appendAttributedString: partialString];
2535                 [partialString release];
2536             }
2537         }
2538
2539         Node *nextNode = currentNode->firstChild();
2540         if (!nextNode)
2541             nextNode = currentNode->nextSibling();
2542
2543         while (!nextNode && currentNode->parentNode()) {
2544             DeprecatedString text;
2545             currentNode = currentNode->parentNode();
2546             if (currentNode == pastEndNode)
2547                 break;
2548             nextNode = currentNode->nextSibling();
2549
2550             if (currentNode->hasTagName(aTag)) {
2551                 // End of a <a> element.  Create an attributed string NSLinkAttributeName attribute
2552                 // for the range of the link.  Note that we create the attributed string from the DOM, which
2553                 // will have corrected any illegally nested <a> elements.
2554                 if (linkStartNode && currentNode == linkStartNode) {
2555                     String href = parseURL(linkStartNode->getAttribute(hrefAttr));
2556                     KURL kURL = Mac(linkStartNode->document()->frame())->completeURL(href.deprecatedString());
2557                     
2558                     NSURL *URL = kURL.getNSURL();
2559                     NSRange tempRange = { linkStartLocation, [result length]-linkStartLocation }; // workaround for 4213314
2560                     [result addAttribute:NSLinkAttributeName value:URL range:tempRange];
2561                     linkStartNode = 0;
2562                 }
2563             }
2564             else if (currentNode->hasTagName(olTag) || currentNode->hasTagName(ulTag)) {
2565                 if (!hasNewLine)
2566                     text += '\n';
2567                 hasNewLine = true;
2568             } else if (currentNode->hasTagName(liTag)) {
2569                 
2570                 int i, count = listItems.size();
2571                 for (i = 0; i < count; i++){
2572                     if (listItems[i] == currentNode){
2573                         listItemLocations[i].end = [result length];
2574                         break;
2575                     }
2576                 }
2577                 if (!hasNewLine)
2578                     text += '\n';
2579                 hasNewLine = true;
2580             } else if (currentNode->hasTagName(blockquoteTag) ||
2581                        currentNode->hasTagName(ddTag) ||
2582                        currentNode->hasTagName(divTag) ||
2583                        currentNode->hasTagName(dlTag) ||
2584                        currentNode->hasTagName(dtTag) ||
2585                        currentNode->hasTagName(hrTag) ||
2586                        currentNode->hasTagName(listingTag) ||
2587                        currentNode->hasTagName(preTag) ||
2588                        currentNode->hasTagName(tdTag) ||
2589                        currentNode->hasTagName(thTag)) {
2590                 if (!hasNewLine)
2591                     text += '\n';
2592                 hasNewLine = true;
2593             } else if (currentNode->hasTagName(pTag) ||
2594                        currentNode->hasTagName(trTag) ||
2595                        currentNode->hasTagName(h1Tag) ||
2596                        currentNode->hasTagName(h2Tag) ||
2597                        currentNode->hasTagName(h3Tag) ||
2598                        currentNode->hasTagName(h4Tag) ||
2599                        currentNode->hasTagName(h5Tag) ||
2600                        currentNode->hasTagName(h6Tag)) {
2601                 if (!hasNewLine)
2602                     text += '\n';
2603                 // An extra newline is needed at the start, not the end, of these types of tags,
2604                 // so don't add another here.
2605                 hasNewLine = true;
2606             }
2607             
2608             NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2609             [result appendAttributedString:partialString];
2610             [partialString release];
2611         }
2612
2613         currentNode = nextNode;
2614     }
2615     
2616     [pendingStyledSpace release];
2617     
2618     // Apply paragraph styles from outside in.  This ensures that nested lists correctly
2619     // override their parent's paragraph style.
2620     {
2621         unsigned i, count = listItems.size();
2622         Element *e;
2623
2624 #ifdef POSITION_LIST
2625         Node *containingBlock;
2626         int containingBlockX, containingBlockY;
2627         
2628         // Determine the position of the outermost containing block.  All paragraph
2629         // styles and tabs should be relative to this position.  So, the horizontal position of 
2630         // each item in the list (in the resulting attributed string) will be relative to position 
2631         // of the outermost containing block.
2632         if (count > 0){
2633             containingBlock = firstNode;
2634             while (containingBlock->renderer()->isInline()){
2635                 containingBlock = containingBlock->parentNode();
2636             }
2637             containingBlock->renderer()->absolutePosition(containingBlockX, containingBlockY);
2638         }
2639 #endif
2640         
2641         for (i = 0; i < count; i++){
2642             e = listItems[i];
2643             info = listItemLocations[i];
2644             
2645             if (info.end < info.start)
2646                 info.end = [result length];
2647                 
2648             RenderObject *r = e->renderer();
2649             RenderStyle *style = r->style();
2650
2651             int rx;
2652             NSFont *font = style->font().primaryFont()->getNSFont();
2653             float pointSize = [font pointSize];
2654
2655 #ifdef POSITION_LIST
2656             int ry;
2657             r->absolutePosition(rx, ry);
2658             rx -= containingBlockX;
2659             
2660             // Ensure that the text is indented at least enough to allow for the markers.
2661             rx = MAX(rx, (int)maxMarkerWidth);
2662 #else
2663             rx = (int)MAX(maxMarkerWidth, pointSize);
2664 #endif
2665
2666             // The bullet text will be right aligned at the first tab marker, followed
2667             // by a space, followed by the list item text.  The space is arbitrarily
2668             // picked as pointSize*2/3.  The space on the first line of the text item
2669             // is established by a left aligned tab, on subsequent lines it's established
2670             // by the head indent.
2671             NSMutableParagraphStyle *mps = [[NSMutableParagraphStyle alloc] init];
2672             [mps setFirstLineHeadIndent: 0];
2673             [mps setHeadIndent: rx];
2674             [mps setTabStops:[NSArray arrayWithObjects:
2675                         [[[NSTextTab alloc] initWithType:NSRightTabStopType location:rx-(pointSize*2/3)] autorelease],
2676                         [[[NSTextTab alloc] initWithType:NSLeftTabStopType location:rx] autorelease],
2677                         nil]];
2678             NSRange tempRange = { info.start, info.end-info.start }; // workaround for 4213314
2679             [result addAttribute:NSParagraphStyleAttributeName value:mps range:tempRange];
2680             [mps release];
2681         }
2682     }
2683
2684     return result;
2685
2686     END_BLOCK_OBJC_EXCEPTIONS;
2687
2688     return nil;
2689 }
2690
2691 NSImage *FrameMac::imageFromRect(NSRect rect) const
2692 {
2693     NSView *view = d->m_view->getDocumentView();
2694     if (!view)
2695         return nil;
2696     
2697     NSImage *resultImage;
2698     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2699     
2700     NSRect bounds = [view bounds];
2701     
2702     // Round image rect size in window coordinate space to avoid pixel cracks at HiDPI (4622794)
2703     rect = [view convertRect:rect toView:nil];
2704     rect.size.height = roundf(rect.size.height);
2705     rect.size.width = roundf(rect.size.width);
2706     rect = [view convertRect:rect fromView:nil];
2707     
2708     resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
2709
2710     if (rect.size.width != 0 && rect.size.height != 0) {
2711         [resultImage setFlipped:YES];
2712         [resultImage lockFocus];
2713
2714         CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
2715
2716         CGContextSaveGState(context);
2717         CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
2718         [view drawRect:rect];
2719         CGContextRestoreGState(context);
2720
2721         [resultImage unlockFocus];
2722         [resultImage setFlipped:NO];
2723     }
2724
2725     return resultImage;
2726
2727     END_BLOCK_OBJC_EXCEPTIONS;
2728     
2729     return nil;
2730 }
2731
2732 NSImage* FrameMac::selectionImage(bool forceWhiteText) const
2733 {
2734     d->m_paintRestriction = forceWhiteText ? PaintRestrictionSelectionOnlyWhiteText : PaintRestrictionSelectionOnly;
2735     NSImage *result = imageFromRect(visibleSelectionRect());
2736     d->m_paintRestriction = PaintRestrictionNone;
2737     return result;
2738 }
2739
2740 NSImage *FrameMac::snapshotDragImage(Node *node, NSRect *imageRect, NSRect *elementRect) const
2741 {
2742     RenderObject *renderer = node->renderer();
2743     if (!renderer)
2744         return nil;
2745     
2746     renderer->updateDragState(true);    // mark dragged nodes (so they pick up the right CSS)
2747     d->m_doc->updateLayout();        // forces style recalc - needed since changing the drag state might
2748                                         // imply new styles, plus JS could have changed other things
2749     IntRect topLevelRect;
2750     NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
2751
2752     d->m_elementToDraw = node;              // invoke special sub-tree drawing mode
2753     NSImage *result = imageFromRect(paintingRect);
2754     renderer->updateDragState(false);
2755     d->m_doc->updateLayout();
2756     d->m_elementToDraw = 0;
2757
2758     if (elementRect)
2759         *elementRect = topLevelRect;
2760     if (imageRect)
2761         *imageRect = paintingRect;
2762     return result;
2763 }
2764
2765 NSFont *FrameMac::fontForSelection(bool *hasMultipleFonts) const
2766 {
2767     if (hasMultipleFonts)
2768         *hasMultipleFonts = false;
2769
2770     if (!selectionController()->isRange()) {
2771         Node *nodeToRemove;
2772         RenderStyle *style = styleForSelectionStart(nodeToRemove); // sets nodeToRemove
2773
2774         NSFont *result = 0;
2775         if (style)
2776             result = style->font().primaryFont()->getNSFont();
2777         
2778         if (nodeToRemove) {
2779             ExceptionCode ec;
2780             nodeToRemove->remove(ec);
2781             ASSERT(ec == 0);
2782         }
2783
2784         return result;
2785     }
2786
2787     NSFont *font = nil;
2788
2789     RefPtr<Range> range = selectionController()->toRange();
2790     Node *startNode = range->editingStartPosition().node();
2791     if (startNode != nil) {
2792         Node *pastEnd = range->pastEndNode();
2793         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
2794         // unreproducible case where this didn't happen, so check for nil also.
2795         for (Node *n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
2796             RenderObject *renderer = n->renderer();
2797             if (!renderer)
2798                 continue;
2799             // FIXME: Are there any node types that have renderers, but that we should be skipping?
2800             NSFont *f = renderer->style()->font().primaryFont()->getNSFont();
2801             if (!font) {
2802                 font = f;
2803                 if (!hasMultipleFonts)
2804                     break;
2805             } else if (font != f) {
2806                 *hasMultipleFonts = true;
2807                 break;
2808             }
2809         }
2810     }
2811
2812     return font;
2813 }
2814
2815 NSDictionary *FrameMac::fontAttributesForSelectionStart() const
2816 {
2817     Node *nodeToRemove;
2818     RenderStyle *style = styleForSelectionStart(nodeToRemove);
2819     if (!style)
2820         return nil;
2821
2822     NSMutableDictionary *result = [NSMutableDictionary dictionary];
2823
2824     if (style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
2825         [result setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
2826
2827     if (style->font().primaryFont()->getNSFont())
2828         [result setObject:style->font().primaryFont()->getNSFont() forKey:NSFontAttributeName];
2829
2830     if (style->color().isValid() && style->color() != Color::black)
2831         [result setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
2832
2833     ShadowData *shadow = style->textShadow();
2834     if (shadow) {
2835         NSShadow *s = [[NSShadow alloc] init];
2836         [s setShadowOffset:NSMakeSize(shadow->x, shadow->y)];
2837         [s setShadowBlurRadius:shadow->blur];
2838         [s setShadowColor:nsColor(shadow->color)];
2839         [result setObject:s forKey:NSShadowAttributeName];
2840     }
2841
2842     int decoration = style->textDecorationsInEffect();
2843     if (decoration & LINE_THROUGH)
2844         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
2845
2846     int superscriptInt = 0;
2847     switch (style->verticalAlign()) {
2848         case BASELINE:
2849         case BOTTOM:
2850         case BASELINE_MIDDLE:
2851         case LENGTH:
2852         case MIDDLE:
2853         case TEXT_BOTTOM:
2854         case TEXT_TOP:
2855         case TOP:
2856             break;
2857         case SUB:
2858             superscriptInt = -1;
2859             break;
2860         case SUPER:
2861             superscriptInt = 1;
2862             break;
2863     }
2864     if (superscriptInt)
2865         [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];
2866
2867     if (decoration & UNDERLINE)
2868         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
2869
2870     if (nodeToRemove) {
2871         ExceptionCode ec = 0;
2872         nodeToRemove->remove(ec);
2873         ASSERT(ec == 0);
2874     }
2875
2876     return result;
2877 }
2878
2879 NSWritingDirection FrameMac::baseWritingDirectionForSelectionStart() const
2880 {
2881     NSWritingDirection result = NSWritingDirectionLeftToRight;
2882
2883     Position pos = selectionController()->selection().visibleStart().deepEquivalent();
2884     Node *node = pos.node();
2885     if (!node || !node->renderer() || !node->renderer()->containingBlock())
2886         return result;
2887     RenderStyle *style = node->renderer()->containingBlock()->style();
2888     if (!style)
2889         return result;
2890         
2891     switch (style->direction()) {
2892         case LTR:
2893             result = NSWritingDirectionLeftToRight;
2894             break;
2895         case RTL:
2896             result = NSWritingDirectionRightToLeft;
2897             break;
2898     }
2899
2900     return result;
2901 }
2902
2903 void FrameMac::tokenizerProcessedData()
2904 {
2905     if (d->m_doc)
2906         checkCompleted();
2907     [_bridge tokenizerProcessedData];
2908 }
2909
2910 void FrameMac::setBridge(WebCoreFrameBridge *bridge)
2911
2912     if (_bridge == bridge)
2913         return;
2914
2915     HardRetain(bridge);
2916     HardRelease(_bridge);
2917     _bridge = bridge;
2918 }
2919
2920 String FrameMac::overrideMediaType() const
2921 {
2922     NSString *overrideType = [_bridge overrideMediaType];
2923     if (overrideType)
2924         return overrideType;
2925     return String();
2926 }
2927
2928 NSColor *FrameMac::bodyBackgroundColor() const
2929 {
2930     if (document() && document()->body() && document()->body()->renderer()) {
2931         Color bgColor = document()->body()->renderer()->style()->backgroundColor();
2932         if (bgColor.isValid())
2933             return nsColor(bgColor);
2934     }
2935     return nil;
2936 }
2937
2938 WebCoreKeyboardUIMode FrameMac::keyboardUIMode() const
2939 {
2940     BEGIN_BLOCK_OBJC_EXCEPTIONS;
2941     return [_bridge keyboardUIMode];
2942     END_BLOCK_OBJC_EXCEPTIONS;
2943
2944     return WebCoreKeyboardAccessDefault;
2945 }
2946
2947 void FrameMac::didTellBridgeAboutLoad(const String& URL)
2948 {
2949     urlsBridgeKnowsAbout.add(URL);
2950 }
2951
2952 bool FrameMac::haveToldBridgeAboutLoad(const String& URL)
2953 {
2954     return urlsBridgeKnowsAbout.contains(URL);
2955 }
2956
2957 void FrameMac::clear()
2958 {
2959     urlsBridgeKnowsAbout.clear();
2960     setMarkedTextRange(0, nil, nil);
2961     Frame::clear();
2962 }
2963
2964 void FrameMac::print()
2965 {
2966     [Mac(this)->_bridge print];
2967 }
2968
2969 KJS::Bindings::Instance *FrameMac::getAppletInstanceForWidget(Widget *widget)
2970 {
2971     NSView *aView = widget->getView();
2972     if (!aView)
2973         return 0;
2974     jobject applet;
2975     
2976     // Get a pointer to the actual Java applet instance.
2977     if ([_bridge respondsToSelector:@selector(getAppletInView:)])
2978         applet = [_bridge getAppletInView:aView];
2979     else
2980         applet = [_bridge pollForAppletInView:aView];
2981     
2982     if (applet) {
2983         // Wrap the Java instance in a language neutral binding and hand
2984         // off ownership to the APPLET element.
2985         KJS::Bindings::RootObject *executionContext = KJS::Bindings::RootObject::findRootObjectForNativeHandleFunction ()(aView);
2986         KJS::Bindings::Instance *instance = KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::JavaLanguage, applet, executionContext);        
2987         return instance;
2988     }
2989     
2990     return 0;
2991 }
2992
2993 static KJS::Bindings::Instance *getInstanceForView(NSView *aView)
2994 {
2995     if ([aView respondsToSelector:@selector(objectForWebScript)]){
2996         id object = [aView objectForWebScript];
2997         if (object) {
2998             KJS::Bindings::RootObject *executionContext = KJS::Bindings::RootObject::findRootObjectForNativeHandleFunction ()(aView);
2999             return KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::ObjectiveCLanguage, object, executionContext);
3000         }
3001     }
3002     else if ([aView respondsToSelector:@selector(createPluginScriptableObject)]) {
3003         NPObject *object = [aView createPluginScriptableObject];
3004         if (object) {
3005             KJS::Bindings::RootObject *executionContext = KJS::Bindings::RootObject::findRootObjectForNativeHandleFunction()(aView);
3006             KJS::Bindings::Instance *instance = KJS::Bindings::Instance::createBindingForLanguageInstance(KJS::Bindings::Instance::CLanguage, object, executionContext);
3007             
3008             // -createPluginScriptableObject returns a retained NPObject.  The caller is expected to release it.
3009             _NPN_ReleaseObject(object);
3010             
3011             return instance;
3012         }
3013     }
3014     return 0;
3015 }
3016
3017 KJS::Bindings::Instance *FrameMac::getEmbedInstanceForWidget(Widget *widget)
3018 {
3019     return getInstanceForView(widget->getView());
3020 }
3021
3022 KJS::Bindings::Instance *FrameMac::getObjectInstanceForWidget(Widget *widget)
3023 {
3024     return getInstanceForView(widget->getView());
3025 }
3026
3027 void FrameMac::addPluginRootObject(KJS::Bindings::RootObject *root)
3028 {
3029     m_rootObjects.append(root);
3030 }
3031
3032 void FrameMac::cleanupPluginObjects()
3033 {
3034     // Delete old plug-in data structures
3035     JSLock lock;
3036     
3037     unsigned count = m_rootObjects.size();
3038     for (unsigned i = 0; i < count; i++)
3039         m_rootObjects[i]->removeAllNativeReferences();
3040     m_rootObjects.clear();
3041     
3042     _bindingRoot = 0;
3043     HardRelease(_windowScriptObject);
3044     _windowScriptObject = 0;
3045     
3046     if (_windowScriptNPObject) {
3047         // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window
3048         // script object properly.
3049         // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
3050         _NPN_DeallocateObject(_windowScriptNPObject);
3051         _windowScriptNPObject = 0;
3052     }
3053 }
3054
3055 void FrameMac::registerCommandForUndoOrRedo(PassRefPtr<EditCommand> cmd, bool isRedo)
3056 {
3057     ASSERT(cmd);
3058     WebUndoAction action = static_cast<WebUndoAction>(cmd->editingAction());
3059     NSUndoManager* undoManager = [_bridge undoManager];
3060     WebCoreEditCommand* command = [WebCoreEditCommand commandWithEditCommand:cmd];
3061     NSString* actionName = [_bridge nameForUndoAction:action];
3062     [undoManager registerUndoWithTarget:_bridge selector:(isRedo ? @selector(redoEditing:) : @selector(undoEditing:)) object:command];
3063     if (actionName)
3064         [undoManager setActionName:actionName];
3065     _haveUndoRedoOperations = YES;
3066 }
3067
3068 void FrameMac::registerCommandForUndo(PassRefPtr<EditCommand> cmd)
3069 {
3070     registerCommandForUndoOrRedo(cmd, false);
3071 }
3072
3073 void FrameMac::registerCommandForRedo(PassRefPtr<EditCommand> cmd)
3074 {
3075     registerCommandForUndoOrRedo(cmd, true);
3076 }
3077
3078 void FrameMac::clearUndoRedoOperations()
3079 {
3080     if (_haveUndoRedoOperations) {
3081         // workaround for <rdar://problem/4645507> NSUndoManager dies
3082         // with uncaught exception when undo items cleared while
3083         // groups are open
3084         NSUndoManager *undoManager = [_bridge undoManager];
3085         int groupingLevel = [undoManager groupingLevel];
3086         for (int i = 0; i < groupingLevel; ++i)
3087             [undoManager endUndoGrouping];
3088         
3089         [undoManager removeAllActionsWithTarget:_bridge];
3090
3091         for (int i = 0; i < groupingLevel; ++i)
3092             [undoManager beginUndoGrouping];
3093
3094         _haveUndoRedoOperations = NO;
3095     }
3096 }
3097
3098 void FrameMac::issueUndoCommand()
3099 {
3100     if (canUndo())
3101         [[_bridge undoManager] undo];
3102 }
3103
3104 void FrameMac::issueRedoCommand()
3105 {
3106     if (canRedo())
3107         [[_bridge undoManager] redo];
3108 }
3109
3110 void FrameMac::issueCutCommand()
3111 {
3112     [_bridge issueCutCommand];
3113 }
3114
3115 void FrameMac::issueCopyCommand()
3116 {
3117     [_bridge issueCopyCommand];
3118 }
3119
3120 void FrameMac::issuePasteCommand()
3121 {
3122     [_bridge issuePasteCommand];
3123 }
3124
3125 void FrameMac::issuePasteAndMatchStyleCommand()
3126 {
3127     [_bridge issuePasteAndMatchStyleCommand];
3128 }
3129
3130 void FrameMac::issueTransposeCommand()
3131 {
3132     [_bridge issueTransposeCommand];
3133 }
3134
3135 bool FrameMac::canUndo() const
3136 {
3137     return [[Mac(this)->_bridge undoManager] canUndo];
3138 }
3139
3140 bool FrameMac::canRedo() const
3141 {
3142     return [[Mac(this)->_bridge undoManager] canRedo];
3143 }
3144
3145 bool FrameMac::canPaste() const
3146 {
3147     return [Mac(this)->_bridge canPaste];
3148 }
3149
3150 void FrameMac::markMisspellingsInAdjacentWords(const VisiblePosition &p)
3151 {
3152     if (![_bridge isContinuousSpellCheckingEnabled])
3153         return;
3154     markMisspellings(Selection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)));
3155 }
3156
3157 void FrameMac::markMisspellings(const Selection& selection)
3158 {
3159     // This function is called with a selection already expanded to word boundaries.
3160     // Might be nice to assert that here.
3161
3162     if (![_bridge isContinuousSpellCheckingEnabled])
3163         return;
3164
3165     RefPtr<Range> searchRange(selection.toRange());
3166     if (!searchRange || searchRange->isDetached())
3167         return;
3168     
3169     // If we're not in an editable node, bail.
3170     int exception = 0;
3171     Node *editableNode = searchRange->startContainer(exception);
3172     if (!editableNode->isContentEditable())
3173         return;
3174     
3175     // Get the spell checker if it is available
3176     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
3177     if (checker == nil)
3178         return;
3179     
3180     WordAwareIterator it(searchRange.get());
3181     
3182     while (!it.atEnd()) {      // we may be starting at the end of the doc, and already by atEnd
3183         const UChar* chars = it.characters();
3184         int len = it.length();
3185         if (len > 1 || !DeprecatedChar(chars[0]).isSpace()) {
3186             NSString *chunk = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(chars) length:len freeWhenDone:NO];
3187             int startIndex = 0;
3188             // Loop over the chunk to find each misspelling in it.
3189             while (startIndex < len) {
3190                 NSRange misspelling = [checker checkSpellingOfString:chunk startingAt:startIndex language:nil wrap:NO inSpellDocumentWithTag:[_bridge spellCheckerDocumentTag] wordCount:NULL];
3191                 if (misspelling.length == 0)
3192                     break;
3193                 else {
3194                     // Build up result range and string.  Note the misspelling may span many text nodes,
3195                     // but the CharIterator insulates us from this complexity
3196                     RefPtr<Range> misspellingRange(rangeOfContents(document()));
3197                     CharacterIterator chars(it.range().get());
3198                     chars.advance(misspelling.location);
3199                     misspellingRange->setStart(chars.range()->startContainer(exception), chars.range()->startOffset(exception), exception);
3200                     chars.advance(misspelling.length);
3201                     misspellingRange->setEnd(chars.range()->startContainer(exception), chars.range()->startOffset(exception), exception);
3202                     // Mark misspelling in document.
3203                     document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
3204                     startIndex = misspelling.location + misspelling.length;
3205                 }
3206             }
3207             [chunk release];
3208         }
3209     
3210         it.advance();
3211     }
3212 }
3213
3214 void FrameMac::respondToChangedSelection(const Selection &oldSelection, bool closeTyping)
3215 {
3216     if (document()) {
3217         if ([_bridge isContinuousSpellCheckingEnabled]) {
3218             Selection oldAdjacentWords;
3219             
3220             // If this is a change in selection resulting from a delete operation, oldSelection may no longer
3221             // be in the document.
3222             if (oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
3223                 VisiblePosition oldStart(oldSelection.visibleStart());
3224                 oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));   
3225             }
3226
3227             VisiblePosition newStart(selectionController()->selection().visibleStart());
3228             Selection newAdjacentWords(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
3229
3230             // When typing we check spelling elsewhere, so don't redo it here.
3231             if (closeTyping && oldAdjacentWords != newAdjacentWords)
3232                 markMisspellings(oldAdjacentWords);
3233
3234             // This only erases a marker in the first word of the selection.
3235             // Perhaps peculiar, but it matches AppKit.
3236             document()->removeMarkers(newAdjacentWords.toRange().get(), DocumentMarker::Spelling);
3237         } else
3238             // When continuous spell checking is off, no markers appear after the selection changes.
3239             document()->removeMarkers(DocumentMarker::Spelling);
3240     }
3241
3242     [_bridge respondToChangedSelection];
3243 }
3244
3245 bool FrameMac::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const
3246 {
3247     return [_bridge shouldChangeSelectedDOMRange:[DOMRange _rangeWith:oldSelection.toRange().get()]
3248                                       toDOMRange:[DOMRange _rangeWith:newSelection.toRange().get()]
3249                                         affinity:static_cast<NSSelectionAffinity>(affinity)
3250                                   stillSelecting:stillSelecting];
3251 }
3252
3253 bool FrameMac::shouldDeleteSelection(const Selection& selection) const
3254 {
3255     return [_bridge shouldDeleteSelectedDOMRange:[DOMRange _rangeWith:selection.toRange().get()]];
3256 }
3257
3258 void FrameMac::respondToChangedContents(const Selection& selection)
3259 {
3260     if (AXObjectCache::accessibilityEnabled()) {
3261         Node* node = selection.start().node();
3262         if (node)
3263             renderer()->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
3264     }
3265     [_bridge respondToChangedContents];
3266 }
3267
3268 bool FrameMac::isContentEditable() const
3269 {
3270     return Frame::isContentEditable() || [_bridge isEditable];
3271 }
3272
3273 bool FrameMac::shouldBeginEditing(const Range *range) const
3274 {
3275     ASSERT(range);
3276     return [_bridge shouldBeginEditing:[DOMRange _rangeWith:const_cast<Range*>(range)]];
3277 }
3278
3279 bool FrameMac::shouldEndEditing(const Range *range) const
3280 {
3281     ASSERT(range);
3282     return [_bridge shouldEndEditing:[DOMRange _rangeWith:const_cast<Range*>(range)]];
3283 }
3284
3285 void FrameMac::didBeginEditing() const
3286 {
3287     [_bridge didBeginEditing];
3288 }
3289
3290 void FrameMac::didEndEditing() const
3291 {
3292     [_bridge didEndEditing];
3293 }
3294
3295 void FrameMac::textFieldDidBeginEditing(Element* input)
3296 {
3297     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3298     [_bridge textFieldDidBeginEditing:(DOMHTMLInputElement *)[DOMElement _elementWith:input]];
3299     END_BLOCK_OBJC_EXCEPTIONS;
3300 }
3301
3302 void FrameMac::textFieldDidEndEditing(Element* input)
3303 {
3304     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3305     [_bridge textFieldDidEndEditing:(DOMHTMLInputElement *)[DOMElement _elementWith:input]];
3306     END_BLOCK_OBJC_EXCEPTIONS;
3307 }
3308
3309 void FrameMac::textDidChangeInTextField(Element* input)
3310 {
3311     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3312     [_bridge textDidChangeInTextField:(DOMHTMLInputElement *)[DOMElement _elementWith:input]];
3313     END_BLOCK_OBJC_EXCEPTIONS;
3314 }
3315
3316 void FrameMac::textDidChangeInTextArea(Element* textarea)
3317 {
3318     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3319     [_bridge textDidChangeInTextArea:(DOMHTMLTextAreaElement *)[DOMElement _elementWith:textarea]];
3320     END_BLOCK_OBJC_EXCEPTIONS;
3321 }
3322
3323 bool FrameMac::doTextFieldCommandFromEvent(Element* input, const PlatformKeyboardEvent* event)
3324 {
3325     // FIXME: We might eventually need to make sure key bindings for editing work even with
3326     // events created with the DOM API. Those don't have a PlatformKeyboardEvent.
3327     if (!event)
3328         return false;
3329
3330     BOOL result = false;
3331     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3332     SEL selector = selectorForKeyEvent(event);
3333     if (selector)
3334         result = [_bridge textField:(DOMHTMLInputElement *)[DOMElement _elementWith:input] doCommandBySelector:selector];
3335     END_BLOCK_OBJC_EXCEPTIONS;
3336     return result;
3337 }
3338
3339 void FrameMac::textWillBeDeletedInTextField(Element* input)
3340 {
3341     // We're using the deleteBackward selector for all deletion operations since the autofill code treats all deletions the same way.
3342     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3343     [_bridge textField:(DOMHTMLInputElement *)[DOMElement _elementWith:input] doCommandBySelector:@selector(deleteBackward:)];
3344     END_BLOCK_OBJC_EXCEPTIONS;
3345 }
3346
3347 bool FrameMac::inputManagerHasMarkedText() const
3348 {
3349     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3350     return [[NSInputManager currentInputManager] hasMarkedText];
3351     END_BLOCK_OBJC_EXCEPTIONS
3352     return false;
3353 }
3354
3355 const short enableRomanKeyboardsOnly = -23;
3356 void FrameMac::setSecureKeyboardEntry(bool enable)
3357 {
3358     if (enable) {
3359         EnableSecureEventInput();
3360 // FIXME: KeyScript is deprecated in Leopard, we need a new solution for this <rdar://problem/4727607>
3361 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
3362         KeyScript(enableRomanKeyboardsOnly);
3363 #endif
3364     } else {
3365         DisableSecureEventInput();
3366 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
3367         KeyScript(smKeyEnableKybds);
3368 #endif
3369     }
3370 }
3371
3372 bool FrameMac::isSecureKeyboardEntry()
3373 {
3374     return IsSecureEventInputEnabled();
3375 }
3376
3377 static void convertAttributesToUnderlines(Vector<MarkedTextUnderline>& result, const Range *markedTextRange, NSArray *attributes, NSArray *ranges)
3378 {
3379     int exception = 0;
3380     int baseOffset = markedTextRange->startOffset(exception);
3381
3382     unsigned length = [attributes count];
3383     ASSERT([ranges count] == length);
3384
3385     for (unsigned i = 0; i < length; i++) {
3386         NSNumber *style = [[attributes objectAtIndex:i] objectForKey:NSUnderlineStyleAttributeName];
3387         if (!style)
3388             continue;
3389         NSRange range = [[ranges objectAtIndex:i] rangeValue];
3390         NSColor *color = [[attributes objectAtIndex:i] objectForKey:NSUnderlineColorAttributeName];
3391         Color qColor = Color::black;
3392         if (color) {
3393             NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
3394             qColor = Color(makeRGBA((int)(255 * [deviceColor redComponent]),
3395                                     (int)(255 * [deviceColor blueComponent]),
3396                                     (int)(255 * [deviceColor greenComponent]),
3397                                     (int)(255 * [deviceColor alphaComponent])));
3398         }
3399
3400         result.append(MarkedTextUnderline(range.location + baseOffset, 
3401                                           range.location + baseOffset + range.length, 
3402                                           qColor,
3403                                           [style intValue] > 1));
3404     }
3405 }
3406
3407 void FrameMac::setMarkedTextRange(const Range *range, NSArray *attributes, NSArray *ranges)
3408 {
3409     int exception = 0;
3410
3411     ASSERT(!range || range->startContainer(exception) == range->endContainer(exception));
3412     ASSERT(!range || range->collapsed(exception) || range->startContainer(exception)->isTextNode());
3413
3414     d->m_markedTextUnderlines.clear();
3415     if (attributes == nil)
3416         d->m_markedTextUsesUnderlines = false;
3417     else {
3418         d->m_markedTextUsesUnderlines = true;
3419         convertAttributesToUnderlines(d->m_markedTextUnderlines, range, attributes, ranges);
3420     }
3421
3422     if (m_markedTextRange.get() && document() && m_markedTextRange->startContainer(exception)->renderer())
3423         m_markedTextRange->startContainer(exception)->renderer()->repaint();
3424
3425     if (range && range->collapsed(exception))
3426         m_markedTextRange = 0;
3427     else
3428         m_markedTextRange = const_cast<Range*>(range);
3429
3430     if (m_markedTextRange.get() && document() && m_markedTextRange->startContainer(exception)->renderer())
3431         m_markedTextRange->startContainer(exception)->renderer()->repaint();
3432 }
3433
3434 bool FrameMac::canGoBackOrForward(int distance) const
3435 {
3436     return [_bridge canGoBackOrForward:distance];
3437 }
3438
3439 void FrameMac::didFirstLayout()
3440 {
3441     [_bridge didFirstLayout];
3442 }
3443
3444 NSMutableDictionary *FrameMac::dashboardRegionsDictionary()
3445 {
3446     Document *doc = document();
3447     if (!doc)
3448         return nil;
3449
3450     const Vector<DashboardRegionValue>& regions = doc->dashboardRegions();
3451     size_t n = regions.size();
3452
3453     // Convert the DeprecatedValueList<DashboardRegionValue> into a NSDictionary of WebDashboardRegions
3454     NSMutableDictionary *webRegions = [NSMutableDictionary dictionaryWithCapacity:n];
3455     for (size_t i = 0; i < n; i++) {
3456         const DashboardRegionValue& region = regions[i];
3457
3458         if (region.type == StyleDashboardRegion::None)
3459             continue;
3460         
3461         NSString *label = region.label;
3462         WebDashboardRegionType type = WebDashboardRegionTypeNone;
3463         if (region.type == StyleDashboardRegion::Circle)
3464             type = WebDashboardRegionTypeCircle;
3465         else if (region.type == StyleDashboardRegion::Rectangle)
3466             type = WebDashboardRegionTypeRectangle;
3467         NSMutableArray *regionValues = [webRegions objectForKey:label];
3468         if (!regionValues) {
3469             regionValues = [[NSMutableArray alloc] initWithCapacity:1];
3470             [webRegions setObject:regionValues forKey:label];
3471             [regionValues release];
3472         }
3473         
3474         WebDashboardRegion *webRegion = [[WebDashboardRegion alloc] initWithRect:region.bounds clip:region.clip type:type];
3475         [regionValues addObject:webRegion];
3476         [webRegion release];
3477     }
3478     
3479     return webRegions;
3480 }
3481
3482 void FrameMac::dashboardRegionsChanged()
3483 {
3484     NSMutableDictionary *webRegions = dashboardRegionsDictionary();
3485     [_bridge dashboardRegionsChanged:webRegions];
3486 }
3487
3488 bool FrameMac::isCharacterSmartReplaceExempt(UChar c, bool isPreviousChar)
3489 {
3490     return [_bridge isCharacterSmartReplaceExempt:c isPreviousCharacter:isPreviousChar];
3491 }
3492
3493 void FrameMac::handledOnloadEvents()
3494 {
3495     [_bridge handledOnloadEvents];
3496 }
3497
3498 bool FrameMac::shouldClose()
3499 {
3500     BEGIN_BLOCK_OBJC_EXCEPTIONS;
3501
3502     if (![_bridge canRunBeforeUnloadConfirmPanel])
3503         return true;
3504
3505     RefPtr<Document> doc = document();
3506     if (!doc)
3507         return true;
3508     HTMLElement* body = doc->body();
3509     if (!body)
3510         return true;
3511
3512     RefPtr<BeforeUnloadEvent> event = new BeforeUnloadEvent;
3513     event->setTarget(doc.get());
3514     doc->handleWindowEvent(event.get(), false);
3515
3516     if (!event->defaultPrevented() && doc)
3517         doc->defaultEventHandler(event.get());
3518     if (event->result().isNull())
3519         return true;
3520
3521     String text = event->result();
3522     text.replace('\\', backslashAsCurrencySymbol());
3523
3524     return [_bridge runBeforeUnloadConfirmPanelWithMessage:text];
3525
3526     END_BLOCK_OBJC_EXCEPTIONS;
3527
3528     return true;
3529 }
3530
3531 void FrameMac::dragSourceMovedTo(const PlatformMouseEvent& event)
3532 {
3533     if (_dragSrc && _dragSrcMayBeDHTML)
3534         // for now we don't care if event handler cancels default behavior, since there is none
3535         dispatchDragSrcEvent(dragEvent, event);
3536 }
3537
3538 void FrameMac::dragSourceEndedAt(const PlatformMouseEvent& event, NSDragOperation operation)
3539 {
3540     if (_dragSrc && _dragSrcMayBeDHTML) {
3541         _dragClipboard->setDestinationOperation(operation);
3542         // for now we don't care if event handler cancels default behavior, since there is none
3543         dispatchDragSrcEvent(dragendEvent, event);
3544     }
3545     freeClipboard();
3546     _dragSrc = 0;
3547 }
3548
3549 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3550 bool FrameMac::dispatchDragSrcEvent(const AtomicString &eventType, const PlatformMouseEvent& event) const
3551 {
3552     bool noDefaultProc = d->m_view->dispatchDragEvent(eventType, _dragSrc.get(), event, _dragClipboard.get());
3553     return !noDefaultProc;
3554 }
3555
3556 void Frame::setNeedsReapplyStyles()
3557 {
3558     [Mac(this)->bridge() setNeedsReapplyStyles];
3559 }
3560
3561 FloatRect FrameMac::customHighlightLineRect(const AtomicString& type, const FloatRect& lineRect)
3562 {
3563     return [bridge() customHighlightRect:type forLine:lineRect];
3564 }
3565
3566 void FrameMac::paintCustomHighlight(const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect, bool text, bool line)
3567 {
3568     [bridge() paintCustomHighlight:type forBox:boxRect onLine:lineRect behindText:text entireLine:line];
3569 }
3570
3571 KURL FrameMac::originalRequestURL() const
3572 {
3573     return [_bridge originalRequestURL];
3574 }
3575
3576 bool FrameMac::isLoadTypeReload()
3577 {
3578     return [_bridge isLoadTypeReload];
3579 }
3580
3581 }