731b15d55e9db8a9ca26b4f14b3e44a8b61e8371
[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     d->m_bComplete = true;
1571     d->m_doc->setParsing(false);
1572
1573     completed();
1574 }
1575
1576 bool KWQKHTMLPart::closeURL()
1577 {
1578     saveDocumentState();
1579     return KHTMLPart::closeURL();
1580 }
1581
1582 void KWQKHTMLPart::khtmlMousePressEvent(MousePressEvent *event)
1583 {
1584     // If we got the event back, that must mean it wasn't prevented,
1585     // so it's allowed to start a drag or selection.
1586     _mouseDownMayStartDrag = true;
1587     _mouseDownMayStartSelect = true;
1588
1589     if (!passWidgetMouseDownEventToWidget(event)) {
1590         // We don't do this at the start of mouse down handling (before calling into WebCore),
1591         // because we don't want to do it until we know we didn't hit a widget.
1592         NSView *view = d->m_view->getDocumentView();
1593
1594         KWQ_BLOCK_EXCEPTIONS;
1595         if ([_currentEvent clickCount] <= 1 && [_bridge firstResponder] != view) {
1596             [_bridge makeFirstResponder:view];
1597         }
1598         KWQ_UNBLOCK_EXCEPTIONS;
1599
1600         KHTMLPart::khtmlMousePressEvent(event);
1601     }
1602 }
1603
1604 void KWQKHTMLPart::khtmlMouseDoubleClickEvent(MouseDoubleClickEvent *event)
1605 {
1606     if (!passWidgetMouseDownEventToWidget(event)) {
1607         KHTMLPart::khtmlMouseDoubleClickEvent(event);
1608     }
1609 }
1610
1611 bool KWQKHTMLPart::passWidgetMouseDownEventToWidget(khtml::MouseEvent *event)
1612 {
1613     // Figure out which view to send the event to.
1614     RenderObject *target = event->innerNode().handle() ? event->innerNode().handle()->renderer() : 0;
1615     if (!target)
1616         return false;
1617
1618     QWidget* widget = RenderLayer::gScrollBar;
1619     if (!widget) {
1620         if (!target->isWidget())
1621             return false;
1622         widget = static_cast<RenderWidget *>(target)->widget();
1623     }
1624
1625     // Doubleclick events don't exist in Cocoa.  Since passWidgetMouseDownEventToWidget will
1626     // just pass _currentEvent down to the widget,  we don't want to call it for events that
1627     // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
1628     // part of the pressed/released handling.
1629     if (!MouseDoubleClickEvent::test(event))
1630         return passWidgetMouseDownEventToWidget(widget);
1631     else
1632         return true;
1633 }
1634
1635 bool KWQKHTMLPart::passWidgetMouseDownEventToWidget(RenderWidget *renderWidget)
1636 {
1637     return passWidgetMouseDownEventToWidget(renderWidget->widget());
1638 }
1639
1640 bool KWQKHTMLPart::passWidgetMouseDownEventToWidget(QWidget* widget)
1641 {
1642     // FIXME: this method always returns true
1643
1644     if (!widget) {
1645         ERROR("hit a RenderWidget without a corresponding QWidget, means a frame is half-constructed");
1646         return true;
1647     }
1648
1649     KWQ_BLOCK_EXCEPTIONS;
1650     
1651     NSView *nodeView = widget->getView();
1652     ASSERT(nodeView);
1653     ASSERT([nodeView superview]);
1654     NSView *topView = nodeView;
1655     NSView *superview;
1656     while ((superview = [topView superview])) {
1657         topView = superview;
1658     }
1659     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[_currentEvent locationInWindow] fromView:topView]];
1660     if (view == nil) {
1661         ERROR("KHTML says we hit a RenderWidget, but AppKit doesn't agree we hit the corresponding NSView");
1662         return true;
1663     }
1664     
1665     if ([_bridge firstResponder] == view) {
1666         // In the case where we just became first responder, we should send the mouseDown:
1667         // to the NSTextField, not the NSTextField's editor. This code makes sure that happens.
1668         // If we don't do this, we see a flash of selected text when clicking in a text field.
1669         if (_firstResponderAtMouseDownTime != view && [view isKindOfClass:[NSTextView class]]) {
1670             NSView *superview = view;
1671             while (superview != nodeView) {
1672                 superview = [superview superview];
1673                 ASSERT(superview);
1674                 if ([superview isKindOfClass:[NSControl class]]) {
1675                     NSControl *control = superview;
1676                     if ([control currentEditor] == view) {
1677                         view = superview;
1678                     }
1679                     break;
1680                 }
1681             }
1682         }
1683     } else {
1684         // Normally [NSWindow sendEvent:] handles setting the first responder.
1685         // But in our case, the event was sent to the view representing the entire web page.
1686         if ([_currentEvent clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) {
1687             [_bridge makeFirstResponder:view];
1688         }
1689     }
1690
1691     // We need to "defer loading" and defer timers while we are tracking the mouse.
1692     // That's because we don't want the new page to load while the user is holding the mouse down.
1693     
1694     BOOL wasDeferringLoading = [_bridge defersLoading];
1695     if (!wasDeferringLoading) {
1696         [_bridge setDefersLoading:YES];
1697     }
1698     BOOL wasDeferringTimers = QObject::defersTimers();
1699     if (!wasDeferringTimers) {
1700         QObject::setDefersTimers(true);
1701     }
1702
1703     ASSERT(!_sendingEventToSubview);
1704     _sendingEventToSubview = true;
1705     [view mouseDown:_currentEvent];
1706     _sendingEventToSubview = false;
1707     
1708     if (!wasDeferringTimers) {
1709         QObject::setDefersTimers(false);
1710     }
1711     if (!wasDeferringLoading) {
1712         [_bridge setDefersLoading:NO];
1713     }
1714
1715     // Remember which view we sent the event to, so we can direct the release event properly.
1716     _mouseDownView = view;
1717     _mouseDownWasInSubframe = false;
1718
1719     KWQ_UNBLOCK_EXCEPTIONS;
1720
1721     return true;
1722 }
1723
1724 bool KWQKHTMLPart::lastEventIsMouseUp()
1725 {
1726     // Many AK widgets run their own event loops and consume events while the mouse is down.
1727     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
1728     // the khtml state with this mouseUp, which khtml never saw.  This method lets us detect
1729     // that state.
1730
1731     KWQ_BLOCK_EXCEPTIONS;
1732     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
1733     if (_currentEvent != currentEventAfterHandlingMouseDown) {
1734         if ([currentEventAfterHandlingMouseDown type] == NSLeftMouseUp) {
1735             return true;
1736         }
1737     }
1738     KWQ_UNBLOCK_EXCEPTIONS;
1739
1740     return false;
1741 }
1742     
1743 // Note that this does the same kind of check as [target isDescendantOf:superview].
1744 // There are two differences: This is a lot slower because it has to walk the whole
1745 // tree, and this works in cases where the target has already been deallocated.
1746 static bool findViewInSubviews(NSView *superview, NSView *target)
1747 {
1748     KWQ_BLOCK_EXCEPTIONS;
1749     NSEnumerator *e = [[superview subviews] objectEnumerator];
1750     NSView *subview;
1751     while ((subview = [e nextObject])) {
1752         if (subview == target || findViewInSubviews(subview, target)) {
1753             return true;
1754         }
1755     }
1756     KWQ_UNBLOCK_EXCEPTIONS;
1757     
1758     return false;
1759 }
1760
1761 NSView *KWQKHTMLPart::mouseDownViewIfStillGood()
1762 {
1763     // Since we have no way of tracking the lifetime of _mouseDownView, we have to assume that
1764     // it could be deallocated already. We search for it in our subview tree; if we don't find
1765     // it, we set it to nil.
1766     NSView *mouseDownView = _mouseDownView;
1767     if (!mouseDownView) {
1768         return nil;
1769     }
1770     KHTMLView *topKHTMLView = d->m_view;
1771     NSView *topView = topKHTMLView ? topKHTMLView->getView() : nil;
1772     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
1773         _mouseDownView = nil;
1774         return nil;
1775     }
1776     return mouseDownView;
1777 }
1778
1779 void KWQKHTMLPart::khtmlMouseMoveEvent(MouseMoveEvent *event)
1780 {
1781     KWQ_BLOCK_EXCEPTIONS;
1782
1783     if ([_currentEvent type] == NSLeftMouseDragged) {
1784         NSView *view = mouseDownViewIfStillGood();
1785
1786         if (view) {
1787             _sendingEventToSubview = true;
1788             [view mouseDragged:_currentEvent];
1789             _sendingEventToSubview = false;
1790             return;
1791         }
1792
1793         if (_mouseDownMayStartDrag &&
1794             !d->m_selectionInitiatedWithDoubleClick &&
1795             !d->m_selectionInitiatedWithTripleClick &&
1796             [_bridge mayStartDragWithMouseDragged:_currentEvent])
1797         {
1798             // We are starting a text/image/url drag, so the cursor should be an arrow
1799             d->m_view->resetCursor();
1800             [_bridge handleMouseDragged:_currentEvent];
1801             return;
1802         } else if (_mouseDownMayStartSelect) {
1803             // we use khtml's selection but our own autoscrolling
1804             [_bridge handleAutoscrollForMouseDragged:_currentEvent];
1805             // Don't allow dragging after we've started selecting.
1806             _mouseDownMayStartDrag = false;
1807         } else {
1808             return;
1809         }
1810     } else {
1811         // If we allowed the other side of the bridge to handle a drag
1812         // last time, then m_bMousePressed might still be set. So we
1813         // clear it now to make sure the next move after a drag
1814         // doesn't look like a drag.
1815         d->m_bMousePressed = false;
1816     }
1817
1818     KHTMLPart::khtmlMouseMoveEvent(event);
1819
1820     KWQ_UNBLOCK_EXCEPTIONS;
1821 }
1822
1823 void KWQKHTMLPart::khtmlMouseReleaseEvent(MouseReleaseEvent *event)
1824 {
1825     NSView *view = mouseDownViewIfStillGood();
1826     if (!view) {
1827         KHTMLPart::khtmlMouseReleaseEvent(event);
1828         return;
1829     }
1830     
1831     _sendingEventToSubview = true;
1832     KWQ_BLOCK_EXCEPTIONS;
1833     [view mouseUp:_currentEvent];
1834     KWQ_UNBLOCK_EXCEPTIONS;
1835     _sendingEventToSubview = false;
1836 }
1837
1838 void KWQKHTMLPart::clearTimers(KHTMLView *view)
1839 {
1840     if (view) {
1841         view->unscheduleRelayout();
1842         if (view->part()) {
1843             DocumentImpl* document = view->part()->xmlDocImpl();
1844             if (document && document->renderer() && document->renderer()->layer())
1845                 document->renderer()->layer()->suspendMarquees();
1846         }
1847     }
1848 }
1849
1850 void KWQKHTMLPart::clearTimers()
1851 {
1852     clearTimers(d->m_view);
1853 }
1854
1855 bool KWQKHTMLPart::passSubframeEventToSubframe(NodeImpl::MouseEvent &event)
1856 {
1857     KWQ_BLOCK_EXCEPTIONS;
1858
1859     switch ([_currentEvent type]) {
1860         case NSLeftMouseDown: {
1861             NodeImpl *node = event.innerNode.handle();
1862             if (!node) {
1863                 return false;
1864             }
1865             RenderPart *renderPart = dynamic_cast<RenderPart *>(node->renderer());
1866             if (!renderPart) {
1867                 return false;
1868             }
1869             if (!passWidgetMouseDownEventToWidget(renderPart)) {
1870                 return false;
1871             }
1872             _mouseDownWasInSubframe = true;
1873             return true;
1874         }
1875         case NSLeftMouseUp: {
1876             if (!_mouseDownWasInSubframe) {
1877                 return false;
1878             }
1879             NSView *view = mouseDownViewIfStillGood();
1880             if (!view) {
1881                 return false;
1882             }
1883             ASSERT(!_sendingEventToSubview);
1884             _sendingEventToSubview = true;
1885             [view mouseUp:_currentEvent];
1886             _sendingEventToSubview = false;
1887             return true;
1888         }
1889         case NSLeftMouseDragged: {
1890             if (!_mouseDownWasInSubframe) {
1891                 return false;
1892             }
1893             NSView *view = mouseDownViewIfStillGood();
1894             if (!view) {
1895                 return false;
1896             }
1897             ASSERT(!_sendingEventToSubview);
1898             _sendingEventToSubview = true;
1899             [view mouseDragged:_currentEvent];
1900             _sendingEventToSubview = false;
1901             return true;
1902         }
1903         default:
1904             return false;
1905     }
1906     KWQ_UNBLOCK_EXCEPTIONS;
1907
1908     return false;
1909 }
1910
1911 void KWQKHTMLPart::mouseDown(NSEvent *event)
1912 {
1913     KHTMLView *v = d->m_view;
1914     if (!v || _sendingEventToSubview) {
1915         return;
1916     }
1917
1918     KWQ_BLOCK_EXCEPTIONS;
1919
1920     _mouseDownView = nil;
1921
1922     NSEvent *oldCurrentEvent = _currentEvent;
1923     _currentEvent = [event retain];
1924     
1925     NSResponder *oldFirstResponderAtMouseDownTime = _firstResponderAtMouseDownTime;
1926     // Unlike other places in WebCore where we get the first
1927     // responder, in this case we must be talking about the real first
1928     // responder, so we could just ask the bridge's window, instead of
1929     // the bridge. It's unclear which is better.
1930     _firstResponderAtMouseDownTime = [[_bridge firstResponder] retain];
1931
1932     _mouseDownMayStartDrag = false;
1933     _mouseDownMayStartSelect = false;
1934
1935     // Sending an event can result in the destruction of the view and part.
1936     // We ref so that happens after we return from the KHTMLView function.
1937     v->ref();
1938     QMouseEvent kEvent(QEvent::MouseButtonPress, event);
1939     v->viewportMousePressEvent(&kEvent);
1940     v->deref();
1941     
1942     [_firstResponderAtMouseDownTime release];
1943     _firstResponderAtMouseDownTime = oldFirstResponderAtMouseDownTime;
1944
1945     ASSERT(_currentEvent == event);
1946     [event release];
1947     _currentEvent = oldCurrentEvent;
1948
1949     KWQ_UNBLOCK_EXCEPTIONS;
1950 }
1951
1952 void KWQKHTMLPart::mouseDragged(NSEvent *event)
1953 {
1954     KHTMLView *v = d->m_view;
1955     if (!v || _sendingEventToSubview) {
1956         return;
1957     }
1958
1959     KWQ_BLOCK_EXCEPTIONS;
1960
1961     NSEvent *oldCurrentEvent = _currentEvent;
1962     _currentEvent = [event retain];
1963
1964     // Sending an event can result in the destruction of the view and part.
1965     // We ref so that happens after we return from the KHTMLView function.
1966     v->ref();
1967     QMouseEvent kEvent(QEvent::MouseMove, event);
1968     v->viewportMouseMoveEvent(&kEvent);
1969     v->deref();
1970     
1971     ASSERT(_currentEvent == event);
1972     [event release];
1973     _currentEvent = oldCurrentEvent;
1974
1975     KWQ_UNBLOCK_EXCEPTIONS;
1976 }
1977
1978 void KWQKHTMLPart::mouseUp(NSEvent *event)
1979 {
1980     KHTMLView *v = d->m_view;
1981     if (!v || _sendingEventToSubview) {
1982         return;
1983     }
1984
1985     KWQ_BLOCK_EXCEPTIONS;
1986
1987     NSEvent *oldCurrentEvent = _currentEvent;
1988     _currentEvent = [event retain];
1989
1990     // Sending an event can result in the destruction of the view and part.
1991     // We ref so that happens after we return from the KHTMLView function.
1992     v->ref();
1993     // Our behavior here is a little different that Qt. Qt always sends
1994     // a mouse release event, even for a double click. To correct problems
1995     // in khtml's DOM click event handling we do not send a release here
1996     // for a double click. Instead we send that event from KHTMLView's
1997     // viewportMouseDoubleClickEvent. Note also that the third click of
1998     // a triple click is treated as a single click, but the fourth is then
1999     // treated as another double click. Hence the "% 2" below.
2000     int clickCount = [event clickCount];
2001     if (clickCount > 0 && clickCount % 2 == 0) {
2002         QMouseEvent doubleClickEvent(QEvent::MouseButtonDblClick, event);
2003         v->viewportMouseDoubleClickEvent(&doubleClickEvent);
2004     } else {
2005         QMouseEvent releaseEvent(QEvent::MouseButtonRelease, event);
2006         v->viewportMouseReleaseEvent(&releaseEvent);
2007     }
2008     v->deref();
2009     
2010     ASSERT(_currentEvent == event);
2011     [event release];
2012     _currentEvent = oldCurrentEvent;
2013     
2014     _mouseDownView = nil;
2015
2016     KWQ_UNBLOCK_EXCEPTIONS;
2017 }
2018
2019 /*
2020  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
2021  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
2022  is done, this routine is used to fix things up.  When a mouse down started us tracking in
2023  the widget, we post a fake mouse up to balance the mouse down we started with. When a 
2024  key down started us tracking in the widget, we post a fake key up to balance things out.
2025  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
2026  be over after the tracking is done.
2027  */
2028 void KWQKHTMLPart::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
2029 {
2030     KWQ_BLOCK_EXCEPTIONS;
2031
2032     _sendingEventToSubview = false;
2033     int eventType = [initiatingEvent type];
2034     ASSERT(eventType == NSLeftMouseDown || eventType == NSKeyDown);
2035     NSEvent *fakeEvent = nil;
2036     if (eventType == NSLeftMouseDown) {
2037         fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
2038                                 location:[initiatingEvent locationInWindow]
2039                             modifierFlags:[initiatingEvent modifierFlags]
2040                                 timestamp:[initiatingEvent timestamp]
2041                             windowNumber:[initiatingEvent windowNumber]
2042                                     context:[initiatingEvent context]
2043                                 eventNumber:[initiatingEvent eventNumber]
2044                                 clickCount:[initiatingEvent clickCount]
2045                                 pressure:[initiatingEvent pressure]];
2046     
2047         mouseUp(fakeEvent);
2048     }
2049     else { // eventType == NSKeyDown
2050         fakeEvent = [NSEvent keyEventWithType:NSKeyUp
2051                                 location:[initiatingEvent locationInWindow]
2052                            modifierFlags:[initiatingEvent modifierFlags]
2053                                timestamp:[initiatingEvent timestamp]
2054                             windowNumber:[initiatingEvent windowNumber]
2055                                  context:[initiatingEvent context]
2056                               characters:[initiatingEvent characters] 
2057              charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
2058                                isARepeat:[initiatingEvent isARepeat] 
2059                                  keyCode:[initiatingEvent keyCode]];
2060         keyEvent(fakeEvent);
2061     }
2062     // FIXME:  We should really get the current modifierFlags here, but there's no way to poll
2063     // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
2064     // no up-to-date cache of them anywhere.
2065     fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
2066                                    location:[[_bridge window] convertScreenToBase:[NSEvent mouseLocation]]
2067                               modifierFlags:[initiatingEvent modifierFlags]
2068                                   timestamp:[initiatingEvent timestamp]
2069                                windowNumber:[initiatingEvent windowNumber]
2070                                     context:[initiatingEvent context]
2071                                 eventNumber:0
2072                                  clickCount:0
2073                                    pressure:0];
2074     mouseMoved(fakeEvent);
2075
2076     KWQ_UNBLOCK_EXCEPTIONS;
2077 }
2078
2079 void KWQKHTMLPart::mouseMoved(NSEvent *event)
2080 {
2081     KHTMLView *v = d->m_view;
2082     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
2083     // These happen because WebKit sometimes has to fake up moved events.
2084     if (!v || d->m_bMousePressed) {
2085         return;
2086     }
2087     
2088     KWQ_BLOCK_EXCEPTIONS;
2089
2090     NSEvent *oldCurrentEvent = _currentEvent;
2091     _currentEvent = [event retain];
2092     
2093     // Sending an event can result in the destruction of the view and part.
2094     // We ref so that happens after we return from the KHTMLView function.
2095     v->ref();
2096     QMouseEvent kEvent(QEvent::MouseMove, event);
2097     v->viewportMouseMoveEvent(&kEvent);
2098     v->deref();
2099     
2100     ASSERT(_currentEvent == event);
2101     [event release];
2102     _currentEvent = oldCurrentEvent;
2103
2104     KWQ_UNBLOCK_EXCEPTIONS;
2105 }
2106
2107 bool KWQKHTMLPart::sendContextMenuEvent(NSEvent *event)
2108 {
2109     DocumentImpl *doc = d->m_doc;
2110     KHTMLView *v = d->m_view;
2111     if (!doc || !v) {
2112         return false;
2113     }
2114
2115     KWQ_BLOCK_EXCEPTIONS;
2116
2117     NSEvent *oldCurrentEvent = _currentEvent;
2118     _currentEvent = [event retain];
2119     
2120     QMouseEvent qev(QEvent::MouseButtonPress, event);
2121
2122     int xm, ym;
2123     v->viewportToContents(qev.x(), qev.y(), xm, ym);
2124
2125     NodeImpl::MouseEvent mev(qev.stateAfter(), NodeImpl::MousePress);
2126     doc->prepareMouseEvent(false, xm, ym, &mev);
2127
2128     // Sending an event can result in the destruction of the view and part.
2129     // We ref so that happens after we return from the KHTMLView function.
2130     v->ref();
2131     bool swallowEvent = v->dispatchMouseEvent(EventImpl::CONTEXTMENU_EVENT,
2132         mev.innerNode.handle(), true, 0, &qev, true, NodeImpl::MousePress);
2133     v->deref();
2134
2135     ASSERT(_currentEvent == event);
2136     [event release];
2137     _currentEvent = oldCurrentEvent;
2138
2139     return swallowEvent;
2140
2141     KWQ_UNBLOCK_EXCEPTIONS;
2142
2143     return false;
2144 }
2145
2146 struct ListItemInfo {
2147     unsigned start;
2148     unsigned end;
2149 };
2150
2151 NSFileWrapper *KWQKHTMLPart::fileWrapperForElement(ElementImpl *e)
2152 {
2153     KWQ_BLOCK_EXCEPTIONS;
2154     
2155     NSFileWrapper *wrapper = nil;
2156
2157     DOMString attr = e->getAttribute(ATTR_SRC);
2158     if (!attr.isEmpty()) {
2159         NSURL *URL = completeURL(attr.string()).getNSURL();
2160         wrapper = [_bridge fileWrapperForURL:URL];
2161     }    
2162     if (!wrapper) {
2163         RenderImage *renderer = static_cast<RenderImage *>(e->renderer());
2164         NSImage *image = renderer->pixmap().image();
2165         NSData *tiffData = [image TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:0.0];
2166         wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:tiffData];
2167         [wrapper setPreferredFilename:@"image.tiff"];
2168         [wrapper autorelease];
2169     }
2170
2171     return wrapper;
2172     
2173     KWQ_UNBLOCK_EXCEPTIONS;
2174
2175     return nil;
2176 }
2177
2178 static ElementImpl *listParent(ElementImpl *item)
2179 {
2180     // Ick!  Avoid use of item->id() which confuses ObjC++.
2181     unsigned short _id = Node(item).elementId();
2182     
2183     while (_id != ID_UL && _id != ID_OL) {
2184         item = static_cast<ElementImpl *>(item->parentNode());
2185         if (!item)
2186             break;
2187         _id = Node(item).elementId();
2188     }
2189     return item;
2190 }
2191
2192 static NodeImpl* isTextFirstInListItem(NodeImpl *e)
2193 {
2194     if (Node(e).nodeType() != Node::TEXT_NODE)
2195         return 0;
2196     NodeImpl* par = e->parentNode();
2197     while (par) {
2198         if (par->firstChild() != e)
2199             return 0;
2200         if (Node(par).elementId() == ID_LI)
2201             return par;
2202         e = par;
2203         par = par->parentNode();
2204     }
2205     return 0;
2206 }
2207
2208 #define BULLET_CHAR 0x2022
2209 #define SQUARE_CHAR 0x25AA
2210 #define CIRCLE_CHAR 0x25E6
2211
2212 NSAttributedString *KWQKHTMLPart::attributedString(NodeImpl *_start, int startOffset, NodeImpl *endNode, int endOffset)
2213 {
2214     KWQ_BLOCK_EXCEPTIONS;
2215
2216     NodeImpl * _startNode = _start;
2217
2218     if (_startNode == nil) {
2219         return nil;
2220     }
2221
2222     // This allocation and autorelease won't raise so it's OK to do it
2223     // outside the exception block
2224     NSMutableAttributedString *result = [[[NSMutableAttributedString alloc] init] autorelease];
2225
2226     bool hasNewLine = true;
2227     bool addedSpace = true;
2228     bool hasParagraphBreak = true;
2229     const ElementImpl *linkStartNode = 0;
2230     unsigned linkStartLocation = 0;
2231     QPtrList<ElementImpl> listItems;
2232     QValueList<ListItemInfo> listItemLocations;
2233     float maxMarkerWidth = 0;
2234     
2235     Node n = _startNode;
2236     
2237     // If the first item is the entire text of a list item, use the list item node as the start of the 
2238     // selection, not the text node.  The user's intent was probably to select the list.
2239     if (n.nodeType() == Node::TEXT_NODE && startOffset == 0) {
2240         NodeImpl *startListNode = isTextFirstInListItem(_startNode);
2241         if (startListNode){
2242             _startNode = startListNode;
2243             n = _startNode;
2244         }
2245     }
2246     
2247     while (!n.isNull()) {
2248         RenderObject *renderer = n.handle()->renderer();
2249         if (renderer) {
2250             RenderStyle *style = renderer->style();
2251             NSFont *font = style->font().getNSFont();
2252             if (n.nodeType() == Node::TEXT_NODE) {
2253                 if (hasNewLine) {
2254                     addedSpace = true;
2255                     hasNewLine = false;
2256                 }
2257                 QString text;
2258                 QString str = n.nodeValue().string();
2259                 int start = (n == _startNode) ? startOffset : -1;
2260                 int end = (n == endNode) ? endOffset : -1;
2261                 if (renderer->isText()) {
2262                     if (renderer->style()->whiteSpace() == PRE) {
2263                         int runStart = (start == -1) ? 0 : start;
2264                         int runEnd = (end == -1) ? str.length() : end;
2265                         text += str.mid(runStart, runEnd-runStart);
2266                         addedSpace = str[runEnd-1].direction() == QChar::DirWS;
2267                     }
2268                     else {
2269                         RenderText* textObj = static_cast<RenderText*>(renderer);
2270                         InlineTextBoxArray runs = textObj->inlineTextBoxes();
2271                         if (runs.count() == 0 && str.length() > 0 && !addedSpace) {
2272                             // We have no runs, but we do have a length.  This means we must be
2273                             // whitespace that collapsed away at the end of a line.
2274                             text += " ";
2275                             addedSpace = true;
2276                         }
2277                         else {
2278                             addedSpace = false;
2279                             for (unsigned i = 0; i < runs.count(); i++) {
2280                                 int runStart = (start == -1) ? runs[i]->m_start : start;
2281                                 int runEnd = (end == -1) ? runs[i]->m_start + runs[i]->m_len : end;
2282                                 runEnd = QMIN(runEnd, runs[i]->m_start + runs[i]->m_len);
2283                                 bool spaceBetweenRuns = false;
2284                                 if (runStart >= runs[i]->m_start &&
2285                                     runStart < runs[i]->m_start + runs[i]->m_len) {
2286                                     QString runText = str.mid(runStart, runEnd - runStart);
2287                                     runText.replace('\n', ' ');
2288                                     text += runText;
2289                                     start = -1;
2290                                     spaceBetweenRuns = i+1 < runs.count() && runs[i+1]->m_start > runEnd;
2291                                     addedSpace = str[runEnd-1].direction() == QChar::DirWS;
2292                                 }
2293                                 if (end != -1 && runEnd >= end)
2294                                     break;
2295
2296                                 if (spaceBetweenRuns && !addedSpace) {
2297                                     text += " ";
2298                                     addedSpace = true;
2299                                 }
2300                             }
2301                         }
2302                     }
2303                 }
2304                 
2305                 text.replace('\\', renderer->backslashAsCurrencySymbol());
2306     
2307                 if (text.length() > 0) {
2308                     hasParagraphBreak = false;
2309                     NSMutableDictionary *attrs;
2310
2311                     attrs = [[NSMutableDictionary alloc] init];
2312                     [attrs setObject:font forKey:NSFontAttributeName];
2313                     if (style && style->color().isValid())
2314                         [attrs setObject:style->color().getNSColor() forKey:NSForegroundColorAttributeName];
2315                     if (style && style->backgroundColor().isValid())
2316                         [attrs setObject:style->backgroundColor().getNSColor() forKey:NSBackgroundColorAttributeName];
2317
2318                     NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString() attributes:attrs];
2319                     [attrs release];
2320                     [result appendAttributedString: partialString];                
2321                     [partialString release];
2322                 }
2323             } else {
2324                 // This is our simple HTML -> ASCII transformation:
2325                 QString text;
2326                 unsigned short _id = n.elementId();
2327                 switch(_id) {
2328                     case ID_A:
2329                         // Note the start of the <a> element.  We will add the NSLinkAttributeName
2330                         // attribute to the attributed string when navigating to the next sibling 
2331                         // of this node.
2332                         linkStartLocation = [result length];
2333                         linkStartNode = static_cast<ElementImpl*>(n.handle());
2334                         break;
2335
2336                     case ID_BR:
2337                         text += "\n";
2338                         hasNewLine = true;
2339                         break;
2340     
2341                     case ID_LI:
2342                         {
2343                             QString listText;
2344                             ElementImpl *itemParent = listParent(static_cast<ElementImpl *>(n.handle()));
2345                             
2346                             if (!hasNewLine)
2347                                 listText += '\n';
2348                             hasNewLine = true;
2349     
2350                             listItems.append(static_cast<ElementImpl*>(n.handle()));
2351                             ListItemInfo info;
2352                             info.start = [result length];
2353                             info.end = 0;
2354                             listItemLocations.append (info);
2355                             
2356                             listText += '\t';
2357                             if (itemParent){
2358                                 // Ick!  Avoid use of itemParent->id() which confuses ObjC++.
2359                                 khtml::RenderListItem *listRenderer = static_cast<khtml::RenderListItem*>(renderer);
2360
2361                                 maxMarkerWidth = MAX([font pointSize], maxMarkerWidth);
2362                                 switch(listRenderer->style()->listStyleType()) {
2363                                     case khtml::DISC:
2364                                         listText += ((QChar)BULLET_CHAR);
2365                                         break;
2366                                     case khtml::CIRCLE:
2367                                         listText += ((QChar)CIRCLE_CHAR);
2368                                         break;
2369                                     case khtml::SQUARE:
2370                                         listText += ((QChar)SQUARE_CHAR);
2371                                         break;
2372                                     case khtml::LNONE:
2373                                         break;
2374                                     default:
2375                                         QString marker = listRenderer->markerStringValue();
2376                                         listText += marker;
2377                                         // Use AppKit metrics.  Will be rendered by AppKit.
2378                                         float markerWidth = [font widthOfString: marker.getNSString()];
2379                                         maxMarkerWidth = MAX(markerWidth, maxMarkerWidth);
2380                                 }
2381
2382                                 listText += ' ';
2383                                 listText += '\t';
2384     
2385                                 NSMutableDictionary *attrs;
2386             
2387                                 attrs = [[NSMutableDictionary alloc] init];
2388                                 [attrs setObject:font forKey:NSFontAttributeName];
2389                                 if (style && style->color().isValid())
2390                                     [attrs setObject:style->color().getNSColor() forKey:NSForegroundColorAttributeName];
2391                                 if (style && style->backgroundColor().isValid())
2392                                     [attrs setObject:style->backgroundColor().getNSColor() forKey:NSBackgroundColorAttributeName];
2393             
2394                                 NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:listText.getNSString() attributes:attrs];
2395                                 [attrs release];
2396                                 [result appendAttributedString: partialString];                
2397                                 [partialString release];
2398                             }
2399                         }
2400                         break;
2401
2402                     case ID_OL:
2403                     case ID_UL:
2404                         if (!hasNewLine)
2405                             text += "\n";
2406                         hasNewLine = true;
2407                         break;
2408
2409                     case ID_TD:
2410                     case ID_TH:
2411                     case ID_HR:
2412                     case ID_DD:
2413                     case ID_DL:
2414                     case ID_DT:
2415                     case ID_PRE:
2416                     case ID_BLOCKQUOTE:
2417                     case ID_DIV:
2418                         if (!hasNewLine)
2419                             text += '\n';
2420                         hasNewLine = true;
2421                         break;
2422                     case ID_P:
2423                     case ID_TR:
2424                     case ID_H1:
2425                     case ID_H2:
2426                     case ID_H3:
2427                     case ID_H4:
2428                     case ID_H5:
2429                     case ID_H6:
2430                         if (!hasNewLine)
2431                             text += '\n';
2432                         if (!hasParagraphBreak) {
2433                             text += '\n';
2434                             hasParagraphBreak = true;
2435                         }
2436                         hasNewLine = true;
2437                         break;
2438                         
2439                     case ID_IMG:
2440                         NSFileWrapper *fileWrapper = fileWrapperForElement(static_cast<ElementImpl *>(n.handle()));
2441                         NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
2442                         NSAttributedString *iString = [NSAttributedString attributedStringWithAttachment:attachment];
2443                         [result appendAttributedString: iString];
2444                         [attachment release];
2445                         break;
2446                 }
2447                 NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2448                 [result appendAttributedString: partialString];
2449                 [partialString release];
2450             }
2451         }
2452
2453         if (n == endNode)
2454             break;
2455
2456         Node next = n.firstChild();
2457         if (next.isNull()){
2458             next = n.nextSibling();
2459         }
2460
2461         while (next.isNull() && !n.parentNode().isNull()) {
2462             QString text;
2463             n = n.parentNode();
2464             if (n == endNode)
2465                 break;
2466             next = n.nextSibling();
2467
2468             unsigned short _id = n.elementId();
2469             switch(_id) {
2470                 case ID_A:
2471                     // End of a <a> element.  Create an attributed string NSLinkAttributeName attribute
2472                     // for the range of the link.  Note that we create the attributed string from the DOM, which
2473                     // will have corrected any illegally nested <a> elements.
2474                     if (linkStartNode && n.handle() == linkStartNode){
2475                         DOMString href = parseURL(linkStartNode->getAttribute(ATTR_HREF));
2476                         KURL kURL = KWQ(linkStartNode->getDocument()->part())->completeURL(href.string());
2477                         
2478                         NSURL *URL = kURL.getNSURL();
2479                         [result addAttribute:NSLinkAttributeName value:URL range:NSMakeRange(linkStartLocation, [result length]-linkStartLocation)];
2480                         linkStartNode = 0;
2481                     }
2482                     break;
2483                 
2484                 case ID_OL:
2485                 case ID_UL:
2486                     if (!hasNewLine)
2487                         text += '\n';
2488                     hasNewLine = true;
2489                     break;
2490
2491                 case ID_LI:
2492                     {
2493                         int i, count = listItems.count();
2494                         for (i = 0; i < count; i++){
2495                             if (listItems.at(i) == n.handle()){
2496                                 listItemLocations[i].end = [result length];
2497                                 break;
2498                             }
2499                         }
2500                     }
2501                     if (!hasNewLine)
2502                         text += '\n';
2503                     hasNewLine = true;
2504                     break;
2505
2506                 case ID_TD:
2507                 case ID_TH:
2508                 case ID_HR:
2509                 case ID_DD:
2510                 case ID_DL:
2511                 case ID_DT:
2512                 case ID_PRE:
2513                 case ID_BLOCKQUOTE:
2514                 case ID_DIV:
2515                     if (!hasNewLine)
2516                         text += '\n';
2517                     hasNewLine = true;
2518                     break;
2519                 case ID_P:
2520                 case ID_TR:
2521                 case ID_H1:
2522                 case ID_H2:
2523                 case ID_H3:
2524                 case ID_H4:
2525                 case ID_H5:
2526                 case ID_H6:
2527                     if (!hasNewLine)
2528                         text += '\n';
2529                     // An extra newline is needed at the start, not the end, of these types of tags,
2530                     // so don't add another here.
2531                     hasNewLine = true;
2532                     break;
2533             }
2534             
2535             NSAttributedString *partialString = [[NSAttributedString alloc] initWithString:text.getNSString()];
2536             [result appendAttributedString:partialString];
2537             [partialString release];
2538         }
2539
2540         n = next;
2541     }
2542     
2543     // Apply paragraph styles from outside in.  This ensures that nested lists correctly
2544     // override their parent's paragraph style.
2545     {
2546         unsigned i, count = listItems.count();
2547         ElementImpl *e;
2548         ListItemInfo info;
2549
2550 #ifdef POSITION_LIST
2551         NodeImpl *containingBlock;
2552         int containingBlockX, containingBlockY;
2553         
2554         // Determine the position of the outermost containing block.  All paragraph
2555         // styles and tabs should be relative to this position.  So, the horizontal position of 
2556         // each item in the list (in the resulting attributed string) will be relative to position 
2557         // of the outermost containing block.
2558         if (count > 0){
2559             containingBlock = _startNode;
2560             while (containingBlock->renderer()->isInline()){
2561                 containingBlock = containingBlock->parentNode();
2562             }
2563             containingBlock->renderer()->absolutePosition(containingBlockX, containingBlockY);
2564         }
2565 #endif
2566         
2567         for (i = 0; i < count; i++){
2568             e = listItems.at(i);
2569             info = listItemLocations[i];
2570             
2571             if (info.end < info.start)
2572                 info.end = [result length];
2573                 
2574             RenderObject *r = e->renderer();
2575             RenderStyle *style = r->style();
2576
2577             int rx;
2578             NSFont *font = style->font().getNSFont();
2579             float pointSize = [font pointSize];
2580
2581 #ifdef POSITION_LIST
2582             int ry;
2583             r->absolutePosition(rx, ry);
2584             rx -= containingBlockX;
2585             
2586             // Ensure that the text is indented at least enough to allow for the markers.
2587             rx = MAX(rx, (int)maxMarkerWidth);
2588 #else
2589             rx = (int)MAX(maxMarkerWidth, pointSize);
2590 #endif
2591
2592             // The bullet text will be right aligned at the first tab marker, followed
2593             // by a space, followed by the list item text.  The space is arbitrarily
2594             // picked as pointSize*2/3.  The space on the first line of the text item
2595             // is established by a left aligned tab, on subsequent lines it's established
2596             // by the head indent.
2597             NSMutableParagraphStyle *mps = [[NSMutableParagraphStyle alloc] init];
2598             [mps setFirstLineHeadIndent: 0];
2599             [mps setHeadIndent: rx];
2600             [mps setTabStops:[NSArray arrayWithObjects:
2601                         [[[NSTextTab alloc] initWithType:NSRightTabStopType location:rx-(pointSize*2/3)] autorelease],
2602                         [[[NSTextTab alloc] initWithType:NSLeftTabStopType location:rx] autorelease],
2603                         nil]];
2604             [result addAttribute:NSParagraphStyleAttributeName value:mps range:NSMakeRange(info.start, info.end-info.start)];
2605             [mps release];
2606         }
2607     }
2608
2609     return result;
2610
2611     KWQ_UNBLOCK_EXCEPTIONS;
2612
2613     return nil;
2614 }
2615
2616 QRect KWQKHTMLPart::selectionRect() const
2617 {
2618     if(!xmlDocImpl()){
2619         return QRect();
2620     }
2621
2622     RenderCanvas *root = static_cast<RenderCanvas *>(xmlDocImpl()->renderer());
2623     if (!root) {
2624         return QRect();
2625
2626     }
2627
2628     return root->selectionRect();
2629 }
2630
2631 KWQWindowWidget *KWQKHTMLPart::topLevelWidget()
2632 {
2633     return _windowWidget;
2634 }
2635
2636 int KWQKHTMLPart::selectionStartOffset() const
2637 {
2638     return d->m_startOffset;
2639 }
2640
2641 int KWQKHTMLPart::selectionEndOffset() const
2642 {
2643     return d->m_endOffset;
2644 }
2645
2646 NodeImpl *KWQKHTMLPart::selectionStart() const
2647 {
2648     return d->m_selectionStart.handle();
2649 }
2650
2651 NodeImpl *KWQKHTMLPart::selectionEnd() const
2652 {
2653     return d->m_selectionEnd.handle();
2654 }
2655
2656 void KWQKHTMLPart::setBridge(WebCoreBridge *p)
2657
2658     if (_bridge != p) {
2659         delete _windowWidget;
2660     }
2661     _bridge = p;
2662     _windowWidget = new KWQWindowWidget(_bridge);
2663 }
2664
2665 void KWQKHTMLPart::setMediaType(const QString &type)
2666 {
2667     if (d->m_view) {
2668         d->m_view->setMediaType(type);
2669     }
2670 }
2671
2672 void KWQKHTMLPart::setShowsFirstResponder(bool flag)
2673 {
2674     if (flag != _showsFirstResponder) {
2675         _showsFirstResponder = flag;
2676         DocumentImpl *doc = xmlDocImpl();
2677         if (doc) {
2678             NodeImpl *node = doc->focusNode();
2679             if (node && node->renderer())
2680                 node->renderer()->repaint();
2681         }
2682     }
2683 }
2684
2685 QChar KWQKHTMLPart::backslashAsCurrencySymbol() const
2686 {
2687     DocumentImpl *doc = xmlDocImpl();
2688     if (!doc) {
2689         return '\\';
2690     }
2691     Decoder *decoder = doc->decoder();
2692     if (!decoder) {
2693         return '\\';
2694     }
2695     const QTextCodec *codec = decoder->codec();
2696     if (!codec) {
2697         return '\\';
2698     }
2699     return codec->backslashAsCurrencySymbol();
2700 }
2701
2702 NSColor *KWQKHTMLPart::bodyBackgroundColor(void) const
2703 {
2704     HTMLDocumentImpl *doc = docImpl();
2705     
2706     if (doc){
2707         HTMLElementImpl *body = doc->body();
2708         QColor bgColor =  body->renderer()->style()->backgroundColor();
2709         
2710         if (bgColor.isValid())
2711             return bgColor.getNSColor();
2712     }
2713     return nil;
2714 }
2715
2716 WebCoreKeyboardUIMode KWQKHTMLPart::keyboardUIMode() const
2717 {
2718     KWQ_BLOCK_EXCEPTIONS;
2719     return [_bridge keyboardUIMode];
2720     KWQ_UNBLOCK_EXCEPTIONS;
2721
2722     return WebCoreKeyboardAccessDefault;
2723 }
2724
2725 void KWQKHTMLPart::setName(const QString &name)
2726 {
2727     QString n = name;
2728
2729     KWQKHTMLPart *parent = KWQ(parentPart());
2730
2731     if (parent && (name.isEmpty() || parent->frameExists(name))) {
2732         n = parent->requestFrameName();
2733     }
2734
2735     KHTMLPart::setName(n);
2736
2737     KWQ_BLOCK_EXCEPTIONS;
2738     [_bridge didSetName:n.getNSString()];
2739     KWQ_UNBLOCK_EXCEPTIONS;
2740 }
2741
2742
2743 void KWQKHTMLPart::didTellBridgeAboutLoad(const QString &urlString)
2744 {
2745     urlsBridgeKnowsAbout.insert(urlString, (char *)1);
2746 }
2747
2748
2749 bool KWQKHTMLPart::haveToldBridgeAboutLoad(const QString &urlString)
2750 {
2751     return urlsBridgeKnowsAbout.find(urlString) != 0;
2752 }
2753
2754 void KWQKHTMLPart::clear()
2755 {
2756     urlsBridgeKnowsAbout.clear();
2757     KHTMLPart::clear();
2758 }
2759
2760 void KWQKHTMLPart::print()
2761 {
2762     [_bridge print];
2763 }
2764
2765 KJS::Bindings::Instance *KWQKHTMLPart::getAppletInstanceForView (NSView *aView)
2766 {
2767     // Get a pointer to the actual Java applet instance.
2768     jobject applet = [_bridge pollForAppletInView:aView];
2769     
2770     if (applet)
2771         // Wrap the Java instance in a language neutral binding and hand
2772         // off ownership to the APPLET element.
2773         return KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::JavaLanguage, applet);
2774     
2775     return 0;
2776 }
2777
2778 void KWQKHTMLPart::addPluginRootObject(const KJS::Bindings::RootObject *root)
2779 {
2780     rootObjects.append (root);
2781 }
2782
2783 void KWQKHTMLPart::cleanupPluginRootObjects()
2784 {
2785     KJS::Bindings::RootObject *root;
2786     while ((root = rootObjects.getLast())) {
2787         KJS::Bindings::RootObject::removeAllJavaReferencesForRoot (root);
2788         rootObjects.removeLast();
2789     }
2790 }
2791