7bfaff6422e30d12ae34d89aa7ae970b0fcd5a9a
[WebKit-https.git] / WebCore / kwq / KWQKHTMLPart.mm
1 /*
2  * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "KWQKHTMLPart.h"
27
28 #import "DOMInternal.h"
29 #import "KWQDOMNode.h"
30 #import "KWQDummyView.h"
31 #import "KWQEditCommand.h"
32 #import "KWQExceptions.h"
33 #import "KWQKJobClasses.h"
34 #import "KWQLogging.h"
35 #import "KWQPageState.h"
36 #import "KWQPrinter.h"
37 #import "KWQScrollBar.h"
38 #import "KWQWindowWidget.h"
39 #import "WebCoreBridge.h"
40 #import "WebCoreViewFactory.h"
41 #import "csshelper.h"
42 #import "dom2_eventsimpl.h"
43 #import "dom2_rangeimpl.h"
44 #import "dom_selection.h"
45 #import "html_documentimpl.h"
46 #import "html_misc.h"
47 #import "htmlattrs.h"
48 #import "htmltokenizer.h"
49 #import "khtml_text_operations.h"
50 #import "khtmlpart_p.h"
51 #import "khtmlview.h"
52 #import "kjs_binding.h"
53 #import "kjs_window.h"
54 #import "render_canvas.h"
55 #import "render_frames.h"
56 #import "render_image.h"
57 #import "render_list.h"
58 #import "render_style.h"
59 #import "render_table.h"
60 #import "render_text.h"
61 #import <JavaScriptCore/identifier.h>
62 #import <JavaScriptCore/property_map.h>
63 #import <JavaScriptCore/runtime.h>
64 #import <JavaScriptCore/runtime_root.h>
65
66 #undef _KWQ_TIMING
67
68 using DOM::AtomicString;
69 using DOM::DocumentImpl;
70 using DOM::DOMString;
71 using DOM::ElementImpl;
72 using DOM::EventImpl;
73 using DOM::HTMLDocumentImpl;
74 using DOM::HTMLElementImpl;
75 using DOM::HTMLFormElementImpl;
76 using DOM::HTMLFrameElementImpl;
77 using DOM::HTMLGenericFormElementImpl;
78 using DOM::HTMLTableCellElementImpl;
79 using DOM::Node;
80 using DOM::NodeImpl;
81 using DOM::Range;
82 using DOM::RangeImpl;
83 using DOM::Selection;
84
85 using khtml::Cache;
86 using khtml::ChildFrame;
87 using khtml::Decoder;
88 using khtml::findPlainText;
89 using khtml::InlineTextBox;
90 using khtml::MouseDoubleClickEvent;
91 using khtml::MouseMoveEvent;
92 using khtml::MousePressEvent;
93 using khtml::MouseReleaseEvent;
94 using khtml::parseURL;
95 using khtml::PRE;
96 using khtml::RenderCanvas;
97 using khtml::RenderImage;
98 using khtml::RenderLayer;
99 using khtml::RenderListItem;
100 using khtml::RenderObject;
101 using khtml::RenderPart;
102 using khtml::RenderStyle;
103 using khtml::RenderTableCell;
104 using khtml::RenderText;
105 using khtml::RenderWidget;
106 using khtml::VISIBLE;
107
108 using KIO::Job;
109
110 using KJS::Interpreter;
111 using KJS::Location;
112 using KJS::SavedBuiltins;
113 using KJS::SavedProperties;
114 using KJS::ScheduledAction;
115 using KJS::Window;
116
117 using KJS::Bindings::Instance;
118
119 using KParts::ReadOnlyPart;
120 using KParts::URLArgs;
121
122 NSEvent *KWQKHTMLPart::_currentEvent = nil;
123 NSResponder *KWQKHTMLPart::_firstResponderAtMouseDownTime = nil;
124
125 void KHTMLPart::completed()
126 {
127     KWQ(this)->_completed.call();
128 }
129
130 void KHTMLPart::completed(bool arg)
131 {
132     KWQ(this)->_completed.call(arg);
133 }
134
135 void KHTMLPart::nodeActivated(const Node &)
136 {
137 }
138
139 bool KHTMLPart::openURL(const KURL &URL)
140 {
141     ASSERT_NOT_REACHED();
142     return true;
143 }
144
145 void KHTMLPart::onURL(const QString &)
146 {
147 }
148
149 void KHTMLPart::setStatusBarText(const QString &status)
150 {
151     KWQ(this)->setStatusBarText(status);
152 }
153
154 void KHTMLPart::started(Job *j)
155 {
156     KWQ(this)->_started.call(j);
157 }
158
159 static void redirectionTimerMonitor(void *context)
160 {
161     KWQKHTMLPart *kwq = static_cast<KWQKHTMLPart *>(context);
162     kwq->redirectionTimerStartedOrStopped();
163 }
164
165 KWQKHTMLPart::KWQKHTMLPart()
166     : _started(this, SIGNAL(started(KIO::Job *)))
167     , _completed(this, SIGNAL(completed()))
168     , _completedWithBool(this, SIGNAL(completed(bool)))
169     , _mouseDownView(nil)
170     , _sendingEventToSubview(false)
171     , _mouseDownMayStartDrag(false)
172     , _mouseDownMayStartSelect(false)
173     , _formValuesAboutToBeSubmitted(nil)
174     , _formAboutToBeSubmitted(nil)
175     , _windowWidget(NULL)
176     , _usesInactiveTextBackgroundColor(false)
177     , _showsFirstResponder(true)
178 {
179     // Must init the cache before connecting to any signals
180     Cache::init();
181
182     // The widget is made outside this class in our case.
183     KHTMLPart::init( 0, DefaultGUI );
184
185     mutableInstances().prepend(this);
186     d->m_redirectionTimer.setMonitor(redirectionTimerMonitor, this);
187 }
188
189 KWQKHTMLPart::~KWQKHTMLPart()
190 {
191     cleanupPluginRootObjects();
192     
193     mutableInstances().remove(this);
194     if (d->m_view) {
195         d->m_view->deref();
196     }
197     // these are all basic Foundation classes and our own classes - we
198     // know they will not raise in dealloc, so no need to block
199     // exceptions.
200     [_formValuesAboutToBeSubmitted release];
201     [_formAboutToBeSubmitted release];
202     delete _windowWidget;
203 }
204
205 void KWQKHTMLPart::setSettings (KHTMLSettings *settings)
206 {
207     d->m_settings = settings;
208 }
209
210 QString KWQKHTMLPart::generateFrameName()
211 {
212     KWQ_BLOCK_EXCEPTIONS;
213     return QString::fromNSString([_bridge generateFrameName]);
214     KWQ_UNBLOCK_EXCEPTIONS;
215
216     return QString();
217 }
218
219 void KWQKHTMLPart::provisionalLoadStarted()
220 {
221     // we don't want to wait until we get an actual http response back
222     // to cancel pending redirects, otherwise they might fire before
223     // that happens.
224     cancelRedirection(true);
225 }
226
227 bool KWQKHTMLPart::openURL(const KURL &url)
228 {
229     KWQ_BLOCK_EXCEPTIONS;
230
231     bool onLoad = false;
232     
233     if (jScript() && jScript()->interpreter()) {
234         KHTMLPart *rootPart = this;
235         while (rootPart->parentPart() != 0)
236             rootPart = rootPart->parentPart();
237         KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(KJSProxy::proxy(rootPart)->interpreter());
238         DOM::Event *evt = interpreter->getCurrentEvent();
239         
240         if (evt) {
241             onLoad = (evt->type() == "load");
242         }
243     }
244
245     // FIXME: The lack of args here to get the reload flag from
246     // indicates a problem in how we use KHTMLPart::processObjectRequest,
247     // where we are opening the URL before the args are set up.
248     [_bridge loadURL:url.getNSURL()
249             referrer:[_bridge referrer]
250               reload:NO
251               onLoadEvent:onLoad
252               target:nil
253      triggeringEvent:nil
254                 form:nil
255           formValues:nil];
256
257     KWQ_UNBLOCK_EXCEPTIONS;
258
259     return true;
260 }
261
262 void KWQKHTMLPart::openURLRequest(const KURL &url, const URLArgs &args)
263 {
264     KWQ_BLOCK_EXCEPTIONS;
265
266     [_bridge loadURL:url.getNSURL()
267             referrer:[_bridge referrer]
268               reload:args.reload
269               onLoadEvent:false
270               target:args.frameName.getNSString()
271      triggeringEvent:nil
272                 form:nil
273           formValues:nil];
274
275     KWQ_UNBLOCK_EXCEPTIONS;
276 }
277
278 void KWQKHTMLPart::didNotOpenURL(const KURL &URL)
279 {
280     if (_submittedFormURL == URL) {
281         _submittedFormURL = KURL();
282     }
283 }
284
285 // Scans logically forward from "start", including any child frames
286 static HTMLFormElementImpl *scanForForm(NodeImpl *start)
287 {
288     NodeImpl *n;
289     for (n = start; n; n = n->traverseNextNode()) {
290         NodeImpl::Id nodeID = idFromNode(n);
291         if (nodeID == ID_FORM) {
292             return static_cast<HTMLFormElementImpl *>(n);
293         } else if (n->isHTMLElement()
294                    && static_cast<HTMLElementImpl *>(n)->isGenericFormElement()) {
295             return static_cast<HTMLGenericFormElementImpl *>(n)->form();
296         } else if (nodeID == ID_FRAME || nodeID == ID_IFRAME) {
297             NodeImpl *childDoc = static_cast<HTMLFrameElementImpl *>(n)->contentDocument();
298             HTMLFormElementImpl *frameResult = scanForForm(childDoc);
299             if (frameResult) {
300                 return frameResult;
301             }
302         }
303     }
304     return 0;
305 }
306
307 // We look for either the form containing the current focus, or for one immediately after it
308 HTMLFormElementImpl *KWQKHTMLPart::currentForm() const
309 {
310     // start looking either at the active (first responder) node, or where the selection is
311     NodeImpl *start = activeNode().handle();
312     if (!start) {
313         start = selectionStart();
314     }
315
316     // try walking up the node tree to find a form element
317     NodeImpl *n;
318     for (n = start; n; n = n->parentNode()) {
319         if (idFromNode(n) == ID_FORM) {
320             return static_cast<HTMLFormElementImpl *>(n);
321         } else if (n->isHTMLElement()
322                    && static_cast<HTMLElementImpl *>(n)->isGenericFormElement()) {
323             return static_cast<HTMLGenericFormElementImpl *>(n)->form();
324         }
325     }
326
327     // try walking forward in the node tree to find a form element
328     if (!start) {
329         start = xmlDocImpl();
330     }
331     return scanForForm(start);
332 }
333
334 // Either get cached regexp or build one that matches any of the labels.
335 // The regexp we build is of the form:  (STR1|STR2|STRN)
336 QRegExp *regExpForLabels(NSArray *labels)
337 {
338     // All the ObjC calls in this method are simple array and string
339     // calls which we can assume do not raise exceptions
340
341
342     // Parallel arrays that we use to cache regExps.  In practice the number of expressions
343     // that the app will use is equal to the number of locales is used in searching.
344     static const unsigned int regExpCacheSize = 4;
345     static NSMutableArray *regExpLabels = nil;
346     static QPtrList <QRegExp> regExps;
347     static QRegExp wordRegExp = QRegExp("\\w");
348
349     QRegExp *result;
350     if (!regExpLabels) {
351         regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
352     }
353     unsigned int cacheHit = [regExpLabels indexOfObject:labels];
354     if (cacheHit != NSNotFound) {
355         result = regExps.at(cacheHit);
356     } else {
357         QString pattern("(");
358         unsigned int numLabels = [labels count];
359         unsigned int i;
360         for (i = 0; i < numLabels; i++) {
361             QString label = QString::fromNSString([labels objectAtIndex:i]);
362
363             bool startsWithWordChar = false;
364             bool endsWithWordChar = false;
365             if (label.length() != 0) {
366                 startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
367                 endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
368             }
369             
370             if (i != 0) {
371                 pattern.append("|");
372             }
373             // Search for word boundaries only if label starts/ends with "word characters".
374             // If we always searched for word boundaries, this wouldn't work for languages
375             // such as Japanese.
376             if (startsWithWordChar) {
377                 pattern.append("\\b");
378             }
379             pattern.append(label);
380             if (endsWithWordChar) {
381                 pattern.append("\\b");
382             }
383         }
384         pattern.append(")");
385         result = new QRegExp(pattern, false);
386     }
387
388     // add regexp to the cache, making sure it is at the front for LRU ordering
389     if (cacheHit != 0) {
390         if (cacheHit != NSNotFound) {
391             // remove from old spot
392             [regExpLabels removeObjectAtIndex:cacheHit];
393             regExps.remove(cacheHit);
394         }
395         // add to start
396         [regExpLabels insertObject:labels atIndex:0];
397         regExps.insert(0, result);
398         // trim if too big
399         if ([regExpLabels count] > regExpCacheSize) {
400             [regExpLabels removeObjectAtIndex:regExpCacheSize];
401             QRegExp *last = regExps.last();
402             regExps.removeLast();
403             delete last;
404         }
405     }
406     return result;
407 }
408
409 NSString *KWQKHTMLPart::searchForLabelsAboveCell(QRegExp *regExp, HTMLTableCellElementImpl *cell)
410 {
411     RenderTableCell *cellRenderer = static_cast<RenderTableCell *>(cell->renderer());
412     RenderTableCell *cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
413
414     if (cellAboveRenderer) {
415         HTMLTableCellElementImpl *aboveCell =
416             static_cast<HTMLTableCellElementImpl *>(cellAboveRenderer->element());
417
418         if (aboveCell) {
419             // search within the above cell we found for a match
420             for (NodeImpl *n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
421                 if (idFromNode(n) == ID_TEXT
422                     && n->renderer() && n->renderer()->style()->visibility() == VISIBLE)
423                 {
424                     // For each text chunk, run the regexp
425                     QString nodeString = n->nodeValue().string();
426                     int pos = regExp->searchRev(nodeString);
427                     if (pos >= 0) {
428                         return nodeString.mid(pos, regExp->matchedLength()).getNSString();
429                     }
430                 }
431             }
432         }
433     }
434     // Any reason in practice to search all cells in that are above cell?
435     return nil;
436 }
437
438 NSString *KWQKHTMLPart::searchForLabelsBeforeElement(NSArray *labels, ElementImpl *element)
439 {
440     QRegExp *regExp = regExpForLabels(labels);
441     // We stop searching after we've seen this many chars
442     const unsigned int charsSearchedThreshold = 500;
443     // This is the absolute max we search.  We allow a little more slop than
444     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
445     const unsigned int maxCharsSearched = 600;
446     // If the starting element is within a table, the cell that contains it
447     HTMLTableCellElementImpl *startingTableCell = 0;
448     bool searchedCellAbove = false;
449
450     // walk backwards in the node tree, until another element, or form, or end of tree
451     int unsigned lengthSearched = 0;
452     NodeImpl *n;
453     for (n = element->traversePreviousNode();
454          n && lengthSearched < charsSearchedThreshold;
455          n = n->traversePreviousNode())
456     {
457         NodeImpl::Id nodeID = idFromNode(n);
458         if (nodeID == ID_FORM
459             || (n->isHTMLElement()
460                 && static_cast<HTMLElementImpl *>(n)->isGenericFormElement()))
461         {
462             // We hit another form element or the start of the form - bail out
463             break;
464         } else if (nodeID == ID_TD && !startingTableCell) {
465             startingTableCell = static_cast<HTMLTableCellElementImpl *>(n);
466         } else if (nodeID == ID_TR && startingTableCell) {
467             NSString *result = searchForLabelsAboveCell(regExp, startingTableCell);
468             if (result) {
469                 return result;
470             }
471             searchedCellAbove = true;
472         } else if (nodeID == 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             // add 100 for slop, to make it more likely that we'll search whole nodes
478             if (lengthSearched + nodeString.length() > maxCharsSearched) {
479                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
480             }
481             int pos = regExp->searchRev(nodeString);
482             if (pos >= 0) {
483                 return nodeString.mid(pos, regExp->matchedLength()).getNSString();
484             } else {
485                 lengthSearched += nodeString.length();
486             }
487         }
488     }
489
490     // If we started in a cell, but bailed because we found the start of the form or the
491     // previous element, we still might need to search the row above us for a label.
492     if (startingTableCell && !searchedCellAbove) {
493          return searchForLabelsAboveCell(regExp, startingTableCell);
494     } else {
495         return nil;
496     }
497 }
498
499 NSString *KWQKHTMLPart::matchLabelsAgainstElement(NSArray *labels, ElementImpl *element)
500 {
501     QString name = element->getAttribute(ATTR_NAME).string();
502     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
503     name.replace(QRegExp("[[:digit:]]"), " ");
504     name.replace("_", " ");
505     
506     QRegExp *regExp = regExpForLabels(labels);
507     // Use the largest match we can find in the whole name string
508     int pos;
509     int length;
510     int bestPos = -1;
511     int bestLength = -1;
512     int start = 0;
513     do {
514         pos = regExp->search(name, start);
515         if (pos != -1) {
516             length = regExp->matchedLength();
517             if (length >= bestLength) {
518                 bestPos = pos;
519                 bestLength = length;
520             }
521             start = pos+1;
522         }
523     } while (pos != -1);
524
525     if (bestPos != -1) {
526         return name.mid(bestPos, bestLength).getNSString();
527     } else {
528         return nil;
529     }
530 }
531
532 // Search from the end of the currently selected location if we are first responder, or from
533 // the beginning of the document if nothing is selected or we're not first responder.
534 bool KWQKHTMLPart::findString(NSString *string, bool forward, bool caseFlag, bool wrapFlag)
535 {
536     QString target = QString::fromNSString(string);
537     if (target.isEmpty()) {
538         return false;
539     }
540
541     // Start on the correct edge of the selection, search to edge of document.
542     Range searchRange(xmlDocImpl());
543     searchRange.selectNodeContents(xmlDocImpl());
544     if (selectionStart()) {
545         if (forward) {
546             searchRange.setStart(selectionEnd(), selectionEndOffset());
547         } else {
548             searchRange.setEnd(selectionStart(), selectionStartOffset());
549         }
550     }
551
552     // Do the search once, then do it a second time to handle wrapped search.
553     // Searches some or all of document twice in the failure case, but that's probably OK.
554     Range resultRange = findPlainText(searchRange, target, forward, caseFlag);
555     if (resultRange.collapsed() && wrapFlag) {
556         searchRange.selectNodeContents(xmlDocImpl());
557         resultRange = findPlainText(searchRange, target, forward, caseFlag);
558         // If we got back to the same place we started, that doesn't count as success.
559         if (resultRange == selection().toRange()) {
560             return false;
561         }
562     }
563
564     if (resultRange.collapsed()) {
565         return false;
566     }
567
568     setSelection(resultRange);
569     jumpToSelection();
570     return true;
571 }
572
573 void KWQKHTMLPart::clearRecordedFormValues()
574 {
575     // It's safe to assume that our own classes and Foundation data
576     // structures won't raise exceptions in dealloc
577
578     [_formValuesAboutToBeSubmitted release];
579     _formValuesAboutToBeSubmitted = nil;
580     [_formAboutToBeSubmitted release];
581     _formAboutToBeSubmitted = nil;
582 }
583
584 void KWQKHTMLPart::recordFormValue(const QString &name, const QString &value, HTMLFormElementImpl *element)
585 {
586     // It's safe to assume that our own classes and basic Foundation
587     // data structures won't raise exceptions
588
589     if (!_formValuesAboutToBeSubmitted) {
590         _formValuesAboutToBeSubmitted = [[NSMutableDictionary alloc] init];
591         ASSERT(!_formAboutToBeSubmitted);
592         _formAboutToBeSubmitted = [[DOMElement _elementWithImpl:element] retain];
593     } else {
594         ASSERT([_formAboutToBeSubmitted _elementImpl] == element);
595     }
596     [_formValuesAboutToBeSubmitted setObject:value.getNSString() forKey:name.getNSString()];
597 }
598
599 void KWQKHTMLPart::submitForm(const KURL &url, const URLArgs &args)
600 {
601     KWQ_BLOCK_EXCEPTIONS;
602
603     // The form multi-submit logic here is only right when we are submitting a form that affects this frame.
604     // Eventually when we find a better fix we can remove this altogether.
605     WebCoreBridge *target = args.frameName.isEmpty() ? _bridge : [_bridge findFrameNamed:args.frameName.getNSString()];
606     KHTMLPart *targetPart = [target part];
607     bool willReplaceThisFrame = false;
608     for (KHTMLPart *p = this; p; p = p->parentPart()) {
609         if (p == targetPart) {
610             willReplaceThisFrame = true;
611             break;
612         }
613     }
614     if (willReplaceThisFrame) {
615         // We do not want to submit more than one form from the same page,
616         // nor do we want to submit a single form more than once.
617         // This flag prevents these from happening.
618         // Note that the flag is reset in setView()
619         // since this part may get reused if it is pulled from the b/f cache.
620         if (_submittedFormURL == url) {
621             return;
622         }
623         _submittedFormURL = url;
624     }
625
626     if (!args.doPost()) {
627         [_bridge loadURL:url.getNSURL()
628                 referrer:[_bridge referrer] 
629                   reload:args.reload
630              onLoadEvent:false
631                   target:args.frameName.getNSString()
632          triggeringEvent:_currentEvent
633                     form:_formAboutToBeSubmitted
634               formValues:_formValuesAboutToBeSubmitted];
635     } else {
636         ASSERT(args.contentType().startsWith("Content-Type: "));
637         [_bridge postWithURL:url.getNSURL()
638                     referrer:[_bridge referrer] 
639                       target:args.frameName.getNSString()
640                         data:[NSData dataWithBytes:args.postData.data() length:args.postData.size()]
641                  contentType:args.contentType().mid(14).getNSString()
642              triggeringEvent:_currentEvent
643                         form:_formAboutToBeSubmitted
644                   formValues:_formValuesAboutToBeSubmitted];
645     }
646     clearRecordedFormValues();
647
648     KWQ_UNBLOCK_EXCEPTIONS;
649 }
650
651 void KWQKHTMLPart::setEncoding(const QString &name, bool userChosen)
652 {
653     if (!d->m_workingURL.isEmpty()) {
654         receivedFirstData();
655     }
656     d->m_encoding = name;
657     d->m_haveEncoding = userChosen;
658 }
659
660 void KWQKHTMLPart::addData(const char *bytes, int length)
661 {
662     ASSERT(d->m_workingURL.isEmpty());
663     ASSERT(d->m_doc);
664     ASSERT(d->m_doc->parsing());
665     write(bytes, length);
666 }
667
668 void KHTMLPart::frameDetached()
669 {
670     KWQ_BLOCK_EXCEPTIONS;
671     [KWQ(this)->bridge() frameDetached];
672     KWQ_UNBLOCK_EXCEPTIONS;
673
674     // FIXME: There may be a better place to do this that works for KHTML too.
675     KHTMLPart *parent = parentPart();
676     if (parent) {
677         FrameList& parentFrames = parent->d->m_frames;
678         FrameIt end = parentFrames.end();
679         for (FrameIt it = parentFrames.begin(); it != end; ++it) {
680             if ((*it).m_part == this) {
681                 parentFrames.remove(it);
682                 deref();
683                 break;
684             }
685         }
686     }
687 }
688
689 void KWQKHTMLPart::urlSelected(const KURL &url, int button, int state, const URLArgs &args)
690 {
691     KWQ_BLOCK_EXCEPTIONS;
692     [_bridge loadURL:url.getNSURL()
693             referrer:[_bridge referrer]
694               reload:args.reload
695          onLoadEvent:false
696               target:args.frameName.getNSString()
697      triggeringEvent:_currentEvent
698                 form:nil
699           formValues:nil];
700     KWQ_UNBLOCK_EXCEPTIONS;
701 }
702
703 class KWQPluginPart : public ReadOnlyPart
704 {
705     virtual bool openURL(const KURL &) { return true; }
706     virtual bool closeURL() { return true; }
707 };
708
709 ReadOnlyPart *KWQKHTMLPart::createPart(const ChildFrame &child, const KURL &url, const QString &mimeType)
710 {
711     KWQ_BLOCK_EXCEPTIONS;
712     ReadOnlyPart *part;
713
714     BOOL needFrame = [_bridge frameRequiredForMIMEType:mimeType.getNSString() URL:url.getNSURL()];
715     if (child.m_type == ChildFrame::Object && !needFrame) {
716         NSMutableArray *attributesArray = [NSMutableArray arrayWithCapacity:child.m_params.count()];
717         for (uint i = 0; i < child.m_params.count(); i++) {
718             [attributesArray addObject:child.m_params[i].getNSString()];
719         }
720         
721         KWQPluginPart *newPart = new KWQPluginPart;
722         newPart->setWidget(new QWidget([_bridge viewForPluginWithURL:url.getNSURL()
723                                                           attributes:attributesArray
724                                                              baseURL:KURL(d->m_doc->baseURL()).getNSURL()
725                                                             MIMEType:child.m_args.serviceType.getNSString()]));
726         part = newPart;
727     } else {
728         LOG(Frames, "name %s", child.m_name.ascii());
729         BOOL allowsScrolling = YES;
730         int marginWidth = -1;
731         int marginHeight = -1;
732         if (child.m_type != ChildFrame::Object) {
733             HTMLFrameElementImpl *o = static_cast<HTMLFrameElementImpl *>(child.m_frame->element());
734             allowsScrolling = o->scrollingMode() != QScrollView::AlwaysOff;
735             marginWidth = o->getMarginWidth();
736             marginHeight = o->getMarginHeight();
737         }
738         WebCoreBridge *childBridge = [_bridge createChildFrameNamed:child.m_name.getNSString()
739                                                             withURL:url.getNSURL()
740                                                          renderPart:child.m_frame
741                                                     allowsScrolling:allowsScrolling
742                                                         marginWidth:marginWidth
743                                                        marginHeight:marginHeight];
744         // This call needs to return an object with a ref, since the caller will expect to own it.
745         // childBridge owns the only ref so far.
746         [childBridge part]->ref();
747         part = [childBridge part];
748     }
749
750     return part;
751
752     KWQ_UNBLOCK_EXCEPTIONS;
753
754     return NULL;
755 }
756     
757 void KWQKHTMLPart::setView(KHTMLView *view)
758 {
759     // Detach the document now, so any onUnload handlers get run - if
760     // we wait until the view is destroyed, then things won't be
761     // hooked up enough for some JavaScript calls to work.
762     if (d->m_doc && view == NULL) {
763         d->m_doc->detach();
764     }
765
766     if (view) {
767         view->ref();
768     }
769     if (d->m_view) {
770         d->m_view->deref();
771     }
772     d->m_view = view;
773     setWidget(view);
774     
775     // Only one form submission is allowed per view of a part.
776     // Since this part may be getting reused as a result of being
777     // pulled from the back/forward cache, reset this flag.
778     _submittedFormURL = KURL();
779 }
780
781 KHTMLView *KWQKHTMLPart::view() const
782 {
783     return d->m_view;
784 }
785
786 void KWQKHTMLPart::setTitle(const DOMString &title)
787 {
788     QString text = title.string();
789     text.replace('\\', backslashAsCurrencySymbol());
790
791     KWQ_BLOCK_EXCEPTIONS;
792     [_bridge setTitle:text.getNSString()];
793     KWQ_UNBLOCK_EXCEPTIONS;
794 }
795
796 void KWQKHTMLPart::setStatusBarText(const QString &status)
797 {
798     QString text = status;
799     text.replace('\\', backslashAsCurrencySymbol());
800
801     KWQ_BLOCK_EXCEPTIONS;
802     [_bridge setStatusText:text.getNSString()];
803     KWQ_UNBLOCK_EXCEPTIONS;
804 }
805
806 void KWQKHTMLPart::scheduleClose()
807 {
808     KWQ_BLOCK_EXCEPTIONS;
809     [_bridge closeWindowSoon];
810     KWQ_UNBLOCK_EXCEPTIONS;
811 }
812
813 void KWQKHTMLPart::unfocusWindow()
814 {
815     KWQ_BLOCK_EXCEPTIONS;
816     [_bridge unfocusWindow];
817     KWQ_UNBLOCK_EXCEPTIONS;
818 }
819
820 void KWQKHTMLPart::jumpToSelection()
821 {
822     // Assumes that selection will only ever be text nodes. This is currently
823     // true, but will it always be so?
824     if (d->m_selection.start().notEmpty()) {
825         RenderText *rt = dynamic_cast<RenderText *>(d->m_selection.start().node()->renderer());
826         if (rt) {
827             int x = 0, y = 0;
828             rt->posOfChar(d->m_selection.start().offset(), x, y);
829             // The -50 offset is copied from KHTMLPart::findTextNext, which sets the contents position
830             // after finding a matched text string.
831            d->m_view->setContentsPos(x - 50, y - 50);
832         }
833 /*
834         Something like this would fix <rdar://problem/3154293>: "Find Next should not scroll page if the next target is already visible"
835
836         I think this would be a better way to do this, to avoid needless horizontal scrolling,
837         but it is not feasible until selectionRect() returns a tighter rect around the
838         selected text.  Right now it works at element granularity.
839  
840         NSView *docView = d->m_view->getDocumentView();
841
842         KWQ_BLOCK_EXCEPTIONS;
843         NSRect selRect = NSRect(selectionRect());
844         NSRect visRect = [docView visibleRect];
845         if (!NSContainsRect(visRect, selRect)) {
846             // pad a bit so we overscroll slightly
847             selRect = NSInsetRect(selRect, -10.0, -10.0);
848             selRect = NSIntersectionRect(selRect, [docView bounds]);
849             [docView scrollRectToVisible:selRect];
850         }
851         KWQ_UNBLOCK_EXCEPTIONS;
852 */
853     }
854 }
855
856 void KWQKHTMLPart::redirectionTimerStartedOrStopped()
857 {
858     // Don't report history navigations, just actual redirection.
859     if (d->m_scheduledRedirection == historyNavigationScheduled) {
860         return;
861     }
862     
863     KWQ_BLOCK_EXCEPTIONS;
864     if (d->m_redirectionTimer.isActive()) {
865         [_bridge reportClientRedirectToURL:KURL(d->m_redirectURL).getNSURL()
866                                      delay:d->m_delayRedirect
867                                   fireDate:[d->m_redirectionTimer.getNSTimer() fireDate]
868                                lockHistory:d->m_redirectLockHistory
869                                isJavaScriptFormAction:d->m_executingJavaScriptFormAction];
870     } else {
871         [_bridge reportClientRedirectCancelled:d->m_cancelWithLoadInProgress];
872     }
873     KWQ_UNBLOCK_EXCEPTIONS;
874 }
875
876 void KWQKHTMLPart::paint(QPainter *p, const QRect &rect)
877 {
878 #ifndef NDEBUG
879     bool fillWithRed;
880     if (p->device()->devType() == QInternal::Printer)
881         fillWithRed = false; // Printing, don't fill with red (can't remember why).
882     else if (!xmlDocImpl() || xmlDocImpl()->ownerElement())
883         fillWithRed = false; // Subframe, don't fill with red.
884     else if (view() && view()->isTransparent())
885         fillWithRed = false; // Transparent, don't fill with red.
886     else
887         fillWithRed = true;
888
889     if (fillWithRed) {
890         p->fillRect(rect.x(), rect.y(), rect.width(), rect.height(), QColor(0xFF, 0, 0));
891     }
892 #endif
893
894     if (renderer()) {
895         renderer()->layer()->paint(p, rect);
896     } else {
897         ERROR("called KWQKHTMLPart::paint with nil renderer");
898     }
899 }
900
901 void KWQKHTMLPart::paintSelectionOnly(QPainter *p, const QRect &rect)
902 {
903     if (renderer()) {
904         renderer()->layer()->paint(p, rect, true);
905     } else {
906         ERROR("called KWQKHTMLPart::paintSelectionOnly with nil renderer");
907     }
908 }
909
910 void KWQKHTMLPart::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
911 {
912     RenderCanvas *root = static_cast<RenderCanvas *>(xmlDocImpl()->renderer());
913     if (root) {
914         // Use a printer device, with painting disabled for the pagination phase
915         QPainter painter(true);
916         painter.setPaintingDisabled(true);
917
918         root->setTruncatedAt((int)floor(oldBottom));
919         QRect dirtyRect(0, (int)floor(oldTop),
920                         root->docWidth(), (int)ceil(oldBottom-oldTop));
921         root->layer()->paint(&painter, dirtyRect);
922         *newBottom = root->bestTruncatedAt();
923         if (*newBottom == 0) {
924             *newBottom = oldBottom;
925         }
926     } else {
927         *newBottom = oldBottom;
928     }
929 }
930
931 RenderObject *KWQKHTMLPart::renderer()
932 {
933     DocumentImpl *doc = xmlDocImpl();
934     return doc ? doc->renderer() : 0;
935 }
936
937 QString KWQKHTMLPart::userAgent() const
938 {
939     KWQ_BLOCK_EXCEPTIONS;
940     return QString::fromNSString([_bridge userAgentForURL:m_url.getNSURL()]);
941     KWQ_UNBLOCK_EXCEPTIONS;
942          
943     return QString();
944 }
945
946 QString KWQKHTMLPart::mimeTypeForFileName(const QString &fileName) const
947 {
948     NSString *ns = fileName.getNSString();
949
950     KWQ_BLOCK_EXCEPTIONS;
951     return QString::fromNSString([_bridge MIMETypeForPath:ns]);
952     KWQ_UNBLOCK_EXCEPTIONS;
953
954     return QString();
955 }
956
957 NSView *KWQKHTMLPart::nextKeyViewInFrame(NodeImpl *node, KWQSelectionDirection direction)
958 {
959     DocumentImpl *doc = xmlDocImpl();
960     if (!doc) {
961         return nil;
962     }
963     for (;;) {
964         node = direction == KWQSelectingNext
965             ? doc->nextFocusNode(node) : doc->previousFocusNode(node);
966         if (!node) {
967             return nil;
968         }
969         RenderWidget *renderWidget = dynamic_cast<RenderWidget *>(node->renderer());
970         if (renderWidget) {
971             QWidget *widget = renderWidget->widget();
972             KHTMLView *childFrameWidget = dynamic_cast<KHTMLView *>(widget);
973             if (childFrameWidget) {
974                 NSView *view = KWQ(childFrameWidget->part())->nextKeyViewInFrame(0, direction);
975                 if (view) {
976                     return view;
977                 }
978             } else if (widget) {
979                 NSView *view = widget->getView();
980                 // AppKit won't be able to handle scrolling and making us the first responder
981                 // well unless we are actually installed in the correct place. KHTML only does
982                 // that for visible widgets, so we need to do it explicitly here.
983                 int x, y;
984                 if (view && renderWidget->absolutePosition(x, y)) {
985                     renderWidget->view()->addChild(widget, x, y);
986                     return view;
987                 }
988             }
989         }
990         else {
991             doc->setFocusNode(node);
992             if (view()) {
993                 view()->ensureRectVisibleCentered(node->getRect());
994             }
995             [_bridge makeFirstResponder:[_bridge documentView]];
996             return [_bridge documentView];
997         }
998     }
999 }
1000
1001 NSView *KWQKHTMLPart::nextKeyViewInFrameHierarchy(NodeImpl *node, KWQSelectionDirection direction)
1002 {
1003     NSView *next = nextKeyViewInFrame(node, direction);
1004     if (next) {
1005         return next;
1006     }
1007
1008     // remove focus from currently focused node
1009     DocumentImpl *doc = xmlDocImpl();
1010     if (doc) {
1011         doc->setFocusNode(0);
1012     }
1013     
1014     KWQKHTMLPart *parent = KWQ(parentPart());
1015     if (parent) {
1016         next = parent->nextKeyView(parent->childFrame(this)->m_frame->element(), direction);
1017         if (next) {
1018             return next;
1019         }
1020     }
1021     
1022     return nil;
1023 }
1024
1025 NSView *KWQKHTMLPart::nextKeyView(NodeImpl *node, KWQSelectionDirection direction)
1026 {
1027     KWQ_BLOCK_EXCEPTIONS;
1028
1029     NSView * next = nextKeyViewInFrameHierarchy(node, direction);
1030     if (next) {
1031         return next;
1032     }
1033
1034     // Look at views from the top level part up, looking for a next key view that we can use.
1035
1036     next = direction == KWQSelectingNext
1037         ? [_bridge nextKeyViewOutsideWebFrameViews]
1038         : [_bridge previousKeyViewOutsideWebFrameViews];
1039
1040     if (next) {
1041         return next;
1042     }
1043
1044     KWQ_UNBLOCK_EXCEPTIONS;
1045     
1046     // If all else fails, make a loop by starting from 0.
1047     return nextKeyViewInFrameHierarchy(0, direction);
1048 }
1049
1050 NSView *KWQKHTMLPart::nextKeyViewForWidget(QWidget *startingWidget, KWQSelectionDirection direction)
1051 {
1052     // Use the event filter object to figure out which RenderWidget owns this QWidget and get to the DOM.
1053     // Then get the next key view in the order determined by the DOM.
1054     NodeImpl *node = nodeForWidget(startingWidget);
1055     ASSERT(node);
1056     return partForNode(node)->nextKeyView(node, direction);
1057 }
1058
1059 bool KWQKHTMLPart::currentEventIsMouseDownInWidget(QWidget *candidate)
1060 {
1061     KWQ_BLOCK_EXCEPTIONS;
1062     switch ([[NSApp currentEvent] type]) {
1063         case NSLeftMouseDown:
1064         case NSRightMouseDown:
1065         case NSOtherMouseDown:
1066             break;
1067         default:
1068             return NO;
1069     }
1070     KWQ_UNBLOCK_EXCEPTIONS;
1071     
1072     NodeImpl *node = nodeForWidget(candidate);
1073     ASSERT(node);
1074     return partForNode(node)->nodeUnderMouse() == node;
1075 }
1076
1077 bool KWQKHTMLPart::currentEventIsKeyboardOptionTab()
1078 {
1079     KWQ_BLOCK_EXCEPTIONS;
1080     NSEvent *evt = [NSApp currentEvent];
1081     if ([evt type] != NSKeyDown) {
1082         return NO;
1083     }
1084
1085     if (([evt modifierFlags] & NSAlternateKeyMask) == 0) {
1086         return NO;
1087     }
1088     
1089     NSString *chars = [evt charactersIgnoringModifiers];
1090     if ([chars length] != 1)
1091         return NO;
1092     
1093     const unichar tabKey = 0x0009;
1094     const unichar shiftTabKey = 0x0019;
1095     unichar c = [chars characterAtIndex:0];
1096     if (c != tabKey && c != shiftTabKey)
1097         return NO;
1098     
1099     KWQ_UNBLOCK_EXCEPTIONS;
1100     return YES;
1101 }
1102
1103 bool KWQKHTMLPart::handleKeyboardOptionTabInView(NSView *view)
1104 {
1105     if (KWQKHTMLPart::currentEventIsKeyboardOptionTab()) {
1106         if (([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) != 0) {
1107             [[view window] selectKeyViewPrecedingView:view];
1108         } else {
1109             [[view window] selectKeyViewFollowingView:view];
1110         }
1111         return YES;
1112     }
1113     
1114     return NO;
1115 }
1116
1117 bool KWQKHTMLPart::tabsToLinks() const
1118 {
1119     if ([_bridge keyboardUIMode] & WebCoreKeyboardAccessTabsToLinks)
1120         return !KWQKHTMLPart::currentEventIsKeyboardOptionTab();
1121     else
1122         return KWQKHTMLPart::currentEventIsKeyboardOptionTab();
1123 }
1124
1125 bool KWQKHTMLPart::tabsToAllControls() const
1126 {
1127     if ([_bridge keyboardUIMode] & WebCoreKeyboardAccessFull)
1128         return !KWQKHTMLPart::currentEventIsKeyboardOptionTab();
1129     else
1130         return KWQKHTMLPart::currentEventIsKeyboardOptionTab();
1131 }
1132
1133 void KWQKHTMLPart::bindObject(void *object, QString name)
1134 {
1135     if (d->m_doc && jScript()) {
1136         Window *w = Window::retrieveWindow(this);
1137         w->put(jScript()->interpreter()->globalExec(), KJS::Identifier(name), Instance::createRuntimeObject(Instance::ObjectiveCLanguage, (void *)object));
1138     }
1139 }
1140
1141
1142 QMap<int, ScheduledAction*> *KWQKHTMLPart::pauseActions(const void *key)
1143 {
1144     if (d->m_doc && d->m_jscript) {
1145         Window *w = Window::retrieveWindow(this);
1146         if (w && w->hasTimeouts()) {
1147             return w->pauseTimeouts(key);
1148         }
1149     }
1150     return 0;
1151 }
1152
1153 void KWQKHTMLPart::resumeActions(QMap<int, ScheduledAction*> *actions, const void *key)
1154 {
1155     if (d->m_doc && d->m_jscript && d->m_bJScriptEnabled) {
1156         Window *w = Window::retrieveWindow(this);
1157         if (w) {
1158             w->resumeTimeouts(actions, key);
1159         }
1160     }
1161 }
1162
1163 bool KWQKHTMLPart::canCachePage()
1164 {
1165     // Only save page state if:
1166     // 1.  We're not a frame or frameset.
1167     // 2.  The page has no unload handler.
1168     // 3.  The page has no password fields.
1169     // 4.  The URL for the page is not https.
1170     // 5.  The page has no applets.
1171     if (d->m_frames.count() ||
1172         parentPart() ||
1173         m_url.protocol().startsWith("https") || 
1174         (d->m_doc && (htmlDocument().applets().length() != 0 ||
1175                       d->m_doc->hasWindowEventListener(EventImpl::UNLOAD_EVENT) ||
1176                       d->m_doc->hasPasswordField()))) {
1177         return false;
1178     }
1179     return true;
1180 }
1181
1182 void KWQKHTMLPart::saveWindowProperties(SavedProperties *windowProperties)
1183 {
1184     Window *window = Window::retrieveWindow(this);
1185     if (window)
1186         window->saveProperties(*windowProperties);
1187 }
1188
1189 void KWQKHTMLPart::saveLocationProperties(SavedProperties *locationProperties)
1190 {
1191     Window *window = Window::retrieveWindow(this);
1192     if (window) {
1193         Interpreter::lock();
1194         Location *location = window->location();
1195         Interpreter::unlock();
1196         location->saveProperties(*locationProperties);
1197     }
1198 }
1199
1200 void KWQKHTMLPart::restoreWindowProperties(SavedProperties *windowProperties)
1201 {
1202     Window *window = Window::retrieveWindow(this);
1203     if (window)
1204         window->restoreProperties(*windowProperties);
1205 }
1206
1207 void KWQKHTMLPart::restoreLocationProperties(SavedProperties *locationProperties)
1208 {
1209     Window *window = Window::retrieveWindow(this);
1210     if (window) {
1211         Interpreter::lock();
1212         Location *location = window->location();
1213         Interpreter::unlock();
1214         location->restoreProperties(*locationProperties);
1215     }
1216 }
1217
1218 void KWQKHTMLPart::saveInterpreterBuiltins(SavedBuiltins &interpreterBuiltins)
1219 {
1220     if (jScript() && jScript()->interpreter()) {
1221         jScript()->interpreter()->saveBuiltins(interpreterBuiltins);
1222     }
1223 }
1224
1225 void KWQKHTMLPart::restoreInterpreterBuiltins(const SavedBuiltins &interpreterBuiltins)
1226 {
1227     if (jScript() && jScript()->interpreter()) {
1228         jScript()->interpreter()->restoreBuiltins(interpreterBuiltins);
1229     }
1230 }
1231
1232 void KWQKHTMLPart::openURLFromPageCache(KWQPageState *state)
1233 {
1234     // It's safe to assume none of the KWQPageState methods will raise
1235     // exceptions, since KWQPageState is implemented by WebCore and
1236     // does not throw
1237
1238     DocumentImpl *doc = [state document];
1239     KURL *url = [state URL];
1240     SavedProperties *windowProperties = [state windowProperties];
1241     SavedProperties *locationProperties = [state locationProperties];
1242     SavedBuiltins *interpreterBuiltins = [state interpreterBuiltins];
1243     QMap<int, ScheduledAction*> *actions = [state pausedActions];
1244     
1245     cancelRedirection();
1246
1247     // We still have to close the previous part page.
1248     if (!d->m_restored){
1249         closeURL();
1250     }
1251             
1252     d->m_bComplete = false;
1253     
1254     // Don't re-emit the load event.
1255     d->m_bLoadEventEmitted = true;
1256     
1257     // delete old status bar msg's from kjs (if it _was_ activated on last URL)
1258     if( d->m_bJScriptEnabled )
1259     {
1260         d->m_kjsStatusBarText = QString::null;
1261         d->m_kjsDefaultStatusBarText = QString::null;
1262     }
1263
1264     ASSERT (url);
1265     
1266     m_url = *url;
1267     
1268     // 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
1269     // data arrives) (Simon)
1270     if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() && m_url.path().isEmpty()) {
1271         m_url.setPath("/");
1272         emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
1273     }
1274     
1275     // copy to m_workingURL after fixing m_url above
1276     d->m_workingURL = m_url;
1277         
1278     emit started( 0L );
1279     
1280     // -----------begin-----------
1281     clear();
1282
1283     doc->setInPageCache(NO);
1284
1285     d->m_bCleared = false;
1286     d->m_cacheId = 0;
1287     d->m_bComplete = false;
1288     d->m_bLoadEventEmitted = false;
1289     d->m_referrer = m_url.url();
1290     
1291     setView(doc->view());
1292     
1293     d->m_doc = doc;
1294     d->m_doc->ref();
1295     
1296     Decoder *decoder = doc->decoder();
1297     if (decoder) {
1298         decoder->ref();
1299     }
1300     if (d->m_decoder) {
1301         d->m_decoder->deref();
1302     }
1303     d->m_decoder = decoder;
1304
1305     updatePolicyBaseURL();
1306         
1307     restoreWindowProperties (windowProperties);
1308     restoreLocationProperties (locationProperties);
1309     restoreInterpreterBuiltins (*interpreterBuiltins);
1310
1311     if (actions)
1312         resumeActions (actions, state);
1313     
1314     checkCompleted();
1315 }
1316
1317 KWQKHTMLPart *KWQKHTMLPart::partForWidget(const QWidget *widget)
1318 {
1319     ASSERT_ARG(widget, widget);
1320     
1321     NodeImpl *node = nodeForWidget(widget);
1322     if (node) {
1323         return partForNode(node);
1324     }
1325     
1326     // Assume all widgets are either form controls, or KHTMLViews.
1327     const KHTMLView *view = dynamic_cast<const KHTMLView *>(widget);
1328     ASSERT(view);
1329     return KWQ(view->part());
1330 }
1331
1332 WebCoreBridge *KWQKHTMLPart::bridgeForWidget(const QWidget *widget)
1333 {
1334     ASSERT_ARG(widget, widget);
1335     
1336     KWQKHTMLPart *part = partForWidget(widget);
1337     ASSERT(part);
1338     return part->bridge();
1339 }
1340
1341 KWQKHTMLPart *KWQKHTMLPart::partForNode(NodeImpl *node)
1342 {
1343     ASSERT_ARG(node, node);
1344     return KWQ(node->getDocument()->part());
1345 }
1346
1347 NSView *KWQKHTMLPart::documentViewForNode(DOM::NodeImpl *node)
1348 {
1349     WebCoreBridge *bridge = partForNode(node)->bridge();
1350     return [bridge documentView];
1351 }
1352
1353 NodeImpl *KWQKHTMLPart::nodeForWidget(const QWidget *widget)
1354 {
1355     ASSERT_ARG(widget, widget);
1356     const QObject *o = widget->eventFilterObject();
1357     return o ? static_cast<const RenderWidget *>(o)->element() : 0;
1358 }
1359
1360 void KWQKHTMLPart::setDocumentFocus(QWidget *widget)
1361 {
1362     NodeImpl *node = nodeForWidget(widget);
1363     if (node) {
1364         node->getDocument()->setFocusNode(node);
1365     } else {
1366         ERROR("unable to clear focus because widget had no corresponding node");
1367     }
1368 }
1369
1370 void KWQKHTMLPart::clearDocumentFocus(QWidget *widget)
1371 {
1372     NodeImpl *node = nodeForWidget(widget);
1373     if (node) {
1374         node->getDocument()->setFocusNode(0);
1375     } else {
1376         ERROR("unable to clear focus because widget had no corresponding node");
1377     }
1378 }
1379
1380 void KWQKHTMLPart::saveDocumentState()
1381 {
1382     // Do not save doc state if the page has a password field and a form that would be submitted
1383     // via https
1384     if (!(d->m_doc && d->m_doc->hasPasswordField() && d->m_doc->hasSecureForm())) {
1385         KWQ_BLOCK_EXCEPTIONS;
1386         [_bridge saveDocumentState];
1387         KWQ_UNBLOCK_EXCEPTIONS;
1388     }
1389 }
1390
1391 void KWQKHTMLPart::restoreDocumentState()
1392 {
1393     KWQ_BLOCK_EXCEPTIONS;
1394     [_bridge restoreDocumentState];
1395     KWQ_UNBLOCK_EXCEPTIONS;
1396 }
1397
1398 QPtrList<KWQKHTMLPart> &KWQKHTMLPart::mutableInstances()
1399 {
1400     static QPtrList<KWQKHTMLPart> instancesList;
1401     return instancesList;
1402 }
1403
1404 void KWQKHTMLPart::updatePolicyBaseURL()
1405 {
1406     // FIXME: docImpl() returns null for everything other than HTML documents; is this causing problems? -dwh
1407     if (parentPart() && parentPart()->docImpl()) {
1408         setPolicyBaseURL(parentPart()->docImpl()->policyBaseURL());
1409     } else {
1410         setPolicyBaseURL(m_url.url());
1411     }
1412 }
1413
1414 void KWQKHTMLPart::setPolicyBaseURL(const DOMString &s)
1415 {
1416     // FIXME: XML documents will cause this to return null.  docImpl() is
1417     // an HTMLdocument only. -dwh
1418     if (docImpl())
1419         docImpl()->setPolicyBaseURL(s);
1420     ConstFrameIt end = d->m_frames.end();
1421     for (ConstFrameIt it = d->m_frames.begin(); it != end; ++it) {
1422         ReadOnlyPart *subpart = (*it).m_part;
1423         static_cast<KWQKHTMLPart *>(subpart)->setPolicyBaseURL(s);
1424     }
1425 }
1426
1427 QString KWQKHTMLPart::requestedURLString() const
1428 {
1429     KWQ_BLOCK_EXCEPTIONS;
1430     return QString::fromNSString([_bridge requestedURLString]);
1431     KWQ_UNBLOCK_EXCEPTIONS;
1432
1433     return QString();
1434 }
1435
1436 QString KWQKHTMLPart::incomingReferrer() const
1437 {
1438     KWQ_BLOCK_EXCEPTIONS;
1439     return QString::fromNSString([_bridge incomingReferrer]);
1440     KWQ_UNBLOCK_EXCEPTIONS;
1441
1442     return QString();
1443 }
1444
1445 void KWQKHTMLPart::forceLayout()
1446 {
1447     KHTMLView *v = d->m_view;
1448     if (v) {
1449         v->layout();
1450         // We cannot unschedule a pending relayout, since the force can be called with
1451         // a tiny rectangle from a drawRect update.  By unscheduling we in effect
1452         // "validate" and stop the necessary full repaint from occurring.  Basically any basic
1453         // append/remove DHTML is broken by this call.  For now, I have removed the optimization
1454         // until we have a better invalidation stategy. -dwh
1455         //v->unscheduleRelayout();
1456     }
1457 }
1458
1459 void KWQKHTMLPart::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth)
1460 {
1461     // Dumping externalRepresentation(_part->renderer()).ascii() is a good trick to see
1462     // the state of things before and after the layout
1463     RenderCanvas *root = static_cast<RenderCanvas *>(xmlDocImpl()->renderer());
1464     if (root) {
1465         // This magic is basically copied from khtmlview::print
1466         int pageW = (int)ceil(minPageWidth);
1467         root->setWidth(pageW);
1468         root->setNeedsLayoutAndMinMaxRecalc();
1469         forceLayout();
1470         
1471         // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
1472         // maximum page width, we will lay out to the maximum page width and clip extra content.
1473         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
1474         // implementation should not do this!
1475         int rightmostPos = root->rightmostPosition();
1476         if (rightmostPos > minPageWidth) {
1477             pageW = kMin(rightmostPos, (int)ceil(maxPageWidth));
1478             root->setWidth(pageW);
1479             root->setNeedsLayoutAndMinMaxRecalc();
1480             forceLayout();
1481         }
1482     }
1483 }
1484
1485 void KWQKHTMLPart::sendResizeEvent()
1486 {
1487     KHTMLView *v = d->m_view;
1488     if (v) {
1489         // Sending an event can result in the destruction of the view and part.
1490         // We ref so that happens after we return from the KHTMLView function.
1491         v->ref();
1492         QResizeEvent e;
1493         v->resizeEvent(&e);
1494         v->deref();
1495     }
1496 }
1497
1498 void KWQKHTMLPart::sendScrollEvent()
1499 {
1500     KHTMLView *v = d->m_view;
1501     if (v) {
1502         DocumentImpl *doc = xmlDocImpl();
1503         if (!doc)
1504             return;
1505         doc->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, true, false);
1506     }
1507 }
1508
1509 void KWQKHTMLPart::runJavaScriptAlert(const QString &message)
1510 {
1511     QString text = message;
1512     text.replace('\\', backslashAsCurrencySymbol());
1513     KWQ_BLOCK_EXCEPTIONS;
1514     [_bridge runJavaScriptAlertPanelWithMessage:text.getNSString()];
1515     KWQ_UNBLOCK_EXCEPTIONS;
1516 }
1517
1518 bool KWQKHTMLPart::runJavaScriptConfirm(const QString &message)
1519 {
1520     QString text = message;
1521     text.replace('\\', backslashAsCurrencySymbol());
1522
1523     KWQ_BLOCK_EXCEPTIONS;
1524     return [_bridge runJavaScriptConfirmPanelWithMessage:text.getNSString()];
1525     KWQ_UNBLOCK_EXCEPTIONS;
1526
1527     return false;
1528 }
1529
1530 bool KWQKHTMLPart::runJavaScriptPrompt(const QString &prompt, const QString &defaultValue, QString &result)
1531 {
1532     QString promptText = prompt;
1533     promptText.replace('\\', backslashAsCurrencySymbol());
1534     QString defaultValueText = defaultValue;
1535     defaultValueText.replace('\\', backslashAsCurrencySymbol());
1536
1537     KWQ_BLOCK_EXCEPTIONS;
1538     NSString *returnedText = nil;
1539
1540     bool ok = [_bridge runJavaScriptTextInputPanelWithPrompt:prompt.getNSString()
1541                defaultText:defaultValue.getNSString() returningText:&returnedText];
1542
1543     if (ok) {
1544         result = QString::fromNSString(returnedText);
1545         result.replace(backslashAsCurrencySymbol(), '\\');
1546     }
1547
1548     return ok;
1549     KWQ_UNBLOCK_EXCEPTIONS;
1550     
1551     return false;
1552 }
1553
1554 void KWQKHTMLPart::createEmptyDocument()
1555 {
1556     // Although it's not completely clear from the name of this function,
1557     // it does nothing if we already have a document, and just creates an
1558     // empty one if we have no document at all.
1559     if (!d->m_doc) {
1560         KWQ_BLOCK_EXCEPTIONS;
1561         [_bridge loadEmptyDocumentSynchronously];
1562         KWQ_UNBLOCK_EXCEPTIONS;
1563
1564         if (parentPart() && (parentPart()->childFrame(this)->m_type == ChildFrame::IFrame ||
1565                              parentPart()->childFrame(this)->m_type == ChildFrame::Object)) {
1566             d->m_doc->setBaseURL(parentPart()->d->m_doc->baseURL());
1567         }
1568     }
1569 }
1570
1571 void KWQKHTMLPart::addMetaData(const QString &key, const QString &value)
1572 {
1573     d->m_job->addMetaData(key, value);
1574 }
1575
1576 bool KWQKHTMLPart::keyEvent(NSEvent *event)
1577 {
1578     KWQ_BLOCK_EXCEPTIONS;
1579
1580     ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
1581
1582     // Check for cases where we are too early for events -- possible unmatched key up
1583     // from pressing return in the location bar.
1584     DocumentImpl *doc = xmlDocImpl();
1585     if (!doc) {
1586         return false;
1587     }
1588     NodeImpl *node = doc->focusNode();
1589     if (!node && docImpl()) {
1590         node = docImpl()->body();
1591     }
1592     if (!node) {
1593         return false;
1594     }
1595     
1596     NSEvent *oldCurrentEvent = _currentEvent;
1597     _currentEvent = [event retain];
1598
1599     QKeyEvent qEvent(event);
1600     bool result = !node->dispatchKeyEvent(&qEvent);
1601
1602     // We want to send both a down and a press for the initial key event.
1603     // To get KHTML to do this, we send a second KeyPress QKeyEvent with "is repeat" set to true,
1604     // which causes it to send a press to the DOM.
1605     // That's not a great hack; it would be good to do this in a better way.
1606     if ([event type] == NSKeyDown && ![event isARepeat]) {
1607         QKeyEvent repeatEvent(event, true);
1608         if (!node->dispatchKeyEvent(&repeatEvent)) {
1609             result = true;
1610         }
1611     }
1612
1613     ASSERT(_currentEvent == event);
1614     [event release];
1615     _currentEvent = oldCurrentEvent;
1616
1617     return result;
1618
1619     KWQ_UNBLOCK_EXCEPTIONS;
1620
1621     return false;
1622 }
1623
1624 // This does the same kind of work that KHTMLPart::openURL does, except it relies on the fact
1625 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1626 void KWQKHTMLPart::scrollToAnchor(const KURL &URL)
1627 {
1628     cancelRedirection();
1629
1630     m_url = URL;
1631     started(0);
1632
1633     gotoAnchor();
1634
1635     // It's important to model this as a load that starts and immediately finishes.
1636     // Otherwise, the parent frame may think we never finished loading.
1637     d->m_bComplete = false;
1638     checkCompleted();
1639 }
1640
1641 bool KWQKHTMLPart::closeURL()
1642 {
1643     saveDocumentState();
1644     return KHTMLPart::closeURL();
1645 }
1646
1647 void KWQKHTMLPart::khtmlMousePressEvent(MousePressEvent *event)
1648 {
1649     // If we got the event back, that must mean it wasn't prevented,
1650     // so it's allowed to start a drag or selection.
1651     _mouseDownMayStartDrag = true;
1652     _mouseDownMayStartSelect = true;
1653
1654     if (!passWidgetMouseDownEventToWidget(event)) {
1655         // We don't do this at the start of mouse down handling (before calling into WebCore),
1656         // because we don't want to do it until we know we didn't hit a widget.
1657         NSView *view = d->m_view->getDocumentView();
1658
1659         KWQ_BLOCK_EXCEPTIONS;
1660         if ([_currentEvent clickCount] <= 1 && [_bridge firstResponder] != view) {
1661             [_bridge makeFirstResponder:view];
1662         }
1663         KWQ_UNBLOCK_EXCEPTIONS;
1664
1665         KHTMLPart::khtmlMousePressEvent(event);
1666     }
1667 }
1668
1669 void KWQKHTMLPart::khtmlMouseDoubleClickEvent(MouseDoubleClickEvent *event)
1670 {
1671     if (!passWidgetMouseDownEventToWidget(event)) {
1672         KHTMLPart::khtmlMouseDoubleClickEvent(event);
1673     }
1674 }
1675
1676 bool KWQKHTMLPart::passWidgetMouseDownEventToWidget(khtml::MouseEvent *event)
1677 {
1678     // Figure out which view to send the event to.
1679     RenderObject *target = event->innerNode().handle() ? event->innerNode().handle()->renderer() : 0;
1680     if (!target)
1681         return false;
1682
1683     QWidget* widget = RenderLayer::gScrollBar;
1684     if (!widget) {
1685         if (!target->isWidget())
1686             return false;
1687         widget = static_cast<RenderWidget *>(target)->widget();
1688     }
1689
1690     // Doubleclick events don't exist in Cocoa.  Since passWidgetMouseDownEventToWidget will
1691     // just pass _currentEvent down to the widget,  we don't want to call it for events that
1692     // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
1693     // part of the pressed/released handling.
1694     if (!MouseDoubleClickEvent::test(event))
1695         return passWidgetMouseDownEventToWidget(widget);
1696     else
1697         return true;
1698 }
1699
1700 bool KWQKHTMLPart::passWidgetMouseDownEventToWidget(RenderWidget *renderWidget)
1701 {
1702     return passWidgetMouseDownEventToWidget(renderWidget->widget());
1703 }
1704
1705 bool KWQKHTMLPart::passWidgetMouseDownEventToWidget(QWidget* widget)
1706 {
1707     // FIXME: this method always returns true
1708
1709     if (!widget) {
1710         ERROR("hit a RenderWidget without a corresponding QWidget, means a frame is half-constructed");
1711         return true;
1712     }
1713
1714     KWQ_BLOCK_EXCEPTIONS;
1715     
1716     NSView *nodeView = widget->getView();
1717     ASSERT(nodeView);
1718     ASSERT([nodeView superview]);
1719     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[_currentEvent locationInWindow] fromView:nil]];
1720     if (view == nil) {
1721         ERROR("KHTML says we hit a RenderWidget, but AppKit doesn't agree we hit the corresponding NSView");
1722         return true;
1723     }
1724     
1725     if ([_bridge firstResponder] == view) {
1726         // In the case where we just became first responder, we should send the mouseDown:
1727         // to the NSTextField, not the NSTextField's editor. This code makes sure that happens.
1728         // If we don't do this, we see a flash of selected text when clicking in a text field.
1729         if (_firstResponderAtMouseDownTime != view && [view isKindOfClass:[NSTextView class]]) {
1730             NSView *superview = view;
1731             while (superview != nodeView) {
1732                 superview = [superview superview];
1733                 ASSERT(superview);
1734                 if ([superview isKindOfClass:[NSControl class]]) {
1735                     NSControl *control = superview;
1736                     if ([control currentEditor] == view) {
1737                         view = superview;
1738                     }
1739                     break;
1740                 }
1741             }
1742         }
1743     } else {
1744         // Normally [NSWindow sendEvent:] handles setting the first responder.
1745         // But in our case, the event was sent to the view representing the entire web page.
1746         if ([_currentEvent clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) {
1747             [_bridge makeFirstResponder:view];
1748         }
1749     }
1750
1751     // We need to "defer loading" and defer timers while we are tracking the mouse.
1752     // That's because we don't want the new page to load while the user is holding the mouse down.
1753     
1754     BOOL wasDeferringLoading = [_bridge defersLoading];
1755     if (!wasDeferringLoading) {
1756         [_bridge setDefersLoading:YES];
1757     }
1758     BOOL wasDeferringTimers = QObject::defersTimers();
1759     if (!wasDeferringTimers) {
1760         QObject::setDefersTimers(true);
1761     }
1762
1763     ASSERT(!_sendingEventToSubview);
1764     _sendingEventToSubview = true;
1765     [view mouseDown:_currentEvent];
1766     _sendingEventToSubview = false;
1767     
1768     if (!wasDeferringTimers) {
1769         QObject::setDefersTimers(false);
1770     }
1771     if (!wasDeferringLoading) {
1772         [_bridge setDefersLoading:NO];
1773     }
1774
1775     // Remember which view we sent the event to, so we can direct the release event properly.
1776     _mouseDownView = view;
1777     _mouseDownWasInSubframe = false;
1778
1779     KWQ_UNBLOCK_EXCEPTIONS;
1780
1781     return true;
1782 }
1783
1784 bool KWQKHTMLPart::lastEventIsMouseUp()
1785 {
1786     // Many AK widgets run their own event loops and consume events while the mouse is down.
1787     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
1788     // the khtml state with this mouseUp, which khtml never saw.  This method lets us detect
1789     // that state.
1790
1791     KWQ_BLOCK_EXCEPTIONS;
1792     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
1793     if (_currentEvent != currentEventAfterHandlingMouseDown) {
1794         if ([currentEventAfterHandlingMouseDown type] == NSLeftMouseUp) {
1795             return true;
1796         }
1797     }
1798     KWQ_UNBLOCK_EXCEPTIONS;
1799
1800     return false;
1801 }
1802     
1803 // Note that this does the same kind of check as [target isDescendantOf:superview].
1804 // There are two differences: This is a lot slower because it has to walk the whole
1805 // tree, and this works in cases where the target has already been deallocated.
1806 static bool findViewInSubviews(NSView *superview, NSView *target)
1807 {
1808     KWQ_BLOCK_EXCEPTIONS;
1809     NSEnumerator *e = [[superview subviews] objectEnumerator];
1810     NSView *subview;
1811     while ((subview = [e nextObject])) {
1812         if (subview == target || findViewInSubviews(subview, target)) {
1813             return true;
1814         }
1815     }
1816     KWQ_UNBLOCK_EXCEPTIONS;
1817     
1818     return false;
1819 }
1820
1821 NSView *KWQKHTMLPart::mouseDownViewIfStillGood()
1822 {
1823     // Since we have no way of tracking the lifetime of _mouseDownView, we have to assume that
1824     // it could be deallocated already. We search for it in our subview tree; if we don't find
1825     // it, we set it to nil.
1826     NSView *mouseDownView = _mouseDownView;
1827     if (!mouseDownView) {
1828         return nil;
1829     }
1830     KHTMLView *topKHTMLView = d->m_view;
1831     NSView *topView = topKHTMLView ? topKHTMLView->getView() : nil;
1832     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
1833         _mouseDownView = nil;
1834         return nil;
1835     }
1836     return mouseDownView;
1837 }
1838
1839 void KWQKHTMLPart::khtmlMouseMoveEvent(MouseMoveEvent *event)
1840 {
1841     KWQ_BLOCK_EXCEPTIONS;
1842
1843     if ([_currentEvent type] == NSLeftMouseDragged) {
1844         NSView *view = mouseDownViewIfStillGood();
1845
1846         if (view) {
1847             _sendingEventToSubview = true;
1848             [view mouseDragged:_currentEvent];
1849             _sendingEventToSubview = false;
1850             return;
1851         }
1852
1853         if (_mouseDownMayStartDrag && 
1854         d->m_textElement == DOM::Selection::CHARACTER &&
1855         [_bridge mayStartDragWithMouseDragged:_currentEvent]) {
1856             // We are starting a text/image/url drag, so the cursor should be an arrow
1857             d->m_view->resetCursor();
1858             [_bridge handleMouseDragged:_currentEvent];
1859             return;
1860         } else if (_mouseDownMayStartSelect) {
1861             // we use khtml's selection but our own autoscrolling
1862             [_bridge handleAutoscrollForMouseDragged:_currentEvent];
1863             // Don't allow dragging after we've started selecting.
1864             _mouseDownMayStartDrag = false;
1865         } else {
1866             return;
1867         }
1868     } else {
1869         // If we allowed the other side of the bridge to handle a drag
1870         // last time, then m_bMousePressed might still be set. So we
1871         // clear it now to make sure the next move after a drag
1872         // doesn't look like a drag.
1873         d->m_bMousePressed = false;
1874     }
1875
1876     KHTMLPart::khtmlMouseMoveEvent(event);
1877
1878     KWQ_UNBLOCK_EXCEPTIONS;
1879 }
1880
1881 void KWQKHTMLPart::khtmlMouseReleaseEvent(MouseReleaseEvent *event)
1882 {
1883     NSView *view = mouseDownViewIfStillGood();
1884     if (!view) {
1885         KHTMLPart::khtmlMouseReleaseEvent(event);
1886         return;
1887     }
1888     
1889     _sendingEventToSubview = true;
1890     KWQ_BLOCK_EXCEPTIONS;
1891     [view mouseUp:_currentEvent];
1892     KWQ_UNBLOCK_EXCEPTIONS;
1893     _sendingEventToSubview = false;
1894 }
1895
1896 void KWQKHTMLPart::clearTimers(KHTMLView *view)
1897 {
1898     if (view) {
1899         view->unscheduleRelayout();
1900         if (view->part()) {
1901             DocumentImpl* document = view->part()->xmlDocImpl();
1902             if (document && document->renderer() && document->renderer()->layer())
1903                 document->renderer()->layer()->suspendMarquees();
1904         }
1905     }
1906 }
1907
1908 void KWQKHTMLPart::clearTimers()
1909 {
1910     clearTimers(d->m_view);
1911 }
1912
1913 bool KWQKHTMLPart::passSubframeEventToSubframe(NodeImpl::MouseEvent &event)
1914 {
1915     KWQ_BLOCK_EXCEPTIONS;
1916
1917     switch ([_currentEvent type]) {
1918         case NSLeftMouseDown: {
1919             NodeImpl *node = event.innerNode.handle();
1920             if (!node) {
1921                 return false;
1922             }
1923             RenderPart *renderPart = dynamic_cast<RenderPart *>(node->renderer());
1924             if (!renderPart) {
1925                 return false;
1926             }
1927             if (!passWidgetMouseDownEventToWidget(renderPart)) {
1928                 return false;
1929             }
1930             _mouseDownWasInSubframe = true;
1931             return true;
1932         }
1933         case NSLeftMouseUp: {
1934             if (!_mouseDownWasInSubframe) {
1935                 return false;
1936             }
1937             NSView *view = mouseDownViewIfStillGood();
1938             if (!view) {
1939                 return false;
1940             }
1941             ASSERT(!_sendingEventToSubview);
1942             _sendingEventToSubview = true;
1943             [view mouseUp:_currentEvent];
1944             _sendingEventToSubview = false;
1945             return true;
1946         }
1947         case NSLeftMouseDragged: {
1948             if (!_mouseDownWasInSubframe) {
1949                 return false;
1950             }
1951             NSView *view = mouseDownViewIfStillGood();
1952             if (!view) {
1953                 return false;
1954             }
1955             ASSERT(!_sendingEventToSubview);
1956             _sendingEventToSubview = true;
1957             [view mouseDragged:_currentEvent];
1958             _sendingEventToSubview = false;
1959             return true;
1960         }
1961         default:
1962             return false;
1963     }
1964     KWQ_UNBLOCK_EXCEPTIONS;
1965
1966     return false;
1967 }
1968
1969 void KWQKHTMLPart::mouseDown(NSEvent *event)
1970 {
1971     KHTMLView *v = d->m_view;
1972     if (!v || _sendingEventToSubview) {
1973         return;
1974     }
1975
1976     KWQ_BLOCK_EXCEPTIONS;
1977
1978     _mouseDownView = nil;
1979
1980     NSEvent *oldCurrentEvent = _currentEvent;
1981     _currentEvent = [event retain];
1982     
1983     NSResponder *oldFirstResponderAtMouseDownTime = _firstResponderAtMouseDownTime;
1984     // Unlike other places in WebCore where we get the first
1985     // responder, in this case we must be talking about the real first
1986     // responder, so we could just ask the bridge's window, instead of
1987     // the bridge. It's unclear which is better.
1988     _firstResponderAtMouseDownTime = [[_bridge firstResponder] retain];
1989
1990     _mouseDownMayStartDrag = false;
1991     _mouseDownMayStartSelect = false;
1992
1993     // Sending an event can result in the destruction of the view and part.
1994     // We ref so that happens after we return from the KHTMLView function.
1995     v->ref();
1996     QMouseEvent kEvent(QEvent::MouseButtonPress, event);
1997     v->viewportMousePressEvent(&kEvent);
1998     v->deref();
1999     
2000     [_firstResponderAtMouseDownTime release];
2001     _firstResponderAtMouseDownTime = oldFirstResponderAtMouseDownTime;
2002
2003     ASSERT(_currentEvent == event);
2004     [event release];
2005     _currentEvent = oldCurrentEvent;
2006
2007     KWQ_UNBLOCK_EXCEPTIONS;
2008 }
2009
2010 void KWQKHTMLPart::mouseDragged(NSEvent *event)
2011 {
2012     KHTMLView *v = d->m_view;
2013     if (!v || _sendingEventToSubview) {
2014         return;
2015     }
2016
2017     KWQ_BLOCK_EXCEPTIONS;
2018
2019     NSEvent *oldCurrentEvent = _currentEvent;
2020     _currentEvent = [event retain];
2021
2022     // Sending an event can result in the destruction of the view and part.
2023     // We ref so that happens after we return from the KHTMLView function.
2024     v->ref();
2025     QMouseEvent kEvent(QEvent::MouseMove, event);
2026     v->viewportMouseMoveEvent(&kEvent);
2027     v->deref();
2028     
2029     ASSERT(_currentEvent == event);
2030     [event release];
2031     _currentEvent = oldCurrentEvent;
2032
2033     KWQ_UNBLOCK_EXCEPTIONS;
2034 }
2035
2036 void KWQKHTMLPart::mouseUp(NSEvent *event)
2037 {
2038     KHTMLView *v = d->m_view;
2039     if (!v || _sendingEventToSubview) {
2040         return;
2041     }
2042
2043     KWQ_BLOCK_EXCEPTIONS;
2044
2045     NSEvent *oldCurrentEvent = _currentEvent;
2046     _currentEvent = [event retain];
2047
2048     // Sending an event can result in the destruction of the view and part.
2049     // We ref so that happens after we return from the KHTMLView function.
2050     v->ref();
2051     // Our behavior here is a little different that Qt. Qt always sends
2052     // a mouse release event, even for a double click. To correct problems
2053     // in khtml's DOM click event handling we do not send a release here
2054     // for a double click. Instead we send that event from KHTMLView's
2055     // viewportMouseDoubleClickEvent. Note also that the third click of
2056     // a triple click is treated as a single click, but the fourth is then
2057     // treated as another double click. Hence the "% 2" below.
2058     int clickCount = [event clickCount];
2059     if (clickCount > 0 && clickCount % 2 == 0) {
2060         QMouseEvent doubleClickEvent(QEvent::MouseButtonDblClick, event);
2061         v->viewportMouseDoubleClickEvent(&doubleClickEvent);
2062     } else {
2063         QMouseEvent releaseEvent(QEvent::MouseButtonRelease, event);
2064         v->viewportMouseReleaseEvent(&releaseEvent);
2065     }
2066     v->deref();
2067     
2068     ASSERT(_currentEvent == event);
2069     [event release];
2070     _currentEvent = oldCurrentEvent;
2071     
2072     _mouseDownView = nil;
2073
2074     KWQ_UNBLOCK_EXCEPTIONS;
2075 }
2076
2077 /*
2078  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
2079  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
2080  is done, this routine is used to fix things up.  When a mouse down started us tracking in
2081  the widget, we post a fake mouse up to balance the mouse down we started with. When a 
2082  key down started us tracking in the widget, we post a fake key up to balance things out.
2083  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
2084  be over after the tracking is done.
2085  */
2086 void KWQKHTMLPart::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
2087 {
2088     KWQ_BLOCK_EXCEPTIONS;
2089
2090     _sendingEventToSubview = false;
2091     int eventType = [initiatingEvent type];
2092     ASSERT(eventType == NSLeftMouseDown || eventType == NSKeyDown);
2093     NSEvent *fakeEvent = nil;
2094     if (eventType == NSLeftMouseDown) {
2095         fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
2096                                 location:[initiatingEvent locationInWindow]
2097                             modifierFlags:[initiatingEvent modifierFlags]
2098                                 timestamp:[initiatingEvent timestamp]
2099                             windowNumber:[initiatingEvent windowNumber]
2100                                     context:[initiatingEvent context]
2101                                 eventNumber:[initiatingEvent eventNumber]
2102                                 clickCount:[initiatingEvent clickCount]
2103                                 pressure:[initiatingEvent pressure]];
2104     
2105         mouseUp(fakeEvent);
2106     }
2107     else { // eventType == NSKeyDown
2108         fakeEvent = [NSEvent keyEventWithType:NSKeyUp
2109                                 location:[initiatingEvent locationInWindow]
2110                            modifierFlags:[initiatingEvent modifierFlags]
2111                                timestamp:[initiatingEvent timestamp]
2112                             windowNumber:[initiatingEvent windowNumber]
2113                                  context:[initiatingEvent context]
2114                               characters:[initiatingEvent characters] 
2115              charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
2116                                isARepeat:[initiatingEvent isARepeat] 
2117                                  keyCode:[initiatingEvent keyCode]];
2118         keyEvent(fakeEvent);
2119     }
2120     // FIXME:  We should really get the current modifierFlags here, but there's no way to poll
2121     // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
2122     // no up-to-date cache of them anywhere.
2123     fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
2124                                    location:[[_bridge window] convertScreenToBase:[NSEvent mouseLocation]]
2125                               modifierFlags:[initiatingEvent modifierFlags]
2126                                   timestamp:[initiatingEvent timestamp]
2127                                windowNumber:[initiatingEvent windowNumber]
2128                                     context:[initiatingEvent context]
2129                                 eventNumber:0
2130                                  clickCount:0
2131                                    pressure:0];
2132     mouseMoved(fakeEvent);
2133
2134     KWQ_UNBLOCK_EXCEPTIONS;
2135 }
2136
2137 void KWQKHTMLPart::mouseMoved(NSEvent *event)
2138 {
2139     KHTMLView *v = d->m_view;
2140     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
2141     // These happen because WebKit sometimes has to fake up moved events.
2142     if (!v || d->m_bMousePressed) {
2143         return;
2144     }
2145     
2146     KWQ_BLOCK_EXCEPTIONS;
2147
2148     NSEvent *oldCurrentEvent = _currentEvent;
2149     _currentEvent = [event retain];
2150     
2151     // Sending an event can result in the destruction of the view and part.
2152     // We ref so that happens after we return from the KHTMLView function.
2153     v->ref();
2154     QMouseEvent kEvent(QEvent::MouseMove, event);
2155     v->viewportMouseMoveEvent(&kEvent);
2156     v->deref();
2157     
2158     ASSERT(_currentEvent == event);
2159     [event release];
2160     _currentEvent = oldCurrentEvent;
2161
2162     KWQ_UNBLOCK_EXCEPTIONS;
2163 }
2164
2165 bool KWQKHTMLPart::sendContextMenuEvent(NSEvent *event)
2166 {
2167     DocumentImpl *doc = d->m_doc;
2168     KHTMLView *v = d->m_view;
2169     if (!doc || !v) {
2170         return false;
2171     }
2172
2173     KWQ_BLOCK_EXCEPTIONS;
2174
2175     NSEvent *oldCurrentEvent = _currentEvent;
2176     _currentEvent = [event retain];
2177     
2178     QMouseEvent qev(QEvent::MouseButtonPress, event);
2179
2180     int xm, ym;
2181     v->viewportToContents(qev.x(), qev.y(), xm, ym);
2182
2183     NodeImpl::MouseEvent mev(qev.stateAfter(), NodeImpl::MousePress);
2184     doc->prepareMouseEvent(false, xm, ym, &mev);
2185
2186     // Sending an event can result in the destruction of the view and part.
2187     // We ref so that happens after we return from the KHTMLView function.
2188     v->ref();
2189     bool swallowEvent = v->dispatchMouseEvent(EventImpl::CONTEXTMENU_EVENT,
2190         mev.innerNode.handle(), true, 0, &qev, true, NodeImpl::MousePress);
2191     v->deref();
2192
2193     ASSERT(_currentEvent == event);
2194     [event release];
2195     _currentEvent = oldCurrentEvent;
2196
2197     return swallowEvent;
2198
2199     KWQ_UNBLOCK_EXCEPTIONS;
2200
2201     return false;
2202 }
2203
2204 struct ListItemInfo {
2205     unsigned start;
2206     unsigned end;
2207 };
2208
2209 NSFileWrapper *KWQKHTMLPart::fileWrapperForElement(ElementImpl *e)
2210 {
2211     KWQ_BLOCK_EXCEPTIONS;
2212     
2213     NSFileWrapper *wrapper = nil;
2214
2215     AtomicString attr = e->getAttribute(ATTR_SRC);
2216     if (!attr.isEmpty()) {
2217         NSURL *URL = completeURL(attr.string()).getNSURL();
2218         wrapper = [_bridge fileWrapperForURL:URL];
2219     }    
2220     if (!wrapper) {
2221         RenderImage *renderer = static_cast<RenderImage *>(e->renderer());
2222         NSImage *image = renderer->pixmap().image();
2223         NSData *tiffData = [image TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:0.0];
2224         wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:tiffData];
2225         [wrapper setPreferredFilename:@"image.tiff"];
2226         [wrapper autorelease];
2227     }
2228
2229     return wrapper;
2230     
2231     KWQ_UNBLOCK_EXCEPTIONS;
2232
2233     return nil;
2234 }
2235
2236 static ElementImpl *listParent(ElementImpl *item)
2237 {
2238     // Ick!  Avoid use of item->id() which confuses ObjC++.
2239     unsigned short _id = Node(item).elementId();
2240     
2241     while (_id != ID_UL && _id != ID_OL) {
2242         item = static_cast<ElementImpl *>(item->parentNode());
2243         if (!item)
2244             break;
2245         _id = Node(item).elementId();
2246     }
2247     return item;
2248 }
2249
2250 static NodeImpl* isTextFirstInListItem(NodeImpl *e)
2251 {
2252     if (Node(e).nodeType() != Node::TEXT_NODE)
2253         return 0;
2254     NodeImpl* par = e->parentNode();
2255     while (par) {
2256         if (par->firstChild() != e)
2257             return 0;
2258         if (Node(par).elementId() == ID_LI)
2259             return par;
2260         e = par;
2261         par = par->parentNode();
2262     }
2263     return 0;
2264 }
2265
2266 // FIXME: This collosal function needs to be refactored into maintainable smaller bits.
2267
2268 #define BULLET_CHAR 0x2022
2269 #define SQUARE_CHAR 0x25AA
2270 #define CIRCLE_CHAR 0x25E6
2271
2272 NSAttributedString *KWQKHTMLPart::attributedString(NodeImpl *_start, int startOffset, NodeImpl *endNode, int endOffset)
2273 {
2274     KWQ_BLOCK_EXCEPTIONS;
2275
2276     NodeImpl * _startNode = _start;
2277
2278     if (_startNode == nil) {
2279         return nil;
2280     }
2281
2282     NSMutableAttributedString *result = [[[NSMutableAttributedString alloc] init] autorelease];
2283
2284     bool hasNewLine = true;
2285     bool addedSpace = true;
2286     NSAttributedString *pendingStyledSpace = nil;
2287     bool hasParagraphBreak = true;
2288     const ElementImpl *linkStartNode = 0;
2289     unsigned linkStartLocation = 0;
2290     QPtrList<ElementImpl> listItems;
2291     QValueList<ListItemInfo> listItemLocations;
2292     float maxMarkerWidth = 0;
2293     
2294     Node n = _startNode;
2295     
2296     // If the first item is the entire text of a list item, use the list item node as the start of the 
2297     // selection, not the text node.  The user's intent was probably to select the list.
2298     if (n.nodeType() == Node::TEXT_NODE && startOffset == 0) {
2299         NodeImpl *startListNode = isTextFirstInListItem(_startNode);
2300         if (startListNode){
2301             _startNode = startListNode;
2302             n = _startNode;
2303         }
2304     }
2305     
2306     while (!n.isNull()) {
2307         RenderObject *renderer = n.handle()->renderer();
2308         if (renderer) {
2309             RenderStyle *style = renderer->style();
2310             NSFont *font = style->font().getNSFont();
2311             bool needSpace = pendingStyledSpace != nil;
2312             if (n.nodeType() == Node::TEXT_NODE) {
2313                 if (hasNewLine) {
2314                     addedSpace = true;
2315                     needSpace = false;
2316                     [pendingStyledSpace release];
2317                     pendingStyledSpace = nil;
2318                     hasNewLine = false;
2319                 }
2320                 QString text;
2321                 QString str = n.nodeValue().string();
2322                 int start = (n == _startNode) ? startOffset : -1;
2323                 int end = (n == endNode) ? endOffset : -1;
2324                 if (renderer->isText()) {
2325                     if (renderer->style()->whiteSpace() == PRE) {
2326                         if (needSpace && !addedSpace) {
2327                             if (text.isEmpty() && linkStartLocation == [result length]) {
2328                                 ++linkStartLocation;
2329                             }
2330                             [result appendAttributedString:pendingStyledSpace];
2331                         }
2332                         int runStart = (start == -1) ? 0 : start;
2333                         int runEnd = (end == -1) ? str.length() : end;
2334                         text += str.mid(runStart, runEnd-runStart);
2335                         [pendingStyledSpace release];
2336                         pendingStyledSpace = nil;
2337                         addedSpace = str[runEnd-1].direction() == QChar::DirWS;
2338                     }
2339                     else {
2340                         RenderText* textObj = static_cast<RenderText*>(renderer);
2341                         if (!textObj->firstTextBox() && str.length() > 0 && !addedSpace) {
2342                             // We have no runs, but we do have a length.  This means we must be
2343                             // whitespace that collapsed away at the end of a line.
2344                             text += " ";
2345                             addedSpace = true;
2346                         }
2347                         else {
2348                             addedSpace = false;
2349                             for (InlineTextBox* box = textObj->firstTextBox(); box; box = box->nextTextBox()) {
2350                                 int runStart = (start == -1) ? box->m_start : start;
2351                                 int runEnd = (end == -1) ? box->m_start + box->m_len : end;
2352                                 runEnd = kMin(runEnd, box->m_start + box->m_len);
2353                                 if (runStart >= box->m_start &&
2354                                     runStart < box->m_start + box->m_len) {
2355                                     if (box == textObj->firstTextBox() && box->m_start == runStart && runStart > 0) {
2356                                         needSpace = true; // collapsed space at the start
2357                                     }
2358                                     if (needSpace && !addedSpace) {
2359                                         if (pendingStyledSpace != nil) {
2360                                             if (text.isEmpty() && linkStartLocation == [result length]) {
2361                                                 ++linkStartLocation;
2362                                             }
2363                                             [result appendAttributedString:pendingStyledSpace];
2364                                         } else {
2365                                             text += ' ';
2366                                         }
2367                                     }
2368                                     QString runText = str.mid(runStart, runEnd - runStart);
2369                                     runText.replace('\n', ' ');
2370                                     text += runText;
2371                                     int nextRunStart = box->nextTextBox() ? box->nextTextBox()->m_start : str.length(); // collapsed space between runs or at the end
2372                                     needSpace = nextRunStart > runEnd;
2373                                     [pendingStyledSpace release];
2374                                     pendingStyledSpace = nil;
2375                                     addedSpace = str[runEnd-1].direction() == QChar::DirWS;
2376                                     start = -1;
2377                                 }
2378                                 if (end != -1 && runEnd >= end)
2379                                     break;
2380                             }
2381                         }
2382                     }
2383                 }
2384                 
2385                 text.replace('\\', renderer->backslashAsCurrencySymbol());
2386     
2387                 if (text.length() > 0 || needSpace) {
2388                     NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
2389                     [attrs setObject:font forKey:NSFontAttributeName];
2390                     if (style && style->color().isValid() && qAlpha(style->color().rgb()) != 0)
2391                         [attrs setObject:style->color().getNSColor() forKey:NSForegroundColorAttributeName];
2392                     if (style && style->backgroundColor().isValid() && qAlpha(style->backgroundColor().rgb()) != 0)
2393                         [attrs setObject:style->backgroundColor().getNSColor() forKey:NSBackgroundColorAttributeName];
2394
2395                     if (text.length() > 0) {
2396                         hasParagraphBreak = false;
2397                         NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString() attributes:attrs];
2398                         [result appendAttributedString: partialString];                
2399                         [partialString release];
2400                     }
2401
2402                     if (needSpace) {
2403                         [pendingStyledSpace release];
2404                         pendingStyledSpace = [[NSAttributedString alloc] initWithString:@" " attributes:attrs];
2405                     }
2406
2407                     [attrs release];
2408                 }
2409             } else {
2410                 // This is our simple HTML -> ASCII transformation:
2411                 QString text;
2412                 unsigned short _id = n.elementId();
2413                 switch(_id) {
2414                     case ID_A:
2415                         // Note the start of the <a> element.  We will add the NSLinkAttributeName
2416                         // attribute to the attributed string when navigating to the next sibling 
2417                         // of this node.
2418                         linkStartLocation = [result length];
2419                         linkStartNode = static_cast<ElementImpl*>(n.handle());
2420                         break;
2421
2422                     case ID_BR:
2423                         text += "\n";
2424                         hasNewLine = true;
2425                         break;
2426     
2427                     case ID_LI:
2428                         {
2429                             QString listText;
2430                             ElementImpl *itemParent = listParent(static_cast<ElementImpl *>(n.handle()));
2431                             
2432                             if (!hasNewLine)
2433                                 listText += '\n';
2434                             hasNewLine = true;
2435     
2436                             listItems.append(static_cast<ElementImpl*>(n.handle()));
2437                             ListItemInfo info;
2438                             info.start = [result length];
2439                             info.end = 0;
2440                             listItemLocations.append (info);
2441                             
2442                             listText += '\t';
2443                             if (itemParent){
2444                                 khtml::RenderListItem *listRenderer = static_cast<khtml::RenderListItem*>(renderer);
2445
2446                                 maxMarkerWidth = MAX([font pointSize], maxMarkerWidth);
2447                                 switch(listRenderer->style()->listStyleType()) {
2448                                     case khtml::DISC:
2449                                         listText += ((QChar)BULLET_CHAR);
2450                                         break;
2451                                     case khtml::CIRCLE:
2452                                         listText += ((QChar)CIRCLE_CHAR);
2453                                         break;
2454                                     case khtml::SQUARE:
2455                                         listText += ((QChar)SQUARE_CHAR);
2456                                         break;
2457                                     case khtml::LNONE:
2458                                         break;
2459                                     default:
2460                                         QString marker = listRenderer->markerStringValue();
2461                                         listText += marker;
2462                                         // Use AppKit metrics.  Will be rendered by AppKit.
2463                                         float markerWidth = [font widthOfString: marker.getNSString()];
2464                                         maxMarkerWidth = MAX(markerWidth, maxMarkerWidth);
2465                                 }
2466
2467                                 listText += ' ';
2468                                 listText += '\t';
2469     
2470                                 NSMutableDictionary *attrs;
2471             
2472                                 attrs = [[NSMutableDictionary alloc] init];
2473                                 [attrs setObject:font forKey:NSFontAttributeName];
2474                                 if (style && style->color().isValid())
2475                                     [attrs setObject:style->color().getNSColor() forKey:NSForegroundColorAttributeName];
2476                                 if (style && style->backgroundColor().isValid())
2477                                     [attrs setObject:style->backgroundColor().getNSColor() forKey:NSBackgroundColorAttributeName];
2478             
2479                                 NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:listText.getNSString() attributes:attrs];
2480                                 [attrs release];
2481                                 [result appendAttributedString: partialString];                
2482                                 [partialString release];
2483                             }
2484                         }
2485                         break;
2486
2487                     case ID_OL:
2488                     case ID_UL:
2489                         if (!hasNewLine)
2490                             text += "\n";
2491                         hasNewLine = true;
2492                         break;
2493
2494                     case ID_TD:
2495                     case ID_TH:
2496                     case ID_HR:
2497                     case ID_DD:
2498                     case ID_DL:
2499                     case ID_DT:
2500                     case ID_PRE:
2501                     case ID_BLOCKQUOTE:
2502                     case ID_DIV:
2503                         if (!hasNewLine)
2504                             text += '\n';
2505                         hasNewLine = true;
2506                         break;
2507                     case ID_P:
2508                     case ID_TR:
2509                     case ID_H1:
2510                     case ID_H2:
2511                     case ID_H3:
2512                     case ID_H4:
2513                     case ID_H5:
2514                     case ID_H6:
2515                         if (!hasNewLine)
2516                             text += '\n';
2517                         if (!hasParagraphBreak) {
2518                             text += '\n';
2519                             hasParagraphBreak = true;
2520                         }
2521                         hasNewLine = true;
2522                         break;
2523                         
2524                     case ID_IMG:
2525                         if (pendingStyledSpace != nil) {
2526                             if (linkStartLocation == [result length]) {
2527                                 ++linkStartLocation;
2528                             }
2529                             [result appendAttributedString:pendingStyledSpace];
2530                             [pendingStyledSpace release];
2531                             pendingStyledSpace = nil;
2532                         }
2533                         NSFileWrapper *fileWrapper = fileWrapperForElement(static_cast<ElementImpl *>(n.handle()));
2534                         NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
2535                         NSAttributedString *iString = [NSAttributedString attributedStringWithAttachment:attachment];
2536                         [result appendAttributedString: iString];
2537                         [attachment release];
2538                         break;
2539                 }
2540                 NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2541                 [result appendAttributedString: partialString];
2542                 [partialString release];
2543             }
2544         }
2545
2546         if (n == endNode)
2547             break;
2548
2549         Node next = n.firstChild();
2550         if (next.isNull()){
2551             next = n.nextSibling();
2552         }
2553
2554         while (next.isNull() && !n.parentNode().isNull()) {
2555             QString text;
2556             n = n.parentNode();
2557             if (n == endNode)
2558                 break;
2559             next = n.nextSibling();
2560
2561             unsigned short _id = n.elementId();
2562             switch(_id) {
2563                 case ID_A:
2564                     // End of a <a> element.  Create an attributed string NSLinkAttributeName attribute
2565                     // for the range of the link.  Note that we create the attributed string from the DOM, which
2566                     // will have corrected any illegally nested <a> elements.
2567                     if (linkStartNode && n.handle() == linkStartNode){
2568                         DOMString href = parseURL(linkStartNode->getAttribute(ATTR_HREF));
2569                         KURL kURL = KWQ(linkStartNode->getDocument()->part())->completeURL(href.string());
2570                         
2571                         NSURL *URL = kURL.getNSURL();
2572                         [result addAttribute:NSLinkAttributeName value:URL range:NSMakeRange(linkStartLocation, [result length]-linkStartLocation)];
2573                         linkStartNode = 0;
2574                     }
2575                     break;
2576                 
2577                 case ID_OL:
2578                 case ID_UL:
2579                     if (!hasNewLine)
2580                         text += '\n';
2581                     hasNewLine = true;
2582                     break;
2583
2584                 case ID_LI:
2585                     {
2586                         int i, count = listItems.count();
2587                         for (i = 0; i < count; i++){
2588                             if (listItems.at(i) == n.handle()){
2589                                 listItemLocations[i].end = [result length];
2590                                 break;
2591                             }
2592                         }
2593                     }
2594                     if (!hasNewLine)
2595                         text += '\n';
2596                     hasNewLine = true;
2597                     break;
2598
2599                 case ID_TD:
2600                 case ID_TH:
2601                 case ID_HR:
2602                 case ID_DD:
2603                 case ID_DL:
2604                 case ID_DT:
2605                 case ID_PRE:
2606                 case ID_BLOCKQUOTE:
2607                 case ID_DIV:
2608                     if (!hasNewLine)
2609                         text += '\n';
2610                     hasNewLine = true;
2611                     break;
2612                 case ID_P:
2613                 case ID_TR:
2614                 case ID_H1:
2615                 case ID_H2:
2616                 case ID_H3:
2617                 case ID_H4:
2618                 case ID_H5:
2619                 case ID_H6:
2620                     if (!hasNewLine)
2621                         text += '\n';
2622                     // An extra newline is needed at the start, not the end, of these types of tags,
2623                     // so don't add another here.
2624                     hasNewLine = true;
2625                     break;
2626             }
2627             
2628             NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2629             [result appendAttributedString:partialString];
2630             [partialString release];
2631         }
2632
2633         n = next;
2634     }
2635     
2636     [pendingStyledSpace release];
2637     
2638     // Apply paragraph styles from outside in.  This ensures that nested lists correctly
2639     // override their parent's paragraph style.
2640     {
2641         unsigned i, count = listItems.count();
2642         ElementImpl *e;
2643         ListItemInfo info;
2644
2645 #ifdef POSITION_LIST
2646         NodeImpl *containingBlock;
2647         int containingBlockX, containingBlockY;
2648         
2649         // Determine the position of the outermost containing block.  All paragraph
2650         // styles and tabs should be relative to this position.  So, the horizontal position of 
2651         // each item in the list (in the resulting attributed string) will be relative to position 
2652         // of the outermost containing block.
2653         if (count > 0){
2654             containingBlock = _startNode;
2655             while (containingBlock->renderer()->isInline()){
2656                 containingBlock = containingBlock->parentNode();
2657             }
2658             containingBlock->renderer()->absolutePosition(containingBlockX, containingBlockY);
2659         }
2660 #endif
2661         
2662         for (i = 0; i < count; i++){
2663             e = listItems.at(i);
2664             info = listItemLocations[i];
2665             
2666             if (info.end < info.start)
2667                 info.end = [result length];
2668                 
2669             RenderObject *r = e->renderer();
2670             RenderStyle *style = r->style();
2671
2672             int rx;
2673             NSFont *font = style->font().getNSFont();
2674             float pointSize = [font pointSize];
2675
2676 #ifdef POSITION_LIST
2677             int ry;
2678             r->absolutePosition(rx, ry);
2679             rx -= containingBlockX;
2680             
2681             // Ensure that the text is indented at least enough to allow for the markers.
2682             rx = MAX(rx, (int)maxMarkerWidth);
2683 #else
2684             rx = (int)MAX(maxMarkerWidth, pointSize);
2685 #endif
2686
2687             // The bullet text will be right aligned at the first tab marker, followed
2688             // by a space, followed by the list item text.  The space is arbitrarily
2689             // picked as pointSize*2/3.  The space on the first line of the text item
2690             // is established by a left aligned tab, on subsequent lines it's established
2691             // by the head indent.
2692             NSMutableParagraphStyle *mps = [[NSMutableParagraphStyle alloc] init];
2693             [mps setFirstLineHeadIndent: 0];
2694             [mps setHeadIndent: rx];
2695             [mps setTabStops:[NSArray arrayWithObjects:
2696                         [[[NSTextTab alloc] initWithType:NSRightTabStopType location:rx-(pointSize*2/3)] autorelease],
2697                         [[[NSTextTab alloc] initWithType:NSLeftTabStopType location:rx] autorelease],
2698                         nil]];
2699             [result addAttribute:NSParagraphStyleAttributeName value:mps range:NSMakeRange(info.start, info.end-info.start)];
2700             [mps release];
2701         }
2702     }
2703
2704     return result;
2705
2706     KWQ_UNBLOCK_EXCEPTIONS;
2707
2708     return nil;
2709 }
2710
2711 QRect KWQKHTMLPart::selectionRect() const
2712 {
2713     if(!xmlDocImpl()){
2714         return QRect();
2715     }
2716
2717     RenderCanvas *root = static_cast<RenderCanvas *>(xmlDocImpl()->renderer());
2718     if (!root) {
2719         return QRect();
2720
2721     }
2722
2723     return root->selectionRect();
2724 }
2725
2726 KWQWindowWidget *KWQKHTMLPart::topLevelWidget()
2727 {
2728     return _windowWidget;
2729 }
2730
2731 int KWQKHTMLPart::selectionStartOffset() const
2732 {
2733     return d->m_selection.start().offset();
2734 }
2735
2736 int KWQKHTMLPart::selectionEndOffset() const
2737 {
2738     return d->m_selection.end().offset();
2739 }
2740
2741 NodeImpl *KWQKHTMLPart::selectionStart() const
2742 {
2743     return d->m_selection.start().node();
2744 }
2745
2746 NodeImpl *KWQKHTMLPart::selectionEnd() const
2747 {
2748     return d->m_selection.end().node();
2749 }
2750
2751 void KWQKHTMLPart::setBridge(WebCoreBridge *p)
2752
2753     if (_bridge != p) {
2754         delete _windowWidget;
2755     }
2756     _bridge = p;
2757     _windowWidget = new KWQWindowWidget(_bridge);
2758 }
2759
2760 QString KWQKHTMLPart::overrideMediaType()
2761 {
2762     NSString *overrideType = [_bridge overrideMediaType];
2763     if (overrideType)
2764         return QString::fromNSString(overrideType);
2765     return QString();
2766 }
2767
2768 void KWQKHTMLPart::setMediaType(const QString &type)
2769 {
2770     if (d->m_view) {
2771         d->m_view->setMediaType(type);
2772     }
2773 }
2774
2775 void KWQKHTMLPart::setShowsFirstResponder(bool flag)
2776 {
2777     if (flag != _showsFirstResponder) {
2778         _showsFirstResponder = flag;
2779         DocumentImpl *doc = xmlDocImpl();
2780         if (doc) {
2781             NodeImpl *node = doc->focusNode();
2782             if (node && node->renderer())
2783                 node->renderer()->repaint();
2784         }
2785         setSelectionVisible(flag);
2786     }
2787 }
2788
2789 QChar KWQKHTMLPart::backslashAsCurrencySymbol() const
2790 {
2791     DocumentImpl *doc = xmlDocImpl();
2792     if (!doc) {
2793         return '\\';
2794     }
2795     Decoder *decoder = doc->decoder();
2796     if (!decoder) {
2797         return '\\';
2798     }
2799     const QTextCodec *codec = decoder->codec();
2800     if (!codec) {
2801         return '\\';
2802     }
2803     return codec->backslashAsCurrencySymbol();
2804 }
2805
2806 NSColor *KWQKHTMLPart::bodyBackgroundColor(void) const
2807 {
2808     HTMLDocumentImpl *doc = docImpl();
2809     
2810     if (doc){
2811         HTMLElementImpl *body = doc->body();
2812         QColor bgColor =  body->renderer()->style()->backgroundColor();
2813         
2814         if (bgColor.isValid())
2815             return bgColor.getNSColor();
2816     }
2817     return nil;
2818 }
2819
2820 WebCoreKeyboardUIMode KWQKHTMLPart::keyboardUIMode() const
2821 {
2822     KWQ_BLOCK_EXCEPTIONS;
2823     return [_bridge keyboardUIMode];
2824     KWQ_UNBLOCK_EXCEPTIONS;
2825
2826     return WebCoreKeyboardAccessDefault;
2827 }
2828
2829 void KWQKHTMLPart::setName(const QString &name)
2830 {
2831     QString n = name;
2832
2833     KWQKHTMLPart *parent = KWQ(parentPart());
2834
2835     if (parent && (name.isEmpty() || parent->frameExists(name))) {
2836         n = parent->requestFrameName();
2837     }
2838
2839     KHTMLPart::setName(n);
2840
2841     KWQ_BLOCK_EXCEPTIONS;
2842     [_bridge didSetName:n.getNSString()];
2843     KWQ_UNBLOCK_EXCEPTIONS;
2844 }
2845
2846
2847 void KWQKHTMLPart::didTellBridgeAboutLoad(const QString &urlString)
2848 {
2849     urlsBridgeKnowsAbout.insert(urlString, (char *)1);
2850 }
2851
2852
2853 bool KWQKHTMLPart::haveToldBridgeAboutLoad(const QString &urlString)
2854 {
2855     return urlsBridgeKnowsAbout.find(urlString) != 0;
2856 }
2857
2858 void KWQKHTMLPart::clear()
2859 {
2860     urlsBridgeKnowsAbout.clear();
2861     KHTMLPart::clear();
2862 }
2863
2864 void KWQKHTMLPart::print()
2865 {
2866     [_bridge print];
2867 }
2868
2869 KJS::Bindings::Instance *KWQKHTMLPart::getAppletInstanceForView (NSView *aView)
2870 {
2871     // Get a pointer to the actual Java applet instance.
2872     jobject applet = [_bridge pollForAppletInView:aView];
2873     
2874     if (applet)
2875         // Wrap the Java instance in a language neutral binding and hand
2876         // off ownership to the APPLET element.
2877         return KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::JavaLanguage, applet);
2878     
2879     return 0;
2880 }
2881
2882 void KWQKHTMLPart::addPluginRootObject(const KJS::Bindings::RootObject *root)
2883 {
2884     rootObjects.append (root);
2885 }
2886
2887 void KWQKHTMLPart::cleanupPluginRootObjects()
2888 {
2889     KJS::Bindings::RootObject *root;
2890     while ((root = rootObjects.getLast())) {
2891         root->removeAllNativeReferences ();
2892         rootObjects.removeLast();
2893     }
2894 }
2895
2896 void KWQKHTMLPart::registerCommandForUndo(const khtml::EditCommand &cmd)
2897 {
2898     ASSERT(cmd.handle());
2899
2900     KWQEditCommand *kwq = [KWQEditCommand commandWithEditCommandImpl:cmd.handle()];
2901     [_bridge registerCommandForUndo:kwq];
2902 }
2903
2904 void KWQKHTMLPart::registerCommandForRedo(const khtml::EditCommand &cmd)
2905 {
2906     ASSERT(cmd.handle());
2907
2908     KWQEditCommand *kwq = [KWQEditCommand commandWithEditCommandImpl:cmd.handle()];
2909     [_bridge registerCommandForRedo:kwq];
2910 }
2911
2912 void KWQKHTMLPart::clearUndoRedoOperations()
2913 {
2914     [_bridge clearUndoRedoOperations];
2915 }
2916
2917 void KWQKHTMLPart::editingKeyEvent()
2918 {
2919     [_bridge editingKeyDown:_currentEvent];
2920 }
2921
2922 void KWQKHTMLPart::issueUndoCommand()
2923 {
2924     [_bridge issueUndoCommand];
2925 }
2926
2927 void KWQKHTMLPart::issueRedoCommand()
2928 {
2929     [_bridge issueRedoCommand];
2930 }
2931
2932 void KWQKHTMLPart::issueCutCommand()
2933 {
2934     [_bridge issueCutCommand];
2935 }
2936
2937 void KWQKHTMLPart::issueCopyCommand()
2938 {
2939     [_bridge issueCopyCommand];
2940 }
2941
2942 void KWQKHTMLPart::issuePasteCommand()
2943 {
2944     [_bridge issuePasteCommand];
2945 }
2946
2947 void KWQKHTMLPart::postDidChangeSelectionNotification()
2948 {
2949     [_bridge postDidChangeSelectionNotification];
2950 }
2951
2952 void KWQKHTMLPart::postDidChangeNotification()
2953 {
2954     [_bridge postDidChangeNotification];
2955 }