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