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