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