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