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