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