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