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