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