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