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