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