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