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