Reviewed by John
[WebKit-https.git] / WebCore / kwq / WebCoreBridge.mm
1 /*
2  * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "WebCoreBridge.h"
27
28 #import "csshelper.h"
29 #import "dom2_eventsimpl.h"
30 #import "dom2_rangeimpl.h"
31 #import "dom2_viewsimpl.h"
32 #import "dom_docimpl.h"
33 #import "dom_node.h"
34 #import "dom_nodeimpl.h"
35 #import "dom_position.h"
36 #import "html_documentimpl.h"
37 #import "html_formimpl.h"
38 #import "html_imageimpl.h"
39 #import "htmlattrs.h"
40 #import "htmlediting.h"
41 #import "htmltags.h"
42 #import "khtml_part.h"
43 #import "khtmlview.h"
44 #import "kjs_proxy.h"
45 #import "kjs_window.h"
46 #import "loader.h"
47 #import "markup.h"
48 #import "render_canvas.h"
49 #import "render_frames.h"
50 #import "render_image.h"
51 #import "render_object.h"
52 #import "render_replaced.h"
53 #import "render_style.h"
54 #import "selection.h"
55 #import "visible_position.h"
56 #import "xml_tokenizer.h"
57
58 #import <JavaScriptCore/npruntime.h>
59 #import <JavaScriptCore/jni_jsobject.h>
60 #import <JavaScriptCore/object.h>
61 #import <JavaScriptCore/runtime_root.h>
62 #import <JavaScriptCore/property_map.h>
63
64 #import "KWQAssertions.h"
65 #import "KWQCharsets.h"
66 #import "KWQClipboard.h"
67 #import "KWQDOMNode.h"
68 #import "KWQEditCommand.h"
69 #import "KWQFont.h"
70 #import "KWQFoundationExtras.h"
71 #import "KWQFrame.h"
72 #import "KWQKHTMLPart.h"
73 #import "KWQLoader.h"
74 #import "KWQPageState.h"
75 #import "KWQRenderTreeDebug.h"
76 #import "KWQView.h"
77 #import "KWQPrinter.h"
78 #import "KWQAccObjectCache.h"
79
80 #import "DOMInternal.h"
81 #import "WebCoreImageRenderer.h"
82 #import "WebCoreTextRendererFactory.h"
83 #import "WebCoreViewFactory.h"
84 #import "WebCoreSettings.h"
85
86 @class NSView;
87
88 using DOM::AtomicString;
89 using DOM::CSSStyleDeclarationImpl;
90 using DOM::DocumentFragmentImpl;
91 using DOM::DocumentImpl;
92 using DOM::DocumentTypeImpl;
93 using DOM::DOMString;
94 using DOM::Element;
95 using DOM::ElementImpl;
96 using DOM::HTMLElementImpl;
97 using DOM::HTMLFormElementImpl;
98 using DOM::HTMLGenericFormElementImpl;
99 using DOM::HTMLImageElementImpl;
100 using DOM::HTMLInputElementImpl;
101 using DOM::Node;
102 using DOM::NodeImpl;
103 using DOM::Position;
104 using DOM::Range;
105
106 using khtml::ChildrenOnly;
107 using khtml::createMarkup;
108 using khtml::Decoder;
109 using khtml::DeleteSelectionCommand;
110 using khtml::EAffinity;
111 using khtml::EditAction;
112 using khtml::EditCommandPtr;
113 using khtml::ETextGranularity;
114 using khtml::IncludeNode;
115 using khtml::MoveSelectionCommand;
116 using khtml::parseURL;
117 using khtml::RenderCanvas;
118 using khtml::RenderImage;
119 using khtml::RenderObject;
120 using khtml::RenderPart;
121 using khtml::RenderStyle;
122 using khtml::RenderWidget;
123 using khtml::ReplaceSelectionCommand;
124 using khtml::Selection;
125 using khtml::Tokenizer;
126 using khtml::TypingCommand;
127 using khtml::UPSTREAM;
128 using khtml::VisiblePosition;
129
130 using KJS::ExecState;
131 using KJS::ObjectImp;
132 using KJS::SavedProperties;
133 using KJS::SavedBuiltins;
134 using KJS::Window;
135
136 using KParts::URLArgs;
137
138 using KJS::Bindings::RootObject;
139
140 NSString *WebCoreElementDOMNodeKey =            @"WebElementDOMNode";
141 NSString *WebCoreElementFrameKey =              @"WebElementFrame";
142 NSString *WebCoreElementImageAltStringKey =     @"WebElementImageAltString";
143 NSString *WebCoreElementImageKey =              @"WebElementImage";
144 NSString *WebCoreElementImageRectKey =          @"WebElementImageRect";
145 NSString *WebCoreElementImageURLKey =           @"WebElementImageURL";
146 NSString *WebCoreElementIsSelectedKey =         @"WebElementIsSelected";
147 NSString *WebCoreElementLinkURLKey =            @"WebElementLinkURL";
148 NSString *WebCoreElementLinkTargetFrameKey =    @"WebElementTargetFrame";
149 NSString *WebCoreElementLinkLabelKey =          @"WebElementLinkLabel";
150 NSString *WebCoreElementLinkTitleKey =          @"WebElementLinkTitle";
151 NSString *WebCoreElementNameKey =               @"WebElementName";
152 NSString *WebCoreElementTitleKey =              @"WebCoreElementTitle"; // not in WebKit API for now, could be in API some day
153
154 NSString *WebCorePageCacheStateKey =            @"WebCorePageCacheState";
155
156 @interface WebCoreBridge (WebCoreBridgeInternal)
157 - (RootObject *)executionContextForView:(NSView *)aView;
158 @end
159
160 static RootObject *rootForView(void *v)
161 {
162     NSView *aView = (NSView *)v;
163     WebCoreBridge *aBridge = [[WebCoreViewFactory sharedFactory] bridgeForView:aView];
164     RootObject *root = 0;
165
166     if (aBridge)
167         root = [aBridge executionContextForView:aView];
168
169     return root;
170 }
171
172 static pthread_t mainThread = 0;
173
174 static void updateRenderingForBindings (ExecState *exec, ObjectImp *rootObject)
175 {
176     if (pthread_self() != mainThread)
177         return;
178         
179     if (!rootObject)
180         return;
181         
182     Window *window = static_cast<Window*>(rootObject);
183     if (!window)
184         return;
185         
186     DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(window->part()->document().handle());
187     if (doc)
188         doc->updateRendering();
189 }
190
191 static BOOL partHasSelection(WebCoreBridge *bridge)
192 {
193     if (!bridge)
194         return NO;
195     
196     KHTMLPart *part = bridge->_part;
197     if (!part)
198         return NO;
199         
200     if (part->selection().isNone())
201         return NO;
202
203     // If a part has a selection, it should also have a document.        
204     ASSERT(part->xmlDocImpl());
205
206     return YES;
207 }
208
209 @implementation WebCoreBridge
210
211 static bool initializedObjectCacheSize = FALSE;
212 static bool initializedKJS = FALSE;
213
214 + (WebCoreBridge *)bridgeForDOMDocument:(DOMDocument *)document
215 {
216     return ((KWQKHTMLPart *)[document _documentImpl]->part())->bridge();
217 }
218
219 - init
220 {
221     [super init];
222     
223     _part = new KWQKHTMLPart;
224     _part->setBridge(self);
225
226     if (!initializedObjectCacheSize){
227         khtml::Cache::setSize([self getObjectCacheSize]);
228         initializedObjectCacheSize = TRUE;
229     }
230     
231     if (!initializedKJS) {
232         mainThread = pthread_self();
233         
234         RootObject::setFindRootObjectForNativeHandleFunction (rootForView);
235
236         KJS::Bindings::Instance::setDidExecuteFunction(updateRenderingForBindings);
237         
238         initializedKJS = TRUE;
239     }
240     
241     _shouldCreateRenderers = YES;
242     
243     return self;
244 }
245
246 - (void)initializeSettings: (WebCoreSettings *)settings
247 {
248     _part->setSettings ([settings settings]);
249 }
250
251 - (void)dealloc
252 {
253     [self removeFromFrame];
254     
255     if (_renderPart) {
256         _renderPart->deref(_renderPartArena);
257     }
258     _part->setBridge(nil);
259     _part->deref();
260         
261     [super dealloc];
262 }
263
264 - (void)finalize
265 {
266     // FIXME: This work really should not be done at deallocation time.
267     // We need to do it at some well-defined time instead.
268
269     [self removeFromFrame];
270     
271     if (_renderPart) {
272         _renderPart->deref(_renderPartArena);
273     }
274     _part->setBridge(nil);
275     _part->deref();
276         
277     [super finalize];
278 }
279
280 - (KWQKHTMLPart *)part
281 {
282     return _part;
283 }
284
285 - (void)setRenderPart:(KHTMLRenderPart *)newPart;
286 {
287     RenderArena *arena = newPart->ref();
288     if (_renderPart) {
289         _renderPart->deref(_renderPartArena);
290     }
291     _renderPart = newPart;
292     _renderPartArena = arena;
293 }
294
295 - (KHTMLRenderPart *)renderPart
296 {
297     return _renderPart;
298 }
299
300 - (void)setParent:(WebCoreBridge *)parent
301 {
302     _part->setParent([parent part]);
303 }
304
305 - (void)provisionalLoadStarted
306 {
307     _part->provisionalLoadStarted();
308 }
309
310 - (void)openURL:(NSURL *)URL reload:(BOOL)reload contentType:(NSString *)contentType refresh:(NSString *)refresh lastModified:(NSDate *)lastModified pageCache:(NSDictionary *)pageCache
311 {
312     if (pageCache) {
313         KWQPageState *state = [pageCache objectForKey:WebCorePageCacheStateKey];
314         _part->openURLFromPageCache(state);
315         [state invalidate];
316         return;
317     }
318         
319     // arguments
320     URLArgs args(_part->browserExtension()->urlArgs());
321     args.reload = reload;
322     if (contentType) {
323         args.serviceType = QString::fromNSString(contentType);
324     }
325     _part->browserExtension()->setURLArgs(args);
326
327     // opening the URL
328     if (_part->didOpenURL(URL)) {
329         // things we have to set up after calling didOpenURL
330         if (refresh) {
331             _part->addMetaData("http-refresh", QString::fromNSString(refresh));
332         }
333         if (lastModified) {
334             NSString *modifiedString = [lastModified descriptionWithCalendarFormat:@"%a %b %d %Y %H:%M:%S" timeZone:nil locale:nil];
335             _part->addMetaData("modified", QString::fromNSString(modifiedString));
336         }
337     }
338 }
339
340 - (void)setEncoding:(NSString *)encoding userChosen:(BOOL)userChosen
341 {
342     _part->setEncoding(QString::fromNSString(encoding), userChosen);
343 }
344
345 - (void)addData:(NSData *)data
346 {
347     DocumentImpl *doc = _part->xmlDocImpl();
348     
349     // Document may be nil if the part is about to redirect
350     // as a result of JS executing during load, i.e. one frame
351     // changing another's location before the frame's document
352     // has been created. 
353     if (doc){
354         doc->setShouldCreateRenderers([self shouldCreateRenderers]);
355         _part->addData((const char *)[data bytes], [data length]);
356     }
357 }
358
359 - (void)closeURL
360 {
361     _part->closeURL();
362 }
363
364 - (void)didNotOpenURL:(NSURL *)URL pageCache:(NSDictionary *)pageCache
365 {
366     _part->didNotOpenURL(KURL(URL).url());
367
368     // We might have made a page cache item, but now we're bailing out due to an error before we ever
369     // transitioned to the new page (before WebFrameState==commit).  The goal here is to restore any state
370     // so that the existing view (that wenever got far enough to replace) can continue being used.
371     DocumentImpl *doc = _part->xmlDocImpl();
372     if (doc) {
373         doc->setInPageCache(NO);
374     }
375     KWQPageState *state = [pageCache objectForKey:WebCorePageCacheStateKey];
376     [state invalidate];
377 }
378
379 - (void)saveDocumentState
380 {
381     DocumentImpl *doc = _part->xmlDocImpl();
382     if (doc != 0){
383         QStringList list = doc->docState();
384         NSMutableArray *documentState = [[[NSMutableArray alloc] init] autorelease];
385         
386         for (uint i = 0; i < list.count(); i++){
387             QString s = list[i];
388             [documentState addObject: [NSString stringWithCharacters: (const unichar *)s.unicode() length: s.length()]];
389         }
390         [self saveDocumentState: documentState];
391     }
392 }
393
394 - (void)restoreDocumentState
395 {
396     DocumentImpl *doc = _part->xmlDocImpl();
397     
398     if (doc != 0){
399         NSArray *documentState = [self documentState];
400         
401         QStringList s;
402         for (uint i = 0; i < [documentState count]; i++){
403             NSString *string = [documentState objectAtIndex: i];
404             s.append(QString::fromNSString(string));
405         }
406             
407         doc->setRestoreState(s);
408     }
409 }
410
411 - (void)scrollToAnchorWithURL:(NSURL *)URL
412 {
413     _part->scrollToAnchor(KURL(URL).url().latin1());
414 }
415
416 - (BOOL)scrollOverflowInDirection:(WebScrollDirection)direction granularity:(WebScrollGranularity)granularity
417 {
418     if (_part == NULL) {
419         return NO;
420     }
421     return _part->scrollOverflow((KWQScrollDirection)direction, (KWQScrollGranularity)granularity);
422 }
423
424 - (BOOL)scrollOverflowWithScrollWheelEvent:(NSEvent *)event
425 {
426     if (_part == NULL) {
427         return NO;
428     }    
429     return _part->scrollOverflowWithScrollWheelEvent(event);
430 }
431
432 - (BOOL)saveDocumentToPageCache
433 {
434     DocumentImpl *doc = _part->xmlDocImpl();
435     if (!doc) {
436         return NO;
437     }
438     
439     if (!doc->view()) {
440         return NO;
441     }
442     _part->clearTimers();
443
444     SavedProperties *windowProperties = new SavedProperties;
445     _part->saveWindowProperties(windowProperties);
446
447     SavedProperties *locationProperties = new SavedProperties;
448     _part->saveLocationProperties(locationProperties);
449     
450     SavedBuiltins *interpreterBuiltins = new SavedBuiltins;
451     _part->saveInterpreterBuiltins(*interpreterBuiltins);
452
453     KWQPageState *pageState = [[[KWQPageState alloc] initWithDocument:doc
454                                                                   URL:_part->m_url
455                                                      windowProperties:windowProperties
456                                                    locationProperties:locationProperties
457                                                   interpreterBuiltins:interpreterBuiltins] autorelease];
458     [pageState setPausedActions: _part->pauseActions((const void *)pageState)];
459
460     return [self saveDocumentToPageCache:pageState];
461 }
462
463 - (BOOL)canCachePage
464 {
465     return _part->canCachePage();
466 }
467
468 - (void)clear
469 {
470     _part->clear();
471 }
472
473 - (void)end
474 {
475     _part->end();
476 }
477
478 - (void)stop
479 {
480     _part->stop();
481 }
482
483 - (void)createKHTMLViewWithNSView:(NSView *)view marginWidth:(int)mw marginHeight:(int)mh
484 {
485     // If we own the view, delete the old one - otherwise the render _part will take care of deleting the view.
486     [self removeFromFrame];
487
488     KHTMLView *kview = new KHTMLView(_part, 0);
489     _part->setView(kview);
490     kview->deref();
491
492     kview->setView(view);
493     if (mw >= 0)
494         kview->setMarginWidth(mw);
495     if (mh >= 0)
496         kview->setMarginHeight(mh);
497 }
498
499 - (void)scrollToAnchor:(NSString *)a
500 {
501     _part->gotoAnchor(QString::fromNSString(a));
502 }
503
504 - (BOOL)isSelectionEditable
505 {
506     // EDIT FIXME: This needs to consider the entire selected range
507     NodeImpl *startNode = _part->selection().start().node();
508     return startNode ? startNode->isContentEditable() : NO;
509 }
510
511 - (WebSelectionState)selectionState
512 {
513     switch (_part->selection().state()) {
514         case Selection::NONE:
515             return WebSelectionStateNone;
516         case Selection::CARET:
517             return WebSelectionStateCaret;
518         case Selection::RANGE:
519             return WebSelectionStateRange;
520     }
521     
522     ASSERT_NOT_REACHED();
523     return WebSelectionStateNone;
524 }
525
526 - (NSString *)_documentTypeString
527 {
528     NSString *documentTypeString = nil;
529     DOM::DocumentImpl *doc = _part->xmlDocImpl();
530     if (doc) {
531         DocumentTypeImpl *doctype = doc->doctype();
532         if (doctype) {
533             documentTypeString = doctype->toString().string().getNSString();
534         }
535     }
536     return documentTypeString;
537 }
538
539 - (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString
540 {
541     NSString *documentTypeString = [self _documentTypeString];
542     if (documentTypeString && markupString) {
543         return [NSString stringWithFormat:@"%@%@", documentTypeString, markupString];
544     } else if (documentTypeString) {
545         return documentTypeString;
546     } else if (markupString) {
547         return markupString;
548     } else {
549         return @"";
550     }
551 }
552
553 - (NSArray *)nodesFromList:(QPtrList<NodeImpl> *)nodeList
554 {
555     NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:nodeList->count()];
556     for (QPtrListIterator<NodeImpl> i(*nodeList); i.current(); ++i) {
557         [nodes addObject:[DOMNode _nodeWithImpl:i.current()]];
558     }
559     return nodes;
560 }
561
562 - (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes
563 {
564     // FIXME: This is never "for interchange". Is that right? See the next method.
565     QPtrList<NodeImpl> nodeList;
566     NSString *markupString = createMarkup([node _nodeImpl], IncludeNode, nodes ? &nodeList : 0).getNSString();
567     if (nodes) {
568         *nodes = [self nodesFromList:&nodeList];
569     }
570     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
571 }
572
573 - (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
574 {
575     // FIXME: This is always "for interchange". Is that right? See the previous method.
576     QPtrList<NodeImpl> nodeList;
577     NSString *markupString = createMarkup([range _rangeImpl], nodes ? &nodeList : 0, AnnotateForInterchange).getNSString();
578     if (nodes) {
579         *nodes = [self nodesFromList:&nodeList];
580     }
581     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
582 }
583
584 - (NSString *)selectedString
585 {
586     QString text = _part->selectedText();
587     text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
588     return [[text.getNSString() copy] autorelease];
589 }
590
591 - (NSString *)stringForRange:(DOMRange *)range
592 {
593     QString text = _part->text([range _rangeImpl]);
594     text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
595     return [[text.getNSString() copy] autorelease];
596 }
597
598 - (void)selectAll
599 {
600     _part->selectAll();
601 }
602
603 - (void)deselectAll
604 {
605     [self deselectText];
606     DocumentImpl *doc = _part->xmlDocImpl();
607     if (doc) {
608         doc->setFocusNode(0);
609     }
610 }
611
612 - (void)deselectText
613 {
614     _part->clearSelection();
615 }
616
617 - (BOOL)isFrameSet
618 {
619     return _part->isFrameSet();
620 }
621
622 - (NSString *)styleSheetForPrinting
623 {
624     if (!_part->settings()->shouldPrintBackgrounds()) {
625         return @"* { background-image: none !important; background-color: white !important;}";
626     }
627     return nil;
628 }
629
630 - (void)reapplyStylesForDeviceType:(WebCoreDeviceType)deviceType
631 {
632     _part->setMediaType(deviceType == WebCoreDeviceScreen ? "screen" : "print");
633     DocumentImpl *doc = _part->xmlDocImpl();
634     if (doc) {
635         static QPaintDevice screen;
636         static QPrinter printer;
637         doc->setPaintDevice(deviceType == WebCoreDeviceScreen ? &screen : &printer);
638         if (deviceType != WebCoreDeviceScreen) {
639             doc->setPrintStyleSheet(QString::fromNSString([self styleSheetForPrinting]));
640         }
641     }
642     return _part->reparseConfiguration();
643 }
644
645 static BOOL nowPrinting(WebCoreBridge *self)
646 {
647     DocumentImpl *doc = self->_part->xmlDocImpl();
648     return doc && doc->paintDevice() && doc->paintDevice()->devType() == QInternal::Printer;
649 }
650
651 // Set or unset the printing mode in the view.  We only toy with this if we're printing.
652 - (void)_setupRootForPrinting:(BOOL)onOrOff
653 {
654     if (nowPrinting(self)) {
655         RenderCanvas *root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
656         if (root) {
657             root->setPrintingMode(onOrOff);
658         }
659     }
660 }
661
662 - (void)forceLayoutAdjustingViewSize:(BOOL)flag
663 {
664     [self _setupRootForPrinting:YES];
665     _part->forceLayout();
666     if (flag) {
667         [self adjustViewSize];
668     }
669     [self _setupRootForPrinting:NO];
670 }
671
672 - (void)forceLayoutWithMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)flag
673 {
674     [self _setupRootForPrinting:YES];
675     _part->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth);
676     if (flag) {
677         [self adjustViewSize];
678     }
679     [self _setupRootForPrinting:NO];
680 }
681
682 - (void)sendResizeEvent
683 {
684     _part->sendResizeEvent();
685 }
686
687 - (void)sendScrollEvent
688 {
689     _part->sendScrollEvent();
690 }
691
692 - (void)drawRect:(NSRect)rect withPainter:(QPainter *)p
693 {
694     [self _setupRootForPrinting:YES];
695     _part->paint(p, QRect(rect));
696     [self _setupRootForPrinting:NO];
697 }
698
699 - (void)drawRect:(NSRect)rect
700 {
701     QPainter painter(nowPrinting(self));
702     bool displaysWithFocusAttributes = _part->displaysWithFocusAttributes();
703     painter.setUsesInactiveTextBackgroundColor(!displaysWithFocusAttributes);
704     painter.setDrawsFocusRing(displaysWithFocusAttributes);
705     [self drawRect:rect withPainter:&painter];
706 }
707
708 // Used by pagination code called from AppKit when a standalone web page is printed.
709 - (NSArray*)computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight
710 {
711     [self _setupRootForPrinting:YES];
712     NSMutableArray* pages = [NSMutableArray arrayWithCapacity:5];
713     if (printWidthScaleFactor == 0 || printHeight == 0)
714         return pages;
715         
716     if (!_part || !_part->xmlDocImpl() || !_part->view()) return pages;
717     RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
718     if (!root) return pages;
719     
720     KHTMLView* view = _part->view();
721     NSView* documentView = view->getDocumentView();
722     if (!documentView)
723         return pages;
724         
725     float currPageHeight = printHeight;
726     float docHeight = root->layer()->height();
727     float docWidth = root->layer()->width();
728     float printWidth = docWidth/printWidthScaleFactor;
729     
730     // We need to give the part the opportunity to adjust the page height at each step.
731     for (float i = 0; i < docHeight; i += currPageHeight) {
732         float proposedBottom = kMin(docHeight, i + printHeight);
733         _part->adjustPageHeight(&proposedBottom, i, proposedBottom, i);
734         currPageHeight = kMax(1.0f, proposedBottom - i);
735         for (float j = 0; j < docWidth; j += printWidth) {
736             NSValue* val = [NSValue valueWithRect: NSMakeRect(j, i, printWidth, currPageHeight)];
737             [pages addObject: val];
738         }
739     }
740     [self _setupRootForPrinting:NO];
741     
742     return pages;
743 }
744
745 // This is to support the case where a webview is embedded in the view that's being printed
746 - (void)adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit
747 {
748     [self _setupRootForPrinting:YES];
749     _part->adjustPageHeight(newBottom, oldTop, oldBottom, bottomLimit);
750     [self _setupRootForPrinting:NO];
751 }
752
753 - (NSObject *)copyDOMNode:(NodeImpl *)node copier:(id <WebCoreDOMTreeCopier>)copier
754 {
755     NSMutableArray *children = [[NSMutableArray alloc] init];
756     for (NodeImpl *child = node->firstChild(); child; child = child->nextSibling()) {
757         [children addObject:[self copyDOMNode:child copier:copier]];
758     }
759     NSObject *copiedNode = [copier nodeWithName:node->nodeName().string().getNSString()
760                                           value:node->nodeValue().string().getNSString()
761                                          source:createMarkup(node, ChildrenOnly).getNSString()
762                                        children:children];
763     [children release];
764     return copiedNode;
765 }
766
767 - (NSObject *)copyDOMTree:(id <WebCoreDOMTreeCopier>)copier
768 {
769     DocumentImpl *doc = _part->xmlDocImpl();
770     if (!doc) {
771         return nil;
772     }
773     return [self copyDOMNode:doc copier:copier];
774 }
775
776 - (NSObject *)copyRenderNode:(RenderObject *)node copier:(id <WebCoreRenderTreeCopier>)copier
777 {
778     NSMutableArray *children = [[NSMutableArray alloc] init];
779     for (RenderObject *child = node->firstChild(); child; child = child->nextSibling()) {
780         [children addObject:[self copyRenderNode:child copier:copier]];
781     }
782           
783     NSString *name = [[NSString alloc] initWithUTF8String:node->renderName()];
784     
785     RenderPart *nodeRenderPart = dynamic_cast<RenderPart *>(node);
786     QWidget *widget = nodeRenderPart ? nodeRenderPart->widget() : 0;
787     NSView *view = widget ? widget->getView() : nil;
788     
789     int nx, ny;
790     node->absolutePosition(nx,ny);
791     NSObject *copiedNode = [copier nodeWithName:name
792                                        position:NSMakePoint(nx,ny)
793                                            rect:NSMakeRect(node->xPos(), node->yPos(), node->width(), node->height())
794                                            view:view
795                                        children:children];
796     
797     [name release];
798     [children release];
799     
800     return copiedNode;
801 }
802
803 - (NSObject *)copyRenderTree:(id <WebCoreRenderTreeCopier>)copier
804 {
805     RenderObject *renderer = _part->renderer();
806     if (!renderer) {
807         return nil;
808     }
809     return [self copyRenderNode:renderer copier:copier];
810 }
811
812 - (void)removeFromFrame
813 {
814     _part->setView(0);
815 }
816
817 - (void)installInFrame:(NSView *)view
818 {
819     // If this isn't the main frame, it must have a render _part set, or it
820     // won't ever get installed in the view hierarchy.
821     ASSERT(self == [self mainFrame] || _renderPart != nil);
822
823     _part->view()->setView(view);
824     if (_renderPart) {
825         _renderPart->setWidget(_part->view());
826         // Now the render part owns the view, so we don't any more.
827     }
828
829     _part->view()->initScrollBars();
830 }
831
832 - (void)setActivationEventNumber:(int)num
833 {
834     _part->setActivationEventNumber(num);
835 }
836
837 - (void)mouseDown:(NSEvent *)event
838 {
839     _part->mouseDown(event);
840 }
841
842 - (void)mouseDragged:(NSEvent *)event
843 {
844     _part->mouseDragged(event);
845 }
846
847 - (void)mouseUp:(NSEvent *)event
848 {
849     _part->mouseUp(event);
850 }
851
852 - (void)mouseMoved:(NSEvent *)event
853 {
854     _part->mouseMoved(event);
855 }
856
857 - (BOOL)sendContextMenuEvent:(NSEvent *)event
858 {
859     return _part->sendContextMenuEvent(event);
860 }
861
862 - (DOMElement *)elementForView:(NSView *)view
863 {
864     // FIXME: implemented currently for only a subset of the KWQ widgets
865     if ([view conformsToProtocol:@protocol(KWQWidgetHolder)]) {
866         NSView <KWQWidgetHolder> *widgetHolder = view;
867         QWidget *widget = [widgetHolder widget];
868         if (widget != nil) {
869             NodeImpl *node = static_cast<const RenderWidget *>(widget->eventFilterObject())->element();
870             return [DOMElement _elementWithImpl:static_cast<ElementImpl *>(node)];
871         }
872     }
873     return nil;
874 }
875
876 static NSView *viewForElement(ElementImpl *elementImpl)
877 {
878     RenderObject *renderer = elementImpl->renderer();
879     if (renderer && renderer->isWidget()) {
880         QWidget *widget = static_cast<const RenderWidget *>(renderer)->widget();
881         if (widget) {
882             widget->populate();
883             return widget->getView();
884         }
885     }
886     return nil;
887 }
888
889 static HTMLInputElementImpl *inputElementFromDOMElement(DOMElement *element)
890 {
891     NodeImpl *node = [element _nodeImpl];
892     if (node && idFromNode(node) == ID_INPUT) {
893         return static_cast<HTMLInputElementImpl *>(node);
894     }
895     return nil;
896 }
897
898 static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
899 {
900     NodeImpl *node = [element _nodeImpl];
901     if (node && idFromNode(node) == ID_FORM) {
902         return static_cast<HTMLFormElementImpl *>(node);
903     }
904     return nil;
905 }
906
907 - (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form
908 {
909     HTMLFormElementImpl *formElement = formElementFromDOMElement(form);
910     if (formElement) {
911         QPtrVector<HTMLGenericFormElementImpl> &elements = formElement->formElements;
912         QString targetName = QString::fromNSString(name);
913         for (unsigned int i = 0; i < elements.count(); i++) {
914             HTMLGenericFormElementImpl *elt = elements.at(i);
915             // Skip option elements, other duds
916             if (elt->name() == targetName) {
917                 return [DOMElement _elementWithImpl:elt];
918             }
919         }
920     }
921     return nil;
922 }
923
924 - (BOOL)elementDoesAutoComplete:(DOMElement *)element
925 {
926     HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
927     return inputElement != nil
928         && inputElement->inputType() == HTMLInputElementImpl::TEXT
929         && inputElement->autoComplete();
930 }
931
932 - (BOOL)elementIsPassword:(DOMElement *)element
933 {
934     HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
935     return inputElement != nil
936         && inputElement->inputType() == HTMLInputElementImpl::PASSWORD;
937 }
938
939 - (DOMElement *)formForElement:(DOMElement *)element;
940 {
941     HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
942     if (inputElement) {
943         HTMLFormElementImpl *formElement = inputElement->form();
944         if (formElement) {
945             return [DOMElement _elementWithImpl:formElement];
946         }
947     }
948     return nil;
949 }
950
951 - (DOMElement *)currentForm
952 {
953     HTMLFormElementImpl *formElement = _part->currentForm();
954     return formElement ? [DOMElement _elementWithImpl:formElement] : nil;
955 }
956
957 - (NSArray *)controlsInForm:(DOMElement *)form
958 {
959     NSMutableArray *results = nil;
960     HTMLFormElementImpl *formElement = formElementFromDOMElement(form);
961     if (formElement) {
962         QPtrVector<HTMLGenericFormElementImpl> &elements = formElement->formElements;
963         for (unsigned int i = 0; i < elements.count(); i++) {
964             if (elements.at(i)->isEnumeratable()) {             // Skip option elements, other duds
965                 NSView *view = viewForElement(elements.at(i));
966                 if (view) {
967                     if (!results) {
968                         results = [NSMutableArray arrayWithObject:view];
969                     } else {
970                         [results addObject:view];
971                     }
972                 }
973             }
974         }
975     }
976     return results;
977 }
978
979 - (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element
980 {
981     return _part->searchForLabelsBeforeElement(labels, [element _elementImpl]);
982 }
983
984 - (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element
985 {
986     return _part->matchLabelsAgainstElement(labels, [element _elementImpl]);
987 }
988
989 - (NSDictionary *)elementAtPoint:(NSPoint)point
990 {
991     RenderObject *renderer = _part->renderer();
992     if (!renderer) {
993         return nil;
994     }
995     RenderObject::NodeInfo nodeInfo(true, true);
996     renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
997     
998     NSMutableDictionary *element = [NSMutableDictionary dictionary];
999     [element setObject:[NSNumber numberWithBool:_part->isPointInsideSelection((int)point.x, (int)point.y)]
1000                 forKey:WebCoreElementIsSelectedKey];
1001     
1002     // Find the title in the nearest enclosing DOM node.
1003     // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
1004     for (NodeImpl *titleNode = nodeInfo.innerNode(); titleNode; titleNode = titleNode->parentNode()) {
1005         if (titleNode->isElementNode()) {
1006             const AtomicString& title = static_cast<ElementImpl *>(titleNode)->getAttribute(ATTR_TITLE);
1007             if (!title.isNull()) {
1008                 // We found a node with a title.
1009                 QString titleText = title.string();
1010                 titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1011                 [element setObject:titleText.getNSString() forKey:WebCoreElementTitleKey];
1012                 break;
1013             }
1014         }
1015     }
1016
1017     NodeImpl *URLNode = nodeInfo.URLElement();
1018     if (URLNode) {
1019         ElementImpl *e = static_cast<ElementImpl *>(URLNode);
1020         
1021         const AtomicString& title = e->getAttribute(ATTR_TITLE);
1022         if (!title.isEmpty()) {
1023             QString titleText = title.string();
1024             titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1025             [element setObject:titleText.getNSString() forKey:WebCoreElementLinkTitleKey];
1026         }
1027         
1028         const AtomicString& link = e->getAttribute(ATTR_HREF);
1029         if (!link.isNull()) {
1030             if (e->firstChild()) {
1031                 Range r(_part->document());
1032                 r.setStartBefore(e->firstChild());
1033                 r.setEndAfter(e->lastChild());
1034                 QString t = _part->text(r);
1035                 if (!t.isEmpty()) {
1036                     [element setObject:t.getNSString() forKey:WebCoreElementLinkLabelKey];
1037                 }
1038             }
1039             QString URLString = parseURL(link).string();
1040             [element setObject:_part->xmlDocImpl()->completeURL(URLString).getNSString() forKey:WebCoreElementLinkURLKey];
1041         }
1042         
1043         DOMString target = e->getAttribute(ATTR_TARGET);
1044         if (target.isEmpty() && _part->xmlDocImpl()) {
1045             target = _part->xmlDocImpl()->baseTarget();
1046         }
1047         if (!target.isEmpty()) {
1048             [element setObject:target.string().getNSString() forKey:WebCoreElementLinkTargetFrameKey];
1049         }
1050     }
1051
1052     NodeImpl *node = nodeInfo.innerNonSharedNode();
1053     if (node) {
1054         [element setObject:[DOMNode _nodeWithImpl:node] forKey:WebCoreElementDOMNodeKey];
1055     
1056         if (node->renderer() && node->renderer()->isImage()) {
1057             RenderImage *r = static_cast<RenderImage *>(node->renderer());
1058             NSImage *image = r->pixmap().image();
1059             // Only return image information if there is an image.
1060             if (image && !r->isDisplayingError()) {
1061                 [element setObject:r->pixmap().image() forKey:WebCoreElementImageKey];
1062             }
1063                 
1064             int x, y;
1065             if (r->absolutePosition(x, y)) {
1066                 NSValue *rect = [NSValue valueWithRect:NSMakeRect(x, y, r->contentWidth(), r->contentHeight())];
1067                 [element setObject:rect forKey:WebCoreElementImageRectKey];
1068             }
1069                 
1070             ElementImpl *i = static_cast<ElementImpl*>(node);
1071     
1072             // FIXME: Code copied from RenderImage::updateFromElement; should share.
1073             DOMString attr;
1074             if (idFromNode(i) == ID_OBJECT) {
1075                 attr = i->getAttribute(ATTR_DATA);
1076             } else {
1077                 attr = i->getAttribute(ATTR_SRC);
1078             }
1079             if (!attr.isEmpty()) {
1080                 QString URLString = parseURL(attr).string();
1081                 [element setObject:_part->xmlDocImpl()->completeURL(URLString).getNSString() forKey:WebCoreElementImageURLKey];
1082             }
1083             
1084             // FIXME: Code copied from RenderImage::updateFromElement; should share.
1085             DOMString alt;
1086             if (idFromNode(i) == ID_INPUT)
1087                 alt = static_cast<HTMLInputElementImpl *>(i)->altText();
1088             else if (idFromNode(i) == ID_IMG)
1089                 alt = static_cast<HTMLImageElementImpl *>(i)->altText();
1090             if (!alt.isNull()) {
1091                 QString altText = alt.string();
1092                 altText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1093                 [element setObject:altText.getNSString() forKey:WebCoreElementImageAltStringKey];
1094             }
1095         }
1096     }
1097     
1098     return element;
1099 }
1100
1101 - (NSURL *)URLWithAttributeString:(NSString *)string
1102 {
1103     DocumentImpl *doc = _part->xmlDocImpl();
1104     if (!doc) {
1105         return nil;
1106     }
1107     QString rel = parseURL(QString::fromNSString(string)).string();
1108     return KURL(doc->baseURL(), rel, doc->decoder() ? doc->decoder()->codec() : 0).getNSURL();
1109 }
1110
1111 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
1112 {
1113     return _part->findString(string, forward, caseFlag, wrapFlag);
1114 }
1115
1116 - (void)jumpToSelection
1117 {
1118     _part->jumpToSelection();
1119 }
1120
1121 - (NSString *)advanceToNextMisspelling
1122 {
1123     return _part->advanceToNextMisspelling().getNSString();
1124 }
1125
1126 - (NSString *)advanceToNextMisspellingStartingJustBeforeSelection
1127 {
1128     return _part->advanceToNextMisspelling(true).getNSString();
1129 }
1130
1131 - (void)setTextSizeMultiplier:(float)multiplier
1132 {
1133     int newZoomFactor = (int)rint(multiplier * 100);
1134     if (_part->zoomFactor() == newZoomFactor) {
1135         return;
1136     }
1137     _part->setZoomFactor(newZoomFactor);
1138 }
1139
1140 - (CFStringEncoding)textEncoding
1141 {
1142     return KWQCFStringEncodingFromIANACharsetName(_part->encoding().latin1());
1143 }
1144
1145 - (NSView *)nextKeyView
1146 {
1147     DocumentImpl *doc = _part->xmlDocImpl();
1148     if (!doc) {
1149         return nil;
1150     }
1151     return _part->nextKeyView(doc->focusNode(), KWQSelectingNext);
1152 }
1153
1154 - (NSView *)previousKeyView
1155 {
1156     DocumentImpl *doc = _part->xmlDocImpl();
1157     if (!doc) {
1158         return nil;
1159     }
1160     return _part->nextKeyView(doc->focusNode(), KWQSelectingPrevious);
1161 }
1162
1163 - (NSView *)nextKeyViewInsideWebFrameViews
1164 {
1165     DocumentImpl *doc = _part->xmlDocImpl();
1166     if (!doc) {
1167         return nil;
1168     }
1169     
1170     return _part->nextKeyViewInFrameHierarchy(doc->focusNode(), KWQSelectingNext);
1171 }
1172
1173 - (NSView *)previousKeyViewInsideWebFrameViews
1174 {
1175     DocumentImpl *doc = _part->xmlDocImpl();
1176     if (!doc) {
1177         return nil;
1178     }
1179
1180     return _part->nextKeyViewInFrameHierarchy(doc->focusNode(), KWQSelectingPrevious);
1181 }
1182
1183 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string
1184 {
1185     _part->createEmptyDocument();
1186     return _part->executeScript(QString::fromNSString(string), true).asString().getNSString();
1187 }
1188
1189 - (WebScriptObject *)windowScriptObject
1190 {
1191     return _part->windowScriptObject();
1192 }
1193
1194 - (NPObject *)windowScriptNPObject
1195 {
1196     return _part->windowScriptNPObject();
1197 }
1198
1199 - (DOMDocument *)DOMDocument
1200 {
1201     return [DOMDocument _documentWithImpl:_part->xmlDocImpl()];
1202 }
1203
1204 - (DOMHTMLElement *)frameElement
1205 {
1206     return (DOMHTMLElement *)[[self DOMDocument] _ownerElement];
1207 }
1208
1209 - (NSAttributedString *)selectedAttributedString
1210 {
1211     return _part->attributedString(_part->selectionStart(), _part->selectionStartOffset(), _part->selectionEnd(), _part->selectionEndOffset());
1212 }
1213
1214 - (NSAttributedString *)attributedStringFrom:(DOMNode *)start startOffset:(int)startOffset to:(DOMNode *)end endOffset:(int)endOffset
1215 {
1216     DOMNode *startNode = start;
1217     DOMNode *endNode = end;
1218     return _part->attributedString([startNode _nodeImpl], startOffset, [endNode _nodeImpl], endOffset);
1219 }
1220
1221 - (NSRect)selectionRect
1222 {
1223     return _part->selectionRect(); 
1224 }
1225
1226 - (NSRect)visibleSelectionRect
1227 {
1228     return _part->visibleSelectionRect(); 
1229 }
1230
1231 - (void)centerSelectionInVisibleArea
1232 {
1233     _part->centerSelectionInVisibleArea(); 
1234 }
1235
1236 - (NSRect)caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
1237 {
1238     return [node _nodeImpl]->renderer()->caretRect(offset, static_cast<EAffinity>(affinity));
1239 }
1240 - (NSRect)firstRectForDOMRange:(DOMRange *)range
1241 {
1242     int extraWidthToEndOfLine = 0;
1243     QRect startCaretRect = [[range startContainer] _nodeImpl]->renderer()->caretRect([range startOffset], UPSTREAM, &extraWidthToEndOfLine);
1244     QRect endCaretRect = [[range startContainer] _nodeImpl]->renderer()->caretRect([range endOffset], UPSTREAM);
1245
1246     if (startCaretRect.y() == endCaretRect.y()) {
1247         // start and end are on the same line
1248         return QRect(MIN(startCaretRect.x(), endCaretRect.x()), 
1249                      startCaretRect.y(), 
1250                      abs(endCaretRect.x() - startCaretRect.x()),
1251                      MAX(startCaretRect.height(), endCaretRect.height()));
1252     }
1253
1254     // start and end aren't on the same line, so go from start to the end of its line
1255     return QRect(startCaretRect.x(), 
1256                  startCaretRect.y(),
1257                  startCaretRect.width() + extraWidthToEndOfLine,
1258                  startCaretRect.height());
1259 }
1260
1261 - (NSImage *)selectionImage
1262 {
1263     return _part->selectionImage();
1264 }
1265
1266 - (void)setName:(NSString *)name
1267 {
1268     _part->KHTMLPart::setName(QString::fromNSString(name));
1269 }
1270
1271 - (NSString *)name
1272 {
1273     return _part->name().getNSString();
1274 }
1275
1276 - (NSURL *)URL
1277 {
1278     return _part->url().getNSURL();
1279 }
1280
1281 - (NSString *)referrer
1282 {
1283     return _part->referrer().getNSString();
1284 }
1285
1286 - (NSString *)domain
1287 {
1288     DocumentImpl *doc = _part->xmlDocImpl();
1289     if (doc && doc->isHTMLDocument()) {
1290         return doc->domain().string().getNSString();
1291     }
1292     return nil;
1293 }
1294
1295 - (WebCoreBridge *)opener
1296 {
1297     KHTMLPart *openerPart = _part->opener();
1298
1299     if (openerPart)
1300         return KWQ(openerPart)->bridge();
1301
1302     return nil;
1303 }
1304
1305 + (NSString *)stringWithData:(NSData *)data textEncoding:(CFStringEncoding)textEncoding
1306 {
1307     if (textEncoding == kCFStringEncodingInvalidId || textEncoding == kCFStringEncodingISOLatin1) {
1308         textEncoding = kCFStringEncodingWindowsLatin1;
1309     }
1310     return QTextCodec(textEncoding).toUnicode((const char*)[data bytes], [data length]).getNSString();
1311 }
1312
1313 + (NSString *)stringWithData:(NSData *)data textEncodingName:(NSString *)textEncodingName
1314 {
1315     CFStringEncoding textEncoding = KWQCFStringEncodingFromIANACharsetName([textEncodingName lossyCString]);
1316     return [WebCoreBridge stringWithData:data textEncoding:textEncoding];
1317 }
1318
1319 - (BOOL)needsLayout
1320 {
1321     RenderObject *renderer = _part->renderer();
1322     return renderer ? renderer->needsLayout() : false;
1323 }
1324
1325 - (void)setNeedsLayout
1326 {
1327     RenderObject *renderer = _part->renderer();
1328     if (renderer)
1329         renderer->setNeedsLayout(true);
1330 }
1331
1332 - (BOOL)interceptKeyEvent:(NSEvent *)event toView:(NSView *)view
1333 {
1334     return _part->keyEvent(event);
1335 }
1336
1337 - (NSString *)renderTreeAsExternalRepresentation
1338 {
1339     return externalRepresentation(_part->renderer()).getNSString();
1340 }
1341
1342 - (void)setSelectionFromNone
1343 {
1344     _part->setSelectionFromNone();
1345 }
1346
1347 - (void)setDisplaysWithFocusAttributes:(BOOL)flag
1348 {
1349     _part->setDisplaysWithFocusAttributes(flag);
1350 }
1351
1352 - (void)setShouldCreateRenderers:(BOOL)f
1353 {
1354     _shouldCreateRenderers = f;
1355 }
1356
1357 - (BOOL)shouldCreateRenderers
1358 {
1359     return _shouldCreateRenderers;
1360 }
1361
1362 - (int)numPendingOrLoadingRequests
1363 {
1364     DocumentImpl *doc = _part->xmlDocImpl();
1365     
1366     if (doc)
1367         return KWQNumberOfPendingOrLoadingRequests (doc->docLoader());
1368     return 0;
1369 }
1370
1371 - (BOOL)doneProcessingData
1372 {
1373     DocumentImpl *doc = _part->xmlDocImpl();
1374     if (doc) {
1375         Tokenizer* tok = doc->tokenizer();
1376         if (tok)
1377             return !tok->processingData();
1378     }
1379     return YES;
1380 }
1381
1382 - (NSColor *)bodyBackgroundColor
1383 {
1384     return _part->bodyBackgroundColor();
1385 }
1386
1387 - (NSColor *)selectionColor
1388 {
1389     RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
1390     if (root) {
1391         RenderStyle *pseudoStyle = root->getPseudoStyle(RenderStyle::SELECTION);
1392         if (pseudoStyle && pseudoStyle->backgroundColor().isValid()) {
1393             return pseudoStyle->backgroundColor().getNSColor();
1394         }
1395     }
1396     return _part->displaysWithFocusAttributes() ? [NSColor selectedTextBackgroundColor] : [NSColor secondarySelectedControlColor];
1397 }
1398
1399 - (void)adjustViewSize
1400 {
1401     KHTMLView *view = _part->view();
1402     if (view)
1403         view->adjustViewSize();
1404 }
1405
1406 -(id)accessibilityTree
1407 {
1408     KWQAccObjectCache::enableAccessibility();
1409     if (!_part || !_part->xmlDocImpl()) return nil;
1410     RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
1411     if (!root) return nil;
1412     return _part->xmlDocImpl()->getAccObjectCache()->accObject(root);
1413 }
1414
1415 - (void)setDrawsBackground:(BOOL)drawsBackground
1416 {
1417     if (_part && _part->view())
1418         _part->view()->setTransparent(!drawsBackground);
1419 }
1420
1421 - (void)undoEditing:(id)arg
1422 {
1423     ASSERT([arg isKindOfClass:[KWQEditCommand class]]);
1424     [arg command]->unapply();
1425 }
1426
1427 - (void)redoEditing:(id)arg
1428 {
1429     ASSERT([arg isKindOfClass:[KWQEditCommand class]]);
1430     [arg command]->reapply();
1431 }
1432
1433 - (DOMRange *)rangeByExpandingSelectionWithGranularity:(WebSelectionGranularity)granularity
1434 {
1435     if (!partHasSelection(self))
1436         return nil;
1437         
1438     // NOTE: The enums *must* match the very similar ones declared in ktml_selection.h
1439     Selection selection(_part->selection());
1440     selection.expandUsingGranularity(static_cast<ETextGranularity>(granularity));
1441     return [DOMRange _rangeWithImpl:selection.toRange().handle()];
1442 }
1443
1444 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
1445 {
1446     if (!partHasSelection(self))
1447         return nil;
1448         
1449     // NOTE: The enums *must* match the very similar ones declared in ktml_selection.h
1450     Selection selection(_part->selection());
1451     selection.modify(static_cast<Selection::EAlter>(alteration), 
1452                      static_cast<Selection::EDirection>(direction), 
1453                      static_cast<ETextGranularity>(granularity));
1454     return [DOMRange _rangeWithImpl:selection.toRange().handle()];
1455 }
1456
1457 - (void)alterCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
1458 {
1459     if (!partHasSelection(self))
1460         return;
1461         
1462     // NOTE: The enums *must* match the very similar ones declared in dom_selection.h
1463     Selection selection(_part->selection());
1464     selection.modify(static_cast<Selection::EAlter>(alteration), 
1465                      static_cast<Selection::EDirection>(direction), 
1466                      static_cast<ETextGranularity>(granularity));
1467
1468     // save vertical navigation x position if necessary; many types of motion blow it away
1469     int xPos = KHTMLPart::NoXPosForVerticalArrowNavigation;
1470     switch (granularity) {
1471         case WebSelectByLine:
1472         case WebSelectByParagraph:
1473             xPos = _part->xPosForVerticalArrowNavigation();
1474             break;
1475         case WebSelectByCharacter:
1476         case WebSelectByWord:
1477         case WebSelectToLineBoundary:
1478         case WebSelectToParagraphBoundary:
1479         case WebSelectToDocumentBoundary:
1480             break;
1481     }
1482
1483     
1484     // setting the selection always clears saved vertical navigation x position
1485     _part->setSelection(selection);
1486     
1487     // restore vertical navigation x position if necessary
1488     if (xPos != KHTMLPart::NoXPosForVerticalArrowNavigation)
1489         _part->setXPosForVerticalArrowNavigation(xPos);
1490
1491     [self ensureSelectionVisible];
1492 }
1493
1494 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration verticalDistance:(float)verticalDistance
1495 {
1496     if (!partHasSelection(self))
1497         return nil;
1498         
1499     Selection selection(_part->selection());
1500     selection.modify(static_cast<Selection::EAlter>(alteration), static_cast<int>(verticalDistance));
1501     return [DOMRange _rangeWithImpl:selection.toRange().handle()];
1502 }
1503
1504 - (void)alterCurrentSelection:(WebSelectionAlteration)alteration verticalDistance:(float)verticalDistance
1505 {
1506     if (!partHasSelection(self))
1507         return;
1508         
1509     Selection selection(_part->selection());
1510     selection.modify(static_cast<Selection::EAlter>(alteration), static_cast<int>(verticalDistance));
1511
1512     // setting the selection always clears saved vertical navigation x position, so preserve it
1513     int xPos = _part->xPosForVerticalArrowNavigation();
1514     _part->setSelection(selection);
1515     _part->setXPosForVerticalArrowNavigation(xPos);
1516
1517     [self ensureSelectionVisible];
1518 }
1519
1520 - (WebSelectionGranularity)selectionGranularity
1521 {
1522     // NOTE: The enums *must* match the very similar ones declared in dom_selection.h
1523     return static_cast<WebSelectionGranularity>(_part->selectionGranularity());
1524 }
1525
1526 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
1527 {
1528     NodeImpl *startContainer = [[range startContainer] _nodeImpl];
1529     NodeImpl *endContainer = [[range endContainer] _nodeImpl];
1530     ASSERT(startContainer);
1531     ASSERT(endContainer);
1532     ASSERT(startContainer->getDocument());
1533     ASSERT(startContainer->getDocument() == endContainer->getDocument());
1534     
1535     _part->xmlDocImpl()->updateLayout();
1536
1537     // Work around bug where isRenderedContent returns false for <br> elements at the ends of lines.
1538     // If that bug wasn't an issue, we could just make the position from the range directly.
1539     Position start(startContainer, [range startOffset]);
1540     Position end(endContainer, [range endOffset]);
1541     start = VisiblePosition(start, UPSTREAM).deepEquivalent();
1542
1543     Selection selection(start, end);
1544     selection.setAffinity(static_cast<EAffinity>(selectionAffinity));
1545     _part->setSelection(selection);
1546 }
1547
1548 - (DOMRange *)selectedDOMRange
1549 {
1550     return [DOMRange _rangeWithImpl:_part->selection().toRange().handle()];
1551 }
1552
1553 - (NSSelectionAffinity)selectionAffinity
1554 {
1555     return static_cast<NSSelectionAffinity>(_part->selection().affinity());
1556 }
1557
1558 - (void)setMarkDOMRange:(DOMRange *)range
1559 {
1560     _part->setMark(Selection([range _rangeImpl]));
1561 }
1562
1563 - (DOMRange *)markDOMRange
1564 {
1565     return [DOMRange _rangeWithImpl:_part->mark().toRange().handle()];
1566 }
1567
1568 - (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges
1569 {
1570     _part->setMarkedTextRange([range _rangeImpl], attributes, ranges);
1571 }
1572
1573 - (DOMRange *)markedTextDOMRange
1574 {
1575     return [DOMRange _rangeWithImpl:_part->markedTextRange().handle()];
1576 }
1577
1578 - (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString 
1579 {
1580     if (!_part || !_part->xmlDocImpl())
1581         return 0;
1582
1583     DocumentFragmentImpl *fragment = createFragmentFromMarkup(_part->xmlDocImpl(), QString::fromNSString(markupString), QString::fromNSString(baseURLString));
1584     return [DOMDocumentFragment _documentFragmentWithImpl:fragment];
1585 }
1586
1587 - (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text
1588 {
1589     if (!partHasSelection(self) || !text)
1590         return 0;
1591     
1592     return [DOMDocumentFragment _documentFragmentWithImpl:createFragmentFromText(_part->xmlDocImpl(), QString::fromNSString(text))];
1593 }
1594
1595 - (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1596 {
1597     if (!partHasSelection(self) || !fragment)
1598         return;
1599     
1600     EditCommandPtr(new ReplaceSelectionCommand(_part->xmlDocImpl(), [fragment _fragmentImpl], selectReplacement, smartReplace)).apply();
1601     [self ensureSelectionVisible];
1602 }
1603
1604 - (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1605 {
1606     DOMDocumentFragment *fragment = [[self DOMDocument] createDocumentFragment];
1607     [fragment appendChild:node];
1608     [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace];
1609 }
1610
1611 - (void)replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1612 {
1613     DOMDocumentFragment *fragment = [self documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
1614     [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace];
1615 }
1616
1617 - (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1618 {
1619     [self replaceSelectionWithFragment:[self documentFragmentWithText:text] selectReplacement:selectReplacement smartReplace:smartReplace];
1620 }
1621
1622 - (void)insertLineBreak
1623 {
1624     if (!partHasSelection(self))
1625         return;
1626     
1627     TypingCommand::insertLineBreak(_part->xmlDocImpl());
1628     [self ensureSelectionVisible];
1629 }
1630
1631 - (void)insertParagraphSeparator
1632 {
1633     if (!partHasSelection(self))
1634         return;
1635     
1636     TypingCommand::insertParagraphSeparator(_part->xmlDocImpl());
1637     [self ensureSelectionVisible];
1638 }
1639
1640 - (void)insertParagraphSeparatorInQuotedContent
1641 {
1642     if (!partHasSelection(self))
1643         return;
1644     
1645     TypingCommand::insertParagraphSeparatorInQuotedContent(_part->xmlDocImpl());
1646     [self ensureSelectionVisible];
1647 }
1648
1649 - (void)insertText:(NSString *)text selectInsertedText:(BOOL)selectInsertedText
1650 {
1651     if (!partHasSelection(self))
1652         return;
1653     
1654     TypingCommand::insertText(_part->xmlDocImpl(), text, selectInsertedText);
1655     [self ensureSelectionVisible];
1656 }
1657
1658 - (void)setSelectionToDragCaret
1659 {
1660     _part->setSelection(_part->dragCaret());
1661 }
1662
1663 - (void)moveSelectionToDragCaret:(DOMDocumentFragment *)selectionFragment smartMove:(BOOL)smartMove
1664 {
1665     Position base = _part->dragCaret().base();
1666     EditCommandPtr(new MoveSelectionCommand(_part->xmlDocImpl(), [selectionFragment _fragmentImpl], base, smartMove)).apply();
1667 }
1668
1669 - (Position)_positionForPoint:(NSPoint)point
1670 {
1671     RenderObject *renderer = _part->renderer();
1672     if (!renderer) {
1673         return Position();
1674     }
1675     
1676     RenderObject::NodeInfo nodeInfo(true, true);
1677     renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
1678     NodeImpl *node = nodeInfo.innerNode();
1679     if (!node->renderer())
1680         return Position();
1681     return node->renderer()->positionForCoordinates((int)point.x, (int)point.y);
1682 }
1683
1684 - (void)moveDragCaretToPoint:(NSPoint)point
1685 {    
1686     Selection dragCaret([self _positionForPoint:point]);
1687     _part->setDragCaret(dragCaret);
1688 }
1689
1690 - (void)removeDragCaret
1691 {
1692     _part->setDragCaret(Selection());
1693 }
1694
1695 - (DOMRange *)dragCaretDOMRange
1696 {
1697     return [DOMRange _rangeWithImpl:_part->dragCaret().toRange().handle()];
1698 }
1699
1700 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
1701 {
1702     Position position = [self _positionForPoint:point];
1703     return position.isNull() ? nil : [DOMRange _rangeWithImpl:Selection(position).toRange().handle()];
1704 }
1705
1706 - (void)deleteSelectionWithSmartDelete:(BOOL)smartDelete
1707 {
1708     if (!partHasSelection(self))
1709         return;
1710     
1711     EditCommandPtr(new DeleteSelectionCommand(_part->xmlDocImpl(), smartDelete)).apply();
1712 }
1713
1714 - (void)deleteKeyPressed
1715 {
1716     if (!_part || !_part->xmlDocImpl())
1717         return;
1718     
1719     TypingCommand::deleteKeyPressed(_part->xmlDocImpl());
1720     [self ensureSelectionVisible];
1721 }
1722
1723 - (DOMCSSStyleDeclaration *)typingStyle
1724 {
1725     if (!_part || !_part->typingStyle())
1726         return nil;
1727     return [DOMCSSStyleDeclaration _styleDeclarationWithImpl:_part->typingStyle()];
1728 }
1729
1730 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
1731 {
1732     if (!_part)
1733         return;
1734     _part->computeAndSetTypingStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
1735 }
1736
1737 - (void)applyStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
1738 {
1739     if (!_part)
1740         return;
1741     _part->applyStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
1742 }
1743
1744 - (BOOL)selectionStartHasStyle:(DOMCSSStyleDeclaration *)style
1745 {
1746     if (!_part)
1747         return NO;
1748     return _part->selectionStartHasStyle([style _styleDeclarationImpl]);
1749 }
1750
1751 - (void)applyEditingStyleToBodyElement
1752 {
1753     if (!_part)
1754         return;
1755     _part->applyEditingStyleToBodyElement();
1756 }
1757
1758 - (void)removeEditingStyleFromBodyElement
1759 {
1760     if (!_part)
1761         return;
1762     _part->removeEditingStyleFromBodyElement();
1763 }
1764
1765 - (void)applyEditingStyleToElement:(DOMElement *)element
1766 {
1767     if (!_part)
1768         return;
1769     _part->applyEditingStyleToElement([element _elementImpl]);
1770 }
1771
1772 - (void)removeEditingStyleFromElement:(DOMElement *)element
1773 {
1774     if (!_part)
1775         return;
1776     _part->removeEditingStyleFromElement([element _elementImpl]);
1777 }
1778
1779 - (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts
1780 {
1781     bool multipleFonts = false;
1782     NSFont *font = nil;
1783     if (_part)
1784         font = _part->fontForSelection(hasMultipleFonts ? &multipleFonts : 0);
1785     if (hasMultipleFonts)
1786         *hasMultipleFonts = multipleFonts;
1787     return font;
1788 }
1789
1790 - (NSDictionary *)fontAttributesForSelectionStart
1791 {
1792     return _part ? _part->fontAttributesForSelectionStart() : nil;
1793 }
1794
1795 - (void)ensureSelectionVisible
1796 {
1797     if (!partHasSelection(self))
1798         return;
1799     
1800     KHTMLView *v = _part->view();
1801     if (!v)
1802         return;
1803
1804     Position extent = _part->selection().extent();
1805     if (extent.isNull())
1806         return;
1807     
1808     RenderObject *renderer = extent.node()->renderer();
1809     if (!renderer)
1810         return;
1811     
1812     NSView *documentView = v->getDocumentView();
1813     if (!documentView)
1814         return;
1815     
1816     QRect extentRect = renderer->caretRect(extent.offset(), _part->selection().affinity());
1817     if (!NSContainsRect([documentView visibleRect], NSRect(extentRect))) {
1818         v->ensureRectVisibleCentered(extentRect, true);
1819     }
1820 }
1821
1822 // [info draggingLocation] is in window coords
1823
1824 - (BOOL)eventMayStartDrag:(NSEvent *)event
1825 {
1826     return _part ? _part->eventMayStartDrag(event) : NO;
1827 }
1828
1829 - (NSDragOperation)dragOperationForDraggingInfo:(id <NSDraggingInfo>)info
1830 {
1831     NSDragOperation op = NSDragOperationNone;
1832     if (_part) {
1833         KHTMLView *v = _part->view();
1834         if (v) {
1835             // Sending an event can result in the destruction of the view and part.
1836             v->ref();
1837             
1838             KWQClipboard::AccessPolicy policy = _part->baseURL().isLocalFile() ? KWQClipboard::Readable : KWQClipboard::TypesReadable;
1839             KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], policy);
1840             clipboard->ref();
1841             NSDragOperation srcOp = [info draggingSourceOperationMask];
1842             clipboard->setSourceOperation(srcOp);
1843
1844             if (v->updateDragAndDrop(QPoint([info draggingLocation]), clipboard)) {
1845                 // *op unchanged if no source op was set
1846                 if (!clipboard->destinationOperation(&op)) {
1847                     // The element accepted but they didn't pick an operation, so we pick one for them
1848                     // (as does WinIE).
1849                     if (srcOp & NSDragOperationCopy) {
1850                         op = NSDragOperationCopy;
1851                     } else if (srcOp & NSDragOperationMove || srcOp & NSDragOperationGeneric) {
1852                         op = NSDragOperationMove;
1853                     } else if (srcOp & NSDragOperationLink) {
1854                         op = NSDragOperationLink;
1855                     } else {
1856                         op = NSDragOperationGeneric;
1857                     }
1858                 } else if (!(op & srcOp)) {
1859                     // make sure WC picked an op that was offered.  Cocoa doesn't seem to enforce this,
1860                     // but IE does.
1861                     op = NSDragOperationNone;
1862                 }
1863             }
1864             clipboard->setAccessPolicy(KWQClipboard::Numb);    // invalidate clipboard here for security
1865
1866             clipboard->deref();
1867             v->deref();
1868             return op;
1869         }
1870     }
1871     return op;
1872 }
1873
1874 - (void)dragExitedWithDraggingInfo:(id <NSDraggingInfo>)info
1875 {
1876     if (_part) {
1877         KHTMLView *v = _part->view();
1878         if (v) {
1879             // Sending an event can result in the destruction of the view and part.
1880             v->ref();
1881
1882             KWQClipboard::AccessPolicy policy = _part->baseURL().isLocalFile() ? KWQClipboard::Readable : KWQClipboard::TypesReadable;
1883             KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], policy);
1884             clipboard->ref();
1885             clipboard->setSourceOperation([info draggingSourceOperationMask]);
1886             
1887             v->cancelDragAndDrop(QPoint([info draggingLocation]), clipboard);
1888             clipboard->setAccessPolicy(KWQClipboard::Numb);    // invalidate clipboard here for security
1889
1890             clipboard->deref();
1891             v->deref();
1892         }
1893     }
1894 }
1895
1896 - (BOOL)concludeDragForDraggingInfo:(id <NSDraggingInfo>)info
1897 {
1898     if (_part) {
1899         KHTMLView *v = _part->view();
1900         if (v) {
1901             // Sending an event can result in the destruction of the view and part.
1902             v->ref();
1903
1904             KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], KWQClipboard::Readable);
1905             clipboard->ref();
1906             clipboard->setSourceOperation([info draggingSourceOperationMask]);
1907
1908             BOOL result = v->performDragAndDrop(QPoint([info draggingLocation]), clipboard);
1909             clipboard->setAccessPolicy(KWQClipboard::Numb);    // invalidate clipboard here for security
1910
1911             clipboard->deref();
1912             v->deref();
1913
1914             return result;
1915         }
1916     }
1917     return NO;
1918 }
1919
1920 - (void)dragSourceMovedTo:(NSPoint)windowLoc
1921 {
1922     if (_part) {
1923         _part->dragSourceMovedTo(QPoint(windowLoc));
1924     }
1925 }
1926
1927 - (void)dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
1928 {
1929     if (_part) {
1930         _part->dragSourceEndedAt(QPoint(windowLoc), operation);
1931     }
1932 }
1933
1934 - (BOOL)mayDHTMLCut
1935 {
1936     return _part->mayCut();
1937 }
1938
1939 - (BOOL)mayDHTMLCopy
1940 {
1941     return _part->mayCopy();
1942 }
1943
1944 - (BOOL)mayDHTMLPaste
1945 {
1946     return _part->mayPaste();
1947 }
1948
1949 - (BOOL)tryDHTMLCut
1950 {
1951     return _part->tryCut();
1952 }
1953
1954 - (BOOL)tryDHTMLCopy
1955 {
1956     return _part->tryCopy();
1957 }
1958
1959 - (BOOL)tryDHTMLPaste
1960 {
1961     return _part->tryPaste();
1962 }
1963
1964 - (DOMRange *)rangeOfCharactersAroundCaret
1965 {
1966     if (!_part)
1967         return nil;
1968         
1969     Selection selection(_part->selection());
1970     if (!selection.isCaret())
1971         return nil;
1972
1973     VisiblePosition caret(selection.start());
1974     VisiblePosition next = caret.next();
1975     VisiblePosition previous = caret.previous();
1976     if (caret == next || caret == previous)
1977         return nil;
1978
1979     return [DOMRange _rangeWithImpl:makeRange(previous, next).handle()];
1980 }
1981
1982 - (NSMutableDictionary *)dashboardRegions
1983 {
1984     return _part->dashboardRegionsDictionary();
1985 }
1986
1987 @end
1988
1989 @implementation WebCoreBridge (WebCoreBridgeInternal)
1990
1991 - (RootObject *)executionContextForView:(NSView *)aView
1992 {
1993     KWQKHTMLPart *part = [self part];
1994     RootObject *root = new RootObject(aView);    // The root gets deleted by JavaScriptCore.
1995     root->setRootObjectImp(static_cast<ObjectImp *>(Window::retrieveWindow(part)));
1996     root->setInterpreter(KJSProxy::proxy(part)->interpreter());
1997     part->addPluginRootObject(root);
1998     return root;
1999 }
2000
2001 @end