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