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