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