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