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_range.h"
31 #import "dom2_rangeimpl.h"
32 #import "dom2_viewsimpl.h"
33 #import "dom_docimpl.h"
34 #import "dom_node.h"
35 #import "dom_nodeimpl.h"
36 #import "dom_position.h"
37 #import "html_documentimpl.h"
38 #import "html_formimpl.h"
39 #import "html_imageimpl.h"
40 #import "htmlediting.h"
41 #import "khtml_part.h"
42 #import "khtmlview.h"
43 #import "kjs_proxy.h"
44 #import "kjs_window.h"
45 #import "loader.h"
46 #import "markup.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 #import "visible_text.h"
56 #import "visible_units.h"
57 #import "xml_tokenizer.h"
58
59 #import <JavaScriptCore/npruntime.h>
60 #import <JavaScriptCore/jni_jsobject.h>
61 #import <JavaScriptCore/object.h>
62 #import <JavaScriptCore/runtime_root.h>
63 #import <JavaScriptCore/property_map.h>
64
65 #import "KWQAssertions.h"
66 #import "KWQCharsets.h"
67 #import "KWQClipboard.h"
68 #import "KWQEditCommand.h"
69 #import "KWQFont.h"
70 #import "KWQFoundationExtras.h"
71 #import "KWQFrame.h"
72 #import "KWQKHTMLPart.h"
73 #import "KWQLoader.h"
74 #import "KWQPageState.h"
75 #import "KWQRenderTreeDebug.h"
76 #import "KWQView.h"
77 #import "KWQPrinter.h"
78 #import "KWQAccObjectCache.h"
79
80 #import "DOMInternal.h"
81 #import "WebCoreImageRenderer.h"
82 #import "WebCoreTextRendererFactory.h"
83 #import "WebCoreViewFactory.h"
84 #import "WebCoreSettings.h"
85
86 @class NSView;
87
88 using DOM::AtomicString;
89 using DOM::CSSStyleDeclarationImpl;
90 using DOM::DocumentFragmentImpl;
91 using DOM::DocumentImpl;
92 using DOM::DocumentTypeImpl;
93 using DOM::DOMString;
94 using DOM::ElementImpl;
95 using DOM::HTMLElementImpl;
96 using DOM::HTMLFormElementImpl;
97 using DOM::HTMLGenericFormElementImpl;
98 using DOM::HTMLImageElementImpl;
99 using DOM::HTMLInputElementImpl;
100 using DOM::HTMLTags;
101 using DOM::HTMLAttributes;
102 using DOM::NodeImpl;
103 using DOM::Position;
104 using DOM::RangeImpl;
105
106 using khtml::ChildrenOnly;
107 using khtml::createMarkup;
108 using khtml::Decoder;
109 using khtml::DeleteSelectionCommand;
110 using khtml::DOWNSTREAM;
111 using khtml::EAffinity;
112 using khtml::EditAction;
113 using khtml::EditCommandPtr;
114 using khtml::ETextGranularity;
115 using khtml::IncludeNode;
116 using khtml::MoveSelectionCommand;
117 using khtml::parseURL;
118 using khtml::RenderCanvas;
119 using khtml::RenderImage;
120 using khtml::RenderObject;
121 using khtml::RenderPart;
122 using khtml::RenderStyle;
123 using khtml::RenderWidget;
124 using khtml::ReplaceSelectionCommand;
125 using khtml::Selection;
126 using khtml::SharedPtr;
127 using khtml::setAffinityUsingLinePosition;
128 using khtml::Tokenizer;
129 using khtml::TextIterator;
130 using khtml::TypingCommand;
131 using khtml::UPSTREAM;
132 using khtml::VisiblePosition;
133
134 using KJS::ExecState;
135 using KJS::ObjectImp;
136 using KJS::SavedProperties;
137 using KJS::SavedBuiltins;
138 using KJS::Window;
139
140 using KParts::URLArgs;
141
142 using KJS::Bindings::RootObject;
143
144 NSString *WebCoreElementDOMNodeKey =            @"WebElementDOMNode";
145 NSString *WebCoreElementFrameKey =              @"WebElementFrame";
146 NSString *WebCoreElementImageAltStringKey =     @"WebElementImageAltString";
147 NSString *WebCoreElementImageKey =              @"WebElementImage";
148 NSString *WebCoreElementImageRectKey =          @"WebElementImageRect";
149 NSString *WebCoreElementImageURLKey =           @"WebElementImageURL";
150 NSString *WebCoreElementIsSelectedKey =         @"WebElementIsSelected";
151 NSString *WebCoreElementLinkURLKey =            @"WebElementLinkURL";
152 NSString *WebCoreElementLinkTargetFrameKey =    @"WebElementTargetFrame";
153 NSString *WebCoreElementLinkLabelKey =          @"WebElementLinkLabel";
154 NSString *WebCoreElementLinkTitleKey =          @"WebElementLinkTitle";
155 NSString *WebCoreElementNameKey =               @"WebElementName";
156 NSString *WebCoreElementTitleKey =              @"WebCoreElementTitle"; // not in WebKit API for now, could be in API some day
157
158 NSString *WebCorePageCacheStateKey =            @"WebCorePageCacheState";
159
160 @interface WebCoreBridge (WebCoreBridgeInternal)
161 - (RootObject *)executionContextForView:(NSView *)aView;
162 @end
163
164 static RootObject *rootForView(void *v)
165 {
166     NSView *aView = (NSView *)v;
167     WebCoreBridge *aBridge = [[WebCoreViewFactory sharedFactory] bridgeForView:aView];
168     RootObject *root = 0;
169
170     if (aBridge)
171         root = [aBridge executionContextForView:aView];
172
173     return root;
174 }
175
176 static pthread_t mainThread = 0;
177
178 static void updateRenderingForBindings (ExecState *exec, ObjectImp *rootObject)
179 {
180     if (pthread_self() != mainThread)
181         return;
182         
183     if (!rootObject)
184         return;
185         
186     Window *window = static_cast<Window*>(rootObject);
187     if (!window)
188         return;
189         
190     DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(window->part()->xmlDocImpl());
191     if (doc)
192         doc->updateRendering();
193 }
194
195 static BOOL partHasSelection(WebCoreBridge *bridge)
196 {
197     if (!bridge)
198         return NO;
199     
200     KHTMLPart *part = [bridge part];
201     if (!part)
202         return NO;
203         
204     if (part->selection().isNone())
205         return NO;
206
207     // If a part has a selection, it should also have a document.        
208     ASSERT(part->xmlDocImpl());
209
210     return YES;
211 }
212
213 static BOOL hasCaseInsensitivePrefix(NSString *string, NSString *prefix)
214 {
215     return [string rangeOfString:prefix options:(NSCaseInsensitiveSearch | NSAnchoredSearch)].location !=
216         NSNotFound;
217 }
218
219 @implementation WebCoreBridge
220
221 static bool initializedObjectCacheSize = FALSE;
222 static bool initializedKJS = FALSE;
223
224 + (WebCoreBridge *)bridgeForDOMDocument:(DOMDocument *)document
225 {
226     return ((KWQKHTMLPart *)[document _documentImpl]->part())->bridge();
227 }
228
229 - init
230 {
231     [super init];
232     
233     _part = new KWQKHTMLPart;
234     _part->setBridge(self);
235
236     if (!initializedObjectCacheSize){
237         khtml::Cache::setSize([self getObjectCacheSize]);
238         initializedObjectCacheSize = TRUE;
239     }
240     
241     if (!initializedKJS) {
242         mainThread = pthread_self();
243         
244         RootObject::setFindRootObjectForNativeHandleFunction (rootForView);
245
246         KJS::Bindings::Instance::setDidExecuteFunction(updateRenderingForBindings);
247         
248         initializedKJS = TRUE;
249     }
250     
251     _shouldCreateRenderers = YES;
252     
253     return self;
254 }
255
256 - (void)initializeSettings: (WebCoreSettings *)settings
257 {
258     _part->setSettings ([settings settings]);
259 }
260
261 - (void)dealloc
262 {
263     [self removeFromFrame];
264     
265     if (_renderPart) {
266         _renderPart->deref(_renderPartArena);
267     }
268     _part->setBridge(nil);
269     _part->deref();
270         
271     [super dealloc];
272 }
273
274 - (void)finalize
275 {
276     // FIXME: This work really should not be done at deallocation time.
277     // We need to do it at some well-defined time instead.
278
279     [self removeFromFrame];
280     
281     if (_renderPart) {
282         _renderPart->deref(_renderPartArena);
283     }
284     _part->setBridge(nil);
285     _part->deref();
286         
287     [super finalize];
288 }
289
290 - (KWQKHTMLPart *)part
291 {
292     return _part;
293 }
294
295 - (void)setRenderPart:(KHTMLRenderPart *)newPart;
296 {
297     RenderArena *arena = newPart->ref();
298     if (_renderPart) {
299         _renderPart->deref(_renderPartArena);
300     }
301     _renderPart = newPart;
302     _renderPartArena = arena;
303 }
304
305 - (KHTMLRenderPart *)renderPart
306 {
307     return _renderPart;
308 }
309
310 - (void)setParent:(WebCoreBridge *)parent
311 {
312     _part->setParent([parent part]);
313 }
314
315 - (void)provisionalLoadStarted
316 {
317     _part->provisionalLoadStarted();
318 }
319
320 - (void)openURL:(NSURL *)URL reload:(BOOL)reload contentType:(NSString *)contentType refresh:(NSString *)refresh lastModified:(NSDate *)lastModified pageCache:(NSDictionary *)pageCache
321 {
322     if (pageCache) {
323         KWQPageState *state = [pageCache objectForKey:WebCorePageCacheStateKey];
324         _part->openURLFromPageCache(state);
325         [state invalidate];
326         return;
327     }
328         
329     // arguments
330     URLArgs args(_part->browserExtension()->urlArgs());
331     args.reload = reload;
332     if (contentType) {
333         args.serviceType = QString::fromNSString(contentType);
334     }
335     _part->browserExtension()->setURLArgs(args);
336
337     // opening the URL
338     if (_part->didOpenURL(URL)) {
339         // things we have to set up after calling didOpenURL
340         if (refresh) {
341             _part->addMetaData("http-refresh", QString::fromNSString(refresh));
342         }
343         if (lastModified) {
344             NSString *modifiedString = [lastModified descriptionWithCalendarFormat:@"%a %b %d %Y %H:%M:%S" timeZone:nil locale:nil];
345             _part->addMetaData("modified", QString::fromNSString(modifiedString));
346         }
347     }
348 }
349
350 - (void)setEncoding:(NSString *)encoding userChosen:(BOOL)userChosen
351 {
352     _part->setEncoding(QString::fromNSString(encoding), userChosen);
353 }
354
355 - (void)addData:(NSData *)data
356 {
357     DocumentImpl *doc = _part->xmlDocImpl();
358     
359     // Document may be nil if the part is about to redirect
360     // as a result of JS executing during load, i.e. one frame
361     // changing another's location before the frame's document
362     // has been created. 
363     if (doc){
364         doc->setShouldCreateRenderers([self shouldCreateRenderers]);
365         _part->addData((const char *)[data bytes], [data length]);
366     }
367 }
368
369 - (void)closeURL
370 {
371     _part->closeURL();
372 }
373
374 - (void)stopLoading
375 {
376     _part->stopLoading();
377 }
378
379 - (void)didNotOpenURL:(NSURL *)URL pageCache:(NSDictionary *)pageCache
380 {
381     _part->didNotOpenURL(KURL(URL).url());
382
383     // We might have made a page cache item, but now we're bailing out due to an error before we ever
384     // transitioned to the new page (before WebFrameState==commit).  The goal here is to restore any state
385     // so that the existing view (that wenever got far enough to replace) can continue being used.
386     DocumentImpl *doc = _part->xmlDocImpl();
387     if (doc) {
388         doc->setInPageCache(NO);
389     }
390     KWQPageState *state = [pageCache objectForKey:WebCorePageCacheStateKey];
391     [state invalidate];
392 }
393
394 - (BOOL)canLoadURL:(NSURL *)URL fromReferrer:(NSString *)referrer hideReferrer:(BOOL *)hideReferrer
395 {
396     BOOL referrerIsWebURL = hasCaseInsensitivePrefix(referrer, @"http:") || hasCaseInsensitivePrefix(referrer, @"https:");
397     BOOL referrerIsLocalURL = hasCaseInsensitivePrefix(referrer, @"file:") || hasCaseInsensitivePrefix(referrer, @"applewebdata:");
398     BOOL URLIsFileURL = [URL scheme] != NULL && [[URL scheme] compare:@"file" options:(NSCaseInsensitiveSearch|NSLiteralSearch)] == NSOrderedSame;
399     
400     *hideReferrer = !referrerIsWebURL;
401     return !URLIsFileURL || referrerIsLocalURL;
402 }
403
404 - (void)saveDocumentState
405 {
406     DocumentImpl *doc = _part->xmlDocImpl();
407     if (doc != 0){
408         QStringList list = doc->docState();
409         NSMutableArray *documentState = [[[NSMutableArray alloc] init] autorelease];
410         
411         for (uint i = 0; i < list.count(); i++){
412             QString s = list[i];
413             [documentState addObject: [NSString stringWithCharacters: (const unichar *)s.unicode() length: s.length()]];
414         }
415         [self saveDocumentState: documentState];
416     }
417 }
418
419 - (void)restoreDocumentState
420 {
421     DocumentImpl *doc = _part->xmlDocImpl();
422     
423     if (doc != 0){
424         NSArray *documentState = [self documentState];
425         
426         QStringList s;
427         for (uint i = 0; i < [documentState count]; i++){
428             NSString *string = [documentState objectAtIndex: i];
429             s.append(QString::fromNSString(string));
430         }
431             
432         doc->setRestoreState(s);
433     }
434 }
435
436 - (void)scrollToAnchorWithURL:(NSURL *)URL
437 {
438     _part->scrollToAnchor(KURL(URL).url().latin1());
439 }
440
441 - (BOOL)scrollOverflowInDirection:(WebScrollDirection)direction granularity:(WebScrollGranularity)granularity
442 {
443     if (_part == NULL) {
444         return NO;
445     }
446     return _part->scrollOverflow((KWQScrollDirection)direction, (KWQScrollGranularity)granularity);
447 }
448
449 - (BOOL)sendScrollWheelEvent:(NSEvent *)event
450 {
451     return _part ? _part->wheelEvent(event) : NO;
452 }
453
454 - (BOOL)saveDocumentToPageCache
455 {
456     DocumentImpl *doc = _part->xmlDocImpl();
457     if (!doc) {
458         return NO;
459     }
460     
461     if (!doc->view()) {
462         return NO;
463     }
464     _part->clearTimers();
465
466     SavedProperties *windowProperties = new SavedProperties;
467     _part->saveWindowProperties(windowProperties);
468
469     SavedProperties *locationProperties = new SavedProperties;
470     _part->saveLocationProperties(locationProperties);
471     
472     SavedBuiltins *interpreterBuiltins = new SavedBuiltins;
473     _part->saveInterpreterBuiltins(*interpreterBuiltins);
474
475     KWQPageState *pageState = [[[KWQPageState alloc] initWithDocument:doc
476                                                                   URL:_part->m_url
477                                                      windowProperties:windowProperties
478                                                    locationProperties:locationProperties
479                                                   interpreterBuiltins:interpreterBuiltins] autorelease];
480     [pageState setPausedActions: _part->pauseActions((const void *)pageState)];
481
482     return [self saveDocumentToPageCache:pageState];
483 }
484
485 - (BOOL)canCachePage
486 {
487     return _part->canCachePage();
488 }
489
490 - (void)clear
491 {
492     _part->clear();
493 }
494
495 - (void)end
496 {
497     _part->end();
498 }
499
500 - (void)stop
501 {
502     _part->stop();
503 }
504
505 - (void)mainResourceError
506 {
507     _part->handleFallbackContent();
508 }
509
510 - (void)createKHTMLViewWithNSView:(NSView *)view marginWidth:(int)mw marginHeight:(int)mh
511 {
512     // If we own the view, delete the old one - otherwise the render _part will take care of deleting the view.
513     [self removeFromFrame];
514
515     KHTMLView *kview = new KHTMLView(_part, 0);
516     _part->setView(kview);
517     kview->deref();
518
519     kview->setView(view);
520     if (mw >= 0)
521         kview->setMarginWidth(mw);
522     if (mh >= 0)
523         kview->setMarginHeight(mh);
524 }
525
526 - (void)scrollToAnchor:(NSString *)a
527 {
528     _part->gotoAnchor(QString::fromNSString(a));
529 }
530
531 - (BOOL)isSelectionEditable
532 {
533     // EDIT FIXME: This needs to consider the entire selected range
534     NodeImpl *startNode = _part->selection().start().node();
535     return startNode ? startNode->isContentEditable() : NO;
536 }
537
538 - (WebSelectionState)selectionState
539 {
540     switch (_part->selection().state()) {
541         case Selection::NONE:
542             return WebSelectionStateNone;
543         case Selection::CARET:
544             return WebSelectionStateCaret;
545         case Selection::RANGE:
546             return WebSelectionStateRange;
547     }
548     
549     ASSERT_NOT_REACHED();
550     return WebSelectionStateNone;
551 }
552
553 - (NSString *)_documentTypeString
554 {
555     NSString *documentTypeString = nil;
556     DOM::DocumentImpl *doc = _part->xmlDocImpl();
557     if (doc) {
558         DocumentTypeImpl *doctype = doc->realDocType();
559         if (doctype) {
560             documentTypeString = doctype->toString().string().getNSString();
561         }
562     }
563     return documentTypeString;
564 }
565
566 - (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString
567 {
568     NSString *documentTypeString = [self _documentTypeString];
569     if (documentTypeString && markupString) {
570         return [NSString stringWithFormat:@"%@%@", documentTypeString, markupString];
571     } else if (documentTypeString) {
572         return documentTypeString;
573     } else if (markupString) {
574         return markupString;
575     } else {
576         return @"";
577     }
578 }
579
580 - (NSArray *)nodesFromList:(QPtrList<NodeImpl> *)nodeList
581 {
582     NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:nodeList->count()];
583     for (QPtrListIterator<NodeImpl> i(*nodeList); i.current(); ++i) {
584         [nodes addObject:[DOMNode _nodeWithImpl:i.current()]];
585     }
586     return nodes;
587 }
588
589 - (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes
590 {
591     // FIXME: This is never "for interchange". Is that right? See the next method.
592     QPtrList<NodeImpl> nodeList;
593     NSString *markupString = createMarkup([node _nodeImpl], IncludeNode, nodes ? &nodeList : 0).getNSString();
594     if (nodes) {
595         *nodes = [self nodesFromList:&nodeList];
596     }
597     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
598 }
599
600 - (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
601 {
602     // FIXME: This is always "for interchange". Is that right? See the previous method.
603     QPtrList<NodeImpl> nodeList;
604     NSString *markupString = createMarkup([range _rangeImpl], nodes ? &nodeList : 0, AnnotateForInterchange).getNSString();
605     if (nodes) {
606         *nodes = [self nodesFromList:&nodeList];
607     }
608     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
609 }
610
611 - (NSString *)selectedString
612 {
613     QString text = _part->selectedText();
614     text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
615     return [[text.getNSString() copy] autorelease];
616 }
617
618 - (NSString *)stringForRange:(DOMRange *)range
619 {
620     QString text = plainText([range _rangeImpl]);
621     text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
622     return [[text.getNSString() copy] autorelease];
623 }
624
625 - (void)selectAll
626 {
627     _part->selectAll();
628 }
629
630 - (void)deselectAll
631 {
632     [self deselectText];
633     DocumentImpl *doc = _part->xmlDocImpl();
634     if (doc) {
635         doc->setFocusNode(0);
636     }
637 }
638
639 - (void)deselectText
640 {
641     _part->clearSelection();
642 }
643
644 - (BOOL)isFrameSet
645 {
646     return _part->isFrameSet();
647 }
648
649 - (void)reapplyStylesForDeviceType:(WebCoreDeviceType)deviceType
650 {
651     _part->setMediaType(deviceType == WebCoreDeviceScreen ? "screen" : "print");
652     DocumentImpl *doc = _part->xmlDocImpl();
653     if (doc) {
654         static QPaintDevice screen;
655         static QPrinter printer;
656         doc->setPaintDevice(deviceType == WebCoreDeviceScreen ? &screen : &printer);
657     }
658     return _part->reparseConfiguration();
659 }
660
661 static BOOL nowPrinting(WebCoreBridge *self)
662 {
663     DocumentImpl *doc = self->_part->xmlDocImpl();
664     return doc && doc->paintDevice() && doc->paintDevice()->devType() == QInternal::Printer;
665 }
666
667 // Set or unset the printing mode in the view.  We only toy with this if we're printing.
668 - (void)_setupRootForPrinting:(BOOL)onOrOff
669 {
670     if (nowPrinting(self)) {
671         RenderCanvas *root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
672         if (root) {
673             root->setPrintingMode(onOrOff);
674         }
675     }
676 }
677
678 - (void)forceLayoutAdjustingViewSize:(BOOL)flag
679 {
680     [self _setupRootForPrinting:YES];
681     _part->forceLayout();
682     if (flag) {
683         [self adjustViewSize];
684     }
685     [self _setupRootForPrinting:NO];
686 }
687
688 - (void)forceLayoutWithMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)flag
689 {
690     [self _setupRootForPrinting:YES];
691     _part->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth);
692     if (flag) {
693         [self adjustViewSize];
694     }
695     [self _setupRootForPrinting:NO];
696 }
697
698 - (void)sendResizeEvent
699 {
700     _part->sendResizeEvent();
701 }
702
703 - (void)sendScrollEvent
704 {
705     _part->sendScrollEvent();
706 }
707
708 - (void)drawRect:(NSRect)rect withPainter:(QPainter *)p
709 {
710     [self _setupRootForPrinting:YES];
711     _part->paint(p, QRect(rect));
712     [self _setupRootForPrinting:NO];
713 }
714
715 - (void)drawRect:(NSRect)rect
716 {
717     QPainter painter(nowPrinting(self));
718     bool displaysWithFocusAttributes = _part->displaysWithFocusAttributes();
719     painter.setUsesInactiveTextBackgroundColor(!displaysWithFocusAttributes);
720     painter.setDrawsFocusRing(displaysWithFocusAttributes);
721     [self drawRect:rect withPainter:&painter];
722 }
723
724 // Used by pagination code called from AppKit when a standalone web page is printed.
725 - (NSArray*)computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight
726 {
727     [self _setupRootForPrinting:YES];
728     NSMutableArray* pages = [NSMutableArray arrayWithCapacity:5];
729     if (printWidthScaleFactor <= 0) {
730         ERROR("printWidthScaleFactor has bad value %.2f", printWidthScaleFactor);
731         return pages;
732     }
733     
734     if (printHeight <= 0) {
735         ERROR("printHeight has bad value %.2f", printHeight);
736         return pages;
737     }
738         
739     if (!_part || !_part->xmlDocImpl() || !_part->view()) return pages;
740     RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
741     if (!root) return pages;
742     
743     KHTMLView* view = _part->view();
744     NSView* documentView = view->getDocumentView();
745     if (!documentView)
746         return pages;
747         
748     float currPageHeight = printHeight;
749     float docHeight = root->layer()->height();
750     float docWidth = root->layer()->width();
751     float printWidth = docWidth/printWidthScaleFactor;
752     
753     // We need to give the part the opportunity to adjust the page height at each step.
754     for (float i = 0; i < docHeight; i += currPageHeight) {
755         float proposedBottom = kMin(docHeight, i + printHeight);
756         _part->adjustPageHeight(&proposedBottom, i, proposedBottom, i);
757         currPageHeight = kMax(1.0f, proposedBottom - i);
758         for (float j = 0; j < docWidth; j += printWidth) {
759             NSValue* val = [NSValue valueWithRect: NSMakeRect(j, i, printWidth, currPageHeight)];
760             [pages addObject: val];
761         }
762     }
763     [self _setupRootForPrinting:NO];
764     
765     return pages;
766 }
767
768 // This is to support the case where a webview is embedded in the view that's being printed
769 - (void)adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit
770 {
771     [self _setupRootForPrinting:YES];
772     _part->adjustPageHeight(newBottom, oldTop, oldBottom, bottomLimit);
773     [self _setupRootForPrinting:NO];
774 }
775
776 - (NSObject *)copyDOMNode:(NodeImpl *)node copier:(id <WebCoreDOMTreeCopier>)copier
777 {
778     NSMutableArray *children = [[NSMutableArray alloc] init];
779     for (NodeImpl *child = node->firstChild(); child; child = child->nextSibling()) {
780         [children addObject:[self copyDOMNode:child copier:copier]];
781     }
782     NSObject *copiedNode = [copier nodeWithName:node->nodeName().string().getNSString()
783                                           value:node->nodeValue().string().getNSString()
784                                          source:createMarkup(node, ChildrenOnly).getNSString()
785                                        children:children];
786     [children release];
787     return copiedNode;
788 }
789
790 - (NSObject *)copyDOMTree:(id <WebCoreDOMTreeCopier>)copier
791 {
792     DocumentImpl *doc = _part->xmlDocImpl();
793     if (!doc) {
794         return nil;
795     }
796     return [self copyDOMNode:doc copier:copier];
797 }
798
799 - (NSObject *)copyRenderNode:(RenderObject *)node copier:(id <WebCoreRenderTreeCopier>)copier
800 {
801     NSMutableArray *children = [[NSMutableArray alloc] init];
802     for (RenderObject *child = node->firstChild(); child; child = child->nextSibling()) {
803         [children addObject:[self copyRenderNode:child copier:copier]];
804     }
805           
806     NSString *name = [[NSString alloc] initWithUTF8String:node->renderName()];
807     
808     RenderWidget *renderWidget = node->isWidget() ? static_cast<RenderWidget *>(node) : 0;
809     QWidget *widget = renderWidget ? renderWidget->widget() : 0;
810     NSView *view = widget ? widget->getView() : nil;
811     
812     int nx, ny;
813     node->absolutePosition(nx,ny);
814     NSObject *copiedNode = [copier nodeWithName:name
815                                        position:NSMakePoint(nx,ny)
816                                            rect:NSMakeRect(node->xPos(), node->yPos(), node->width(), node->height())
817                                            view:view
818                                        children:children];
819     
820     [name release];
821     [children release];
822     
823     return copiedNode;
824 }
825
826 - (NSObject *)copyRenderTree:(id <WebCoreRenderTreeCopier>)copier
827 {
828     RenderObject *renderer = _part->renderer();
829     if (!renderer) {
830         return nil;
831     }
832     return [self copyRenderNode:renderer copier:copier];
833 }
834
835 - (void)removeFromFrame
836 {
837     _part->setView(0);
838 }
839
840 - (void)installInFrame:(NSView *)view
841 {
842     // If this isn't the main frame, it must have a render _part set, or it
843     // won't ever get installed in the view hierarchy.
844     ASSERT(self == [self mainFrame] || _renderPart != nil);
845
846     _part->view()->setView(view);
847     if (_renderPart) {
848         _renderPart->setWidget(_part->view());
849         // Now the render part owns the view, so we don't any more.
850     }
851
852     _part->view()->initScrollBars();
853 }
854
855 - (void)setActivationEventNumber:(int)num
856 {
857     _part->setActivationEventNumber(num);
858 }
859
860 - (void)mouseDown:(NSEvent *)event
861 {
862     _part->mouseDown(event);
863 }
864
865 - (void)mouseDragged:(NSEvent *)event
866 {
867     _part->mouseDragged(event);
868 }
869
870 - (void)mouseUp:(NSEvent *)event
871 {
872     _part->mouseUp(event);
873 }
874
875 - (void)mouseMoved:(NSEvent *)event
876 {
877     _part->mouseMoved(event);
878 }
879
880 - (BOOL)sendContextMenuEvent:(NSEvent *)event
881 {
882     return _part->sendContextMenuEvent(event);
883 }
884
885 - (DOMElement *)elementForView:(NSView *)view
886 {
887     // FIXME: implemented currently for only a subset of the KWQ widgets
888     if ([view conformsToProtocol:@protocol(KWQWidgetHolder)]) {
889         NSView <KWQWidgetHolder> *widgetHolder = view;
890         QWidget *widget = [widgetHolder widget];
891         if (widget != nil) {
892             NodeImpl *node = static_cast<const RenderWidget *>(widget->eventFilterObject())->element();
893             return [DOMElement _elementWithImpl:static_cast<ElementImpl *>(node)];
894         }
895     }
896     return nil;
897 }
898
899 static NSView *viewForElement(ElementImpl *elementImpl)
900 {
901     RenderObject *renderer = elementImpl->renderer();
902     if (renderer && renderer->isWidget()) {
903         QWidget *widget = static_cast<const RenderWidget *>(renderer)->widget();
904         if (widget) {
905             widget->populate();
906             return widget->getView();
907         }
908     }
909     return nil;
910 }
911
912 - (NSView *)viewForElement:(DOMElement *)element
913 {
914     return viewForElement([element _elementImpl]);
915 }
916
917 static HTMLInputElementImpl *inputElementFromDOMElement(DOMElement *element)
918 {
919     NodeImpl *node = [element _nodeImpl];
920     if (node->hasTagName(HTMLTags::input())) {
921         return static_cast<HTMLInputElementImpl *>(node);
922     }
923     return nil;
924 }
925
926 static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
927 {
928     NodeImpl *node = [element _nodeImpl];
929     // This should not be necessary, but an XSL file on
930     // maps.google.com crashes otherwise because it is an xslt file
931     // that contains <form> elements that aren't in any namespace, so
932     // they come out as generic CML elements
933     if (node && node->hasTagName(HTMLTags::form())) {
934         return static_cast<HTMLFormElementImpl *>(node);
935     }
936     return nil;
937 }
938
939 - (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form
940 {
941     HTMLFormElementImpl *formElement = formElementFromDOMElement(form);
942     if (formElement) {
943         QPtrVector<HTMLGenericFormElementImpl> &elements = formElement->formElements;
944         QString targetName = QString::fromNSString(name);
945         for (unsigned int i = 0; i < elements.count(); i++) {
946             HTMLGenericFormElementImpl *elt = elements.at(i);
947             // Skip option elements, other duds
948             if (elt->name() == targetName) {
949                 return [DOMElement _elementWithImpl:elt];
950             }
951         }
952     }
953     return nil;
954 }
955
956 - (BOOL)elementDoesAutoComplete:(DOMElement *)element
957 {
958     HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
959     return inputElement != nil
960         && inputElement->inputType() == HTMLInputElementImpl::TEXT
961         && inputElement->autoComplete();
962 }
963
964 - (BOOL)elementIsPassword:(DOMElement *)element
965 {
966     HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
967     return inputElement != nil
968         && inputElement->inputType() == HTMLInputElementImpl::PASSWORD;
969 }
970
971 - (DOMElement *)formForElement:(DOMElement *)element;
972 {
973     HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
974     if (inputElement) {
975         HTMLFormElementImpl *formElement = inputElement->form();
976         if (formElement) {
977             return [DOMElement _elementWithImpl:formElement];
978         }
979     }
980     return nil;
981 }
982
983 - (DOMElement *)currentForm
984 {
985     HTMLFormElementImpl *formElement = _part->currentForm();
986     return formElement ? [DOMElement _elementWithImpl:formElement] : nil;
987 }
988
989 - (NSArray *)controlsInForm:(DOMElement *)form
990 {
991     NSMutableArray *results = nil;
992     HTMLFormElementImpl *formElement = formElementFromDOMElement(form);
993     if (formElement) {
994         QPtrVector<HTMLGenericFormElementImpl> &elements = formElement->formElements;
995         for (unsigned int i = 0; i < elements.count(); i++) {
996             if (elements.at(i)->isEnumeratable()) {             // Skip option elements, other duds
997                 DOMElement *de = [DOMElement _elementWithImpl:elements.at(i)];
998                 if (!results) {
999                     results = [NSMutableArray arrayWithObject:de];
1000                 } else {
1001                     [results addObject:de];
1002                 }
1003             }
1004         }
1005     }
1006     return results;
1007 }
1008
1009 - (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element
1010 {
1011     return _part->searchForLabelsBeforeElement(labels, [element _elementImpl]);
1012 }
1013
1014 - (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element
1015 {
1016     return _part->matchLabelsAgainstElement(labels, [element _elementImpl]);
1017 }
1018
1019 - (NSDictionary *)elementAtPoint:(NSPoint)point
1020 {
1021     RenderObject *renderer = _part->renderer();
1022     if (!renderer) {
1023         return nil;
1024     }
1025     RenderObject::NodeInfo nodeInfo(true, true);
1026     renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
1027     
1028     NSMutableDictionary *element = [NSMutableDictionary dictionary];
1029     [element setObject:[NSNumber numberWithBool:_part->isPointInsideSelection((int)point.x, (int)point.y)]
1030                 forKey:WebCoreElementIsSelectedKey];
1031     
1032     // Find the title in the nearest enclosing DOM node.
1033     // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
1034     for (NodeImpl *titleNode = nodeInfo.innerNode(); titleNode; titleNode = titleNode->parentNode()) {
1035         if (titleNode->isElementNode()) {
1036             const AtomicString& title = static_cast<ElementImpl *>(titleNode)->getAttribute(HTMLAttributes::title());
1037             if (!title.isNull()) {
1038                 // We found a node with a title.
1039                 QString titleText = title.string();
1040                 titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1041                 [element setObject:titleText.getNSString() forKey:WebCoreElementTitleKey];
1042                 break;
1043             }
1044         }
1045     }
1046
1047     NodeImpl *URLNode = nodeInfo.URLElement();
1048     if (URLNode) {
1049         ElementImpl *e = static_cast<ElementImpl *>(URLNode);
1050         DocumentImpl *doc = e->getDocument();
1051         ASSERT(doc);
1052         
1053         const AtomicString& title = e->getAttribute(HTMLAttributes::title());
1054         if (!title.isEmpty()) {
1055             QString titleText = title.string();
1056             titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1057             [element setObject:titleText.getNSString() forKey:WebCoreElementLinkTitleKey];
1058         }
1059         
1060         const AtomicString& link = e->getAttribute(HTMLAttributes::href());
1061         if (!link.isNull()) {
1062             QString t = plainText(rangeOfContents(e).get());
1063             if (!t.isEmpty()) {
1064                 [element setObject:t.getNSString() forKey:WebCoreElementLinkLabelKey];
1065             }
1066             QString URLString = parseURL(link).string();
1067             [element setObject:doc->completeURL(URLString).getNSString() forKey:WebCoreElementLinkURLKey];
1068         }
1069         
1070         DOMString target = e->getAttribute(HTMLAttributes::target());
1071         if (target.isEmpty() && doc) { // FIXME: Take out this doc check when we're not just before a release.
1072             target = doc->baseTarget();
1073         }
1074         if (!target.isEmpty()) {
1075             [element setObject:target.string().getNSString() forKey:WebCoreElementLinkTargetFrameKey];
1076         }
1077     }
1078
1079     NodeImpl *node = nodeInfo.innerNonSharedNode();
1080     if (node) {
1081         [element setObject:[DOMNode _nodeWithImpl:node] forKey:WebCoreElementDOMNodeKey];
1082     
1083         if (node->renderer() && node->renderer()->isImage()) {
1084             RenderImage *r = static_cast<RenderImage *>(node->renderer());
1085             NSImage * image = (NSImage *)(r->pixmap().image());
1086             // Only return image information if there is an image.
1087             if (image && !r->isDisplayingError()) {
1088                 [element setObject:r->pixmap().image() forKey:WebCoreElementImageKey];
1089             }
1090                 
1091             int x, y;
1092             if (r->absolutePosition(x, y)) {
1093                 NSValue *rect = [NSValue valueWithRect:NSMakeRect(x, y, r->contentWidth(), r->contentHeight())];
1094                 [element setObject:rect forKey:WebCoreElementImageRectKey];
1095             }
1096                 
1097             ElementImpl *i = static_cast<ElementImpl*>(node);
1098     
1099             // FIXME: Code copied from RenderImage::updateFromElement; should share.
1100             DOMString attr;
1101             if (i->hasTagName(HTMLTags::object())) {
1102                 attr = i->getAttribute(HTMLAttributes::data());
1103             } else {
1104                 attr = i->getAttribute(HTMLAttributes::src());
1105             }
1106             if (!attr.isEmpty()) {
1107                 QString URLString = parseURL(attr).string();
1108                 [element setObject:i->getDocument()->completeURL(URLString).getNSString() forKey:WebCoreElementImageURLKey];
1109             }
1110             
1111             // FIXME: Code copied from RenderImage::updateFromElement; should share.
1112             DOMString alt;
1113             if (i->hasTagName(HTMLTags::input()))
1114                 alt = static_cast<HTMLInputElementImpl *>(i)->altText();
1115             else if (i->hasTagName(HTMLTags::img()))
1116                 alt = static_cast<HTMLImageElementImpl *>(i)->altText();
1117             if (!alt.isNull()) {
1118                 QString altText = alt.string();
1119                 altText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1120                 [element setObject:altText.getNSString() forKey:WebCoreElementImageAltStringKey];
1121             }
1122         }
1123     }
1124     
1125     return element;
1126 }
1127
1128 - (NSURL *)URLWithAttributeString:(NSString *)string
1129 {
1130     DocumentImpl *doc = _part->xmlDocImpl();
1131     if (!doc) {
1132         return nil;
1133     }
1134     QString rel = parseURL(QString::fromNSString(string)).string();
1135     return KURL(doc->baseURL(), rel, doc->decoder() ? doc->decoder()->codec() : 0).getNSURL();
1136 }
1137
1138 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
1139 {
1140     return _part->findString(string, forward, caseFlag, wrapFlag);
1141 }
1142
1143 - (void)jumpToSelection
1144 {
1145     _part->jumpToSelection();
1146 }
1147
1148 - (NSString *)advanceToNextMisspelling
1149 {
1150     return _part->advanceToNextMisspelling().getNSString();
1151 }
1152
1153 - (NSString *)advanceToNextMisspellingStartingJustBeforeSelection
1154 {
1155     return _part->advanceToNextMisspelling(true).getNSString();
1156 }
1157
1158 - (void)unmarkAllMisspellings
1159 {
1160     DocumentImpl *doc = _part->xmlDocImpl();
1161     if (!doc) {
1162         return;
1163     }
1164     doc->removeAllMarkers();
1165 }
1166
1167 - (void)setTextSizeMultiplier:(float)multiplier
1168 {
1169     int newZoomFactor = (int)rint(multiplier * 100);
1170     if (_part->zoomFactor() == newZoomFactor) {
1171         return;
1172     }
1173     _part->setZoomFactor(newZoomFactor);
1174 }
1175
1176 - (CFStringEncoding)textEncoding
1177 {
1178     return KWQCFStringEncodingFromIANACharsetName(_part->encoding().latin1());
1179 }
1180
1181 - (NSView *)nextKeyView
1182 {
1183     DocumentImpl *doc = _part->xmlDocImpl();
1184     if (!doc) {
1185         return nil;
1186     }
1187     return _part->nextKeyView(doc->focusNode(), KWQSelectingNext);
1188 }
1189
1190 - (NSView *)previousKeyView
1191 {
1192     DocumentImpl *doc = _part->xmlDocImpl();
1193     if (!doc) {
1194         return nil;
1195     }
1196     return _part->nextKeyView(doc->focusNode(), KWQSelectingPrevious);
1197 }
1198
1199 - (NSView *)nextKeyViewInsideWebFrameViews
1200 {
1201     DocumentImpl *doc = _part->xmlDocImpl();
1202     if (!doc) {
1203         return nil;
1204     }
1205     
1206     return _part->nextKeyViewInFrameHierarchy(doc->focusNode(), KWQSelectingNext);
1207 }
1208
1209 - (NSView *)previousKeyViewInsideWebFrameViews
1210 {
1211     DocumentImpl *doc = _part->xmlDocImpl();
1212     if (!doc) {
1213         return nil;
1214     }
1215
1216     return _part->nextKeyViewInFrameHierarchy(doc->focusNode(), KWQSelectingPrevious);
1217 }
1218
1219 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string
1220 {
1221     return [self stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
1222 }
1223
1224 // 
1225 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
1226 {
1227     _part->createEmptyDocument();
1228     return _part->executeScript(QString::fromNSString(string), forceUserGesture).asString().getNSString();
1229 }
1230
1231 - (WebScriptObject *)windowScriptObject
1232 {
1233     return _part->windowScriptObject();
1234 }
1235
1236 - (NPObject *)windowScriptNPObject
1237 {
1238     return _part->windowScriptNPObject();
1239 }
1240
1241 - (DOMDocument *)DOMDocument
1242 {
1243     return [DOMDocument _documentWithImpl:_part->xmlDocImpl()];
1244 }
1245
1246 - (DOMHTMLElement *)frameElement
1247 {
1248     return (DOMHTMLElement *)[[self DOMDocument] _ownerElement];
1249 }
1250
1251 - (NSAttributedString *)selectedAttributedString
1252 {
1253     return _part->attributedString(_part->selectionStart(), _part->selectionStartOffset(), _part->selectionEnd(), _part->selectionEndOffset());
1254 }
1255
1256 - (NSAttributedString *)attributedStringFrom:(DOMNode *)start startOffset:(int)startOffset to:(DOMNode *)end endOffset:(int)endOffset
1257 {
1258     DOMNode *startNode = start;
1259     DOMNode *endNode = end;
1260     return _part->attributedString([startNode _nodeImpl], startOffset, [endNode _nodeImpl], endOffset);
1261 }
1262
1263 - (NSRect)selectionRect
1264 {
1265     return _part->selectionRect(); 
1266 }
1267
1268 - (NSRect)visibleSelectionRect
1269 {
1270     return _part->visibleSelectionRect(); 
1271 }
1272
1273 - (void)centerSelectionInVisibleArea
1274 {
1275     _part->centerSelectionInVisibleArea(); 
1276 }
1277
1278 - (NSRect)caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
1279 {
1280     return [node _nodeImpl]->renderer()->caretRect(offset, static_cast<EAffinity>(affinity));
1281 }
1282 - (NSRect)firstRectForDOMRange:(DOMRange *)range
1283 {
1284     int extraWidthToEndOfLine = 0;
1285     QRect startCaretRect = [[range startContainer] _nodeImpl]->renderer()->caretRect([range startOffset], UPSTREAM, &extraWidthToEndOfLine);
1286     QRect endCaretRect = [[range startContainer] _nodeImpl]->renderer()->caretRect([range endOffset], UPSTREAM);
1287
1288     if (startCaretRect.y() == endCaretRect.y()) {
1289         // start and end are on the same line
1290         return QRect(MIN(startCaretRect.x(), endCaretRect.x()), 
1291                      startCaretRect.y(), 
1292                      abs(endCaretRect.x() - startCaretRect.x()),
1293                      MAX(startCaretRect.height(), endCaretRect.height()));
1294     }
1295
1296     // start and end aren't on the same line, so go from start to the end of its line
1297     return QRect(startCaretRect.x(), 
1298                  startCaretRect.y(),
1299                  startCaretRect.width() + extraWidthToEndOfLine,
1300                  startCaretRect.height());
1301 }
1302
1303 - (NSImage *)selectionImage
1304 {
1305     return _part->selectionImage();
1306 }
1307
1308 - (void)setName:(NSString *)name
1309 {
1310     _part->KHTMLPart::setName(QString::fromNSString(name));
1311 }
1312
1313 - (NSString *)name
1314 {
1315     return _part->name().getNSString();
1316 }
1317
1318 - (NSURL *)URL
1319 {
1320     return _part->url().getNSURL();
1321 }
1322
1323 - (NSURL *)baseURL
1324 {
1325     return _part->completeURL(_part->xmlDocImpl()->baseURL()).getNSURL();
1326 }
1327
1328 - (NSString *)referrer
1329 {
1330     return _part->referrer().getNSString();
1331 }
1332
1333 - (NSString *)domain
1334 {
1335     DocumentImpl *doc = _part->xmlDocImpl();
1336     if (doc && doc->isHTMLDocument()) {
1337         return doc->domain().string().getNSString();
1338     }
1339     return nil;
1340 }
1341
1342 - (WebCoreBridge *)opener
1343 {
1344     KHTMLPart *openerPart = _part->opener();
1345
1346     if (openerPart)
1347         return KWQ(openerPart)->bridge();
1348
1349     return nil;
1350 }
1351
1352 - (void)setOpener:(WebCoreBridge *)bridge;
1353 {
1354     KHTMLPart *p = [bridge part];
1355     
1356     if (p)
1357         p->setOpener(_part);
1358 }
1359
1360 + (NSString *)stringWithData:(NSData *)data textEncoding:(CFStringEncoding)textEncoding
1361 {
1362     if (textEncoding == kCFStringEncodingInvalidId || textEncoding == kCFStringEncodingISOLatin1) {
1363         textEncoding = kCFStringEncodingWindowsLatin1;
1364     }
1365     return QTextCodec(textEncoding).toUnicode((const char*)[data bytes], [data length]).getNSString();
1366 }
1367
1368 + (NSString *)stringWithData:(NSData *)data textEncodingName:(NSString *)textEncodingName
1369 {
1370     CFStringEncoding textEncoding = KWQCFStringEncodingFromIANACharsetName([textEncodingName lossyCString]);
1371     return [WebCoreBridge stringWithData:data textEncoding:textEncoding];
1372 }
1373
1374 - (BOOL)needsLayout
1375 {
1376     RenderObject *renderer = _part->renderer();
1377     return renderer ? renderer->needsLayout() : false;
1378 }
1379
1380 - (void)setNeedsLayout
1381 {
1382     RenderObject *renderer = _part->renderer();
1383     if (renderer)
1384         renderer->setNeedsLayout(true);
1385 }
1386
1387 - (BOOL)interceptKeyEvent:(NSEvent *)event toView:(NSView *)view
1388 {
1389     return _part->keyEvent(event);
1390 }
1391
1392 - (NSString *)renderTreeAsExternalRepresentation
1393 {
1394     return externalRepresentation(_part->renderer()).getNSString();
1395 }
1396
1397 - (void)setSelectionFromNone
1398 {
1399     _part->setSelectionFromNone();
1400 }
1401
1402 - (void)setDisplaysWithFocusAttributes:(BOOL)flag
1403 {
1404     _part->setDisplaysWithFocusAttributes(flag);
1405 }
1406
1407 - (void)setWindowHasFocus:(BOOL)flag
1408 {
1409     _part->setWindowHasFocus(flag);
1410 }
1411
1412 - (void)setShouldCreateRenderers:(BOOL)f
1413 {
1414     _shouldCreateRenderers = f;
1415 }
1416
1417 - (BOOL)shouldCreateRenderers
1418 {
1419     return _shouldCreateRenderers;
1420 }
1421
1422 - (int)numPendingOrLoadingRequests
1423 {
1424     DocumentImpl *doc = _part->xmlDocImpl();
1425     
1426     if (doc)
1427         return KWQNumberOfPendingOrLoadingRequests (doc->docLoader());
1428     return 0;
1429 }
1430
1431 - (BOOL)doneProcessingData
1432 {
1433     DocumentImpl *doc = _part->xmlDocImpl();
1434     if (doc) {
1435         Tokenizer* tok = doc->tokenizer();
1436         if (tok)
1437             return !tok->processingData();
1438     }
1439     return YES;
1440 }
1441
1442 - (NSColor *)bodyBackgroundColor
1443 {
1444     return _part->bodyBackgroundColor();
1445 }
1446
1447 - (NSColor *)selectionColor
1448 {
1449     RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
1450     if (root) {
1451         RenderStyle *pseudoStyle = root->getPseudoStyle(RenderStyle::SELECTION);
1452         if (pseudoStyle && pseudoStyle->backgroundColor().isValid()) {
1453             return nsColor(pseudoStyle->backgroundColor());
1454         }
1455     }
1456     return _part->displaysWithFocusAttributes() ? [NSColor selectedTextBackgroundColor] : [NSColor secondarySelectedControlColor];
1457 }
1458
1459 - (void)adjustViewSize
1460 {
1461     KHTMLView *view = _part->view();
1462     if (view)
1463         view->adjustViewSize();
1464 }
1465
1466 -(id)accessibilityTree
1467 {
1468     KWQAccObjectCache::enableAccessibility();
1469     if (!_part || !_part->xmlDocImpl()) return nil;
1470     RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
1471     if (!root) return nil;
1472     return _part->xmlDocImpl()->getAccObjectCache()->accObject(root);
1473 }
1474
1475 - (void)setDrawsBackground:(BOOL)drawsBackground
1476 {
1477     if (_part && _part->view())
1478         _part->view()->setTransparent(!drawsBackground);
1479 }
1480
1481 - (void)undoEditing:(id)arg
1482 {
1483     ASSERT([arg isKindOfClass:[KWQEditCommand class]]);
1484     [arg command]->unapply();
1485 }
1486
1487 - (void)redoEditing:(id)arg
1488 {
1489     ASSERT([arg isKindOfClass:[KWQEditCommand class]]);
1490     [arg command]->reapply();
1491 }
1492
1493 - (DOMRange *)rangeByExpandingSelectionWithGranularity:(WebSelectionGranularity)granularity
1494 {
1495     if (!partHasSelection(self))
1496         return nil;
1497         
1498     // NOTE: The enums *must* match the very similar ones declared in ktml_selection.h
1499     Selection selection(_part->selection());
1500     selection.expandUsingGranularity(static_cast<ETextGranularity>(granularity));
1501     return [DOMRange _rangeWithImpl:selection.toRange().get()];
1502 }
1503
1504 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
1505 {
1506     if (!partHasSelection(self))
1507         return nil;
1508         
1509     // NOTE: The enums *must* match the very similar ones declared in ktml_selection.h
1510     Selection selection(_part->selection());
1511     selection.modify(static_cast<Selection::EAlter>(alteration), 
1512                      static_cast<Selection::EDirection>(direction), 
1513                      static_cast<ETextGranularity>(granularity));
1514     return [DOMRange _rangeWithImpl:selection.toRange().get()];
1515 }
1516
1517 - (void)alterCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
1518 {
1519     if (!partHasSelection(self))
1520         return;
1521         
1522     // NOTE: The enums *must* match the very similar ones declared in dom_selection.h
1523     Selection selection(_part->selection());
1524     selection.modify(static_cast<Selection::EAlter>(alteration), 
1525                      static_cast<Selection::EDirection>(direction), 
1526                      static_cast<ETextGranularity>(granularity));
1527
1528     // save vertical navigation x position if necessary; many types of motion blow it away
1529     int xPos = KHTMLPart::NoXPosForVerticalArrowNavigation;
1530     switch (granularity) {
1531         case WebSelectByLine:
1532         case WebSelectByParagraph:
1533             xPos = _part->xPosForVerticalArrowNavigation();
1534             break;
1535         case WebSelectByCharacter:
1536         case WebSelectByWord:
1537         case WebSelectToLineBoundary:
1538         case WebSelectToParagraphBoundary:
1539         case WebSelectToDocumentBoundary:
1540             break;
1541     }
1542
1543     
1544     // setting the selection always clears saved vertical navigation x position
1545     _part->setSelection(selection);
1546     
1547     // altering the selection also sets the granularity back to character
1548     // NOTE: The one exception is that we need to keep word granularity
1549     // to preserve smart delete behavior when extending by word.  e.g. double-click,
1550     // then shift-option-rightarrow, then delete needs to smart delete, per TextEdit.
1551     if (!((alteration == WebSelectByExtending) &&
1552           (granularity == WebSelectByWord) && (_part->selectionGranularity() == khtml::WORD)))
1553         _part->setSelectionGranularity(static_cast<ETextGranularity>(WebSelectByCharacter));
1554     
1555     // restore vertical navigation x position if necessary
1556     if (xPos != KHTMLPart::NoXPosForVerticalArrowNavigation)
1557         _part->setXPosForVerticalArrowNavigation(xPos);
1558
1559     _part->selectFrameElementInParentIfFullySelected();
1560
1561     [self ensureSelectionVisible];
1562 }
1563
1564 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration verticalDistance:(float)verticalDistance
1565 {
1566     if (!partHasSelection(self))
1567         return nil;
1568         
1569     Selection selection(_part->selection());
1570     selection.modify(static_cast<Selection::EAlter>(alteration), static_cast<int>(verticalDistance));
1571     return [DOMRange _rangeWithImpl:selection.toRange().get()];
1572 }
1573
1574 - (void)alterCurrentSelection:(WebSelectionAlteration)alteration verticalDistance:(float)verticalDistance
1575 {
1576     if (!partHasSelection(self))
1577         return;
1578         
1579     Selection selection(_part->selection());
1580     selection.modify(static_cast<Selection::EAlter>(alteration), static_cast<int>(verticalDistance));
1581
1582     // setting the selection always clears saved vertical navigation x position, so preserve it
1583     int xPos = _part->xPosForVerticalArrowNavigation();
1584     _part->setSelection(selection);
1585     _part->setSelectionGranularity(static_cast<ETextGranularity>(WebSelectByCharacter));
1586     _part->setXPosForVerticalArrowNavigation(xPos);
1587
1588     _part->selectFrameElementInParentIfFullySelected();
1589
1590     [self ensureSelectionVisible];
1591 }
1592
1593 - (WebSelectionGranularity)selectionGranularity
1594 {
1595     // NOTE: The enums *must* match the very similar ones declared in dom_selection.h
1596     return static_cast<WebSelectionGranularity>(_part->selectionGranularity());
1597 }
1598
1599 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity closeTyping:(BOOL)closeTyping
1600 {
1601     NodeImpl *startContainer = [[range startContainer] _nodeImpl];
1602     NodeImpl *endContainer = [[range endContainer] _nodeImpl];
1603     ASSERT(startContainer);
1604     ASSERT(endContainer);
1605     ASSERT(startContainer->getDocument());
1606     ASSERT(startContainer->getDocument() == endContainer->getDocument());
1607     
1608     _part->xmlDocImpl()->updateLayout();
1609
1610     EAffinity affinity = static_cast<EAffinity>(selectionAffinity);
1611
1612     bool rangeCollapsed = [range collapsed];
1613     if (!rangeCollapsed)
1614         affinity = DOWNSTREAM;
1615     
1616     // Work around bug where isRenderedContent returns false for <br> elements at the ends of lines.
1617     // If that bug wasn't an issue, we could just make the position from the range directly.
1618     Position start(startContainer, [range startOffset]);
1619     Position end(endContainer, [range endOffset]);
1620     VisiblePosition visibleStart(start, affinity);
1621     start = visibleStart.deepEquivalent();
1622
1623     if (rangeCollapsed) {
1624         setAffinityUsingLinePosition(visibleStart);
1625         affinity = visibleStart.affinity();
1626     }
1627
1628     // FIXME: Can we provide extentAffinity?
1629     Selection selection(start, affinity, end, khtml::SEL_DEFAULT_AFFINITY);
1630     _part->setSelection(selection, closeTyping);
1631 }
1632
1633 - (DOMRange *)selectedDOMRange
1634 {
1635     return [DOMRange _rangeWithImpl:_part->selection().toRange().get()];
1636 }
1637
1638 - (NSRange)convertToNSRange:(DOM::RangeImpl *)range
1639 {
1640     if (!range || range->isDetached()) {
1641         return NSMakeRange(NSNotFound, 0);
1642     }
1643
1644     SharedPtr<RangeImpl> fromStartRange(_part->xmlDocImpl()->createRange());
1645     int exception = 0;
1646
1647     fromStartRange->setEnd(range->startContainer(exception), range->startOffset(exception), exception);
1648     long startPosition = TextIterator::rangeLength(fromStartRange.get());
1649
1650     fromStartRange->setEnd(range->endContainer(exception), range->endOffset(exception), exception);
1651     long endPosition = TextIterator::rangeLength(fromStartRange.get());
1652
1653     return NSMakeRange(startPosition, endPosition - startPosition);
1654 }
1655
1656 - (RangeImpl *)convertToDOMRange:(NSRange)nsrange
1657 {
1658     return TextIterator::rangeFromLocationAndLength(_part->xmlDocImpl(), nsrange.location, nsrange.length);
1659 }
1660
1661 - (DOMRange *)convertToObjCDOMRange:(NSRange)nsrange
1662 {
1663     return [DOMRange _rangeWithImpl:[self convertToDOMRange:nsrange]];
1664 }
1665
1666 - (void)selectNSRange:(NSRange)range
1667 {
1668     _part->setSelection(Selection([self convertToDOMRange:range], khtml::SEL_DEFAULT_AFFINITY, khtml::SEL_DEFAULT_AFFINITY));
1669 }
1670
1671 - (NSRange)selectedNSRange
1672 {
1673     return [self convertToNSRange:_part->selection().toRange().get()];
1674 }
1675
1676 - (NSSelectionAffinity)selectionAffinity
1677 {
1678     return static_cast<NSSelectionAffinity>(_part->selection().startAffinity());
1679 }
1680
1681 - (void)setMarkDOMRange:(DOMRange *)range
1682 {
1683     _part->setMark(Selection([range _rangeImpl], khtml::SEL_DEFAULT_AFFINITY, khtml::SEL_DEFAULT_AFFINITY));
1684 }
1685
1686 - (DOMRange *)markDOMRange
1687 {
1688     return [DOMRange _rangeWithImpl:_part->mark().toRange().get()];
1689 }
1690
1691 - (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges
1692 {
1693     _part->setMarkedTextRange([range _rangeImpl], attributes, ranges);
1694 }
1695
1696 - (DOMRange *)markedTextDOMRange
1697 {
1698     return [DOMRange _rangeWithImpl:_part->markedTextRange()];
1699 }
1700
1701 - (NSRange)markedTextNSRange
1702 {
1703     return [self convertToNSRange:_part->markedTextRange()];
1704 }
1705
1706 - (void)replaceMarkedTextWithText:(NSString *)text
1707 {
1708     if (!partHasSelection(self))
1709         return;
1710     
1711     int exception = 0;
1712
1713     RangeImpl *markedTextRange = _part->markedTextRange();
1714     if (markedTextRange && !markedTextRange->collapsed(exception))
1715         TypingCommand::deleteKeyPressed(_part->xmlDocImpl(), NO);
1716     
1717     if ([text length] > 0)
1718         TypingCommand::insertText(_part->xmlDocImpl(), text, YES);
1719     
1720     [self ensureSelectionVisible];
1721 }
1722
1723 - (BOOL)canDeleteRange:(DOMRange *)range
1724 {
1725     NodeImpl *startContainer = [[range startContainer] _nodeImpl];
1726     NodeImpl *endContainer = [[range endContainer] _nodeImpl];
1727     if (startContainer == nil || endContainer == nil)
1728         return NO;
1729     
1730     if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
1731         return NO;
1732     
1733     if ([range collapsed]) {
1734         VisiblePosition start(startContainer, [range startOffset], DOWNSTREAM);
1735         if (isStartOfEditableContent(start))
1736             return NO;
1737     }
1738     
1739     return YES;
1740 }
1741
1742 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
1743 // be deleted along with the proposed range in order to preserve proper spacing and punctuation of
1744 // the text surrounding the deletion.
1745 - (DOMRange *)smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
1746 {
1747     NodeImpl *startContainer = [[proposedRange startContainer] _nodeImpl];
1748     NodeImpl *endContainer = [[proposedRange endContainer] _nodeImpl];
1749     if (startContainer == nil || endContainer == nil)
1750         return nil;
1751
1752     ASSERT(startContainer->getDocument());
1753     ASSERT(startContainer->getDocument() == endContainer->getDocument());
1754     
1755     _part->xmlDocImpl()->updateLayout();
1756
1757     Position start(startContainer, [proposedRange startOffset]);
1758     Position end(endContainer, [proposedRange endOffset]);
1759     Position newStart = start.upstream().leadingWhitespacePosition(khtml::DOWNSTREAM, true);
1760     if (newStart.isNull())
1761         newStart = start;
1762     Position newEnd = end.downstream().trailingWhitespacePosition(khtml::DOWNSTREAM, true);
1763     if (newEnd.isNull())
1764         newEnd = end;
1765
1766     RangeImpl *range = _part->xmlDocImpl()->createRange();
1767     int exception = 0;
1768     range->setStart(newStart.node(), newStart.offset(), exception);
1769     range->setEnd(newStart.node(), newStart.offset(), exception);
1770     return [DOMRange _rangeWithImpl:range];
1771 }
1772
1773 // Determines whether whitespace needs to be added around aString to preserve proper spacing and
1774 // punctuation when itÕs inserted into the receiverÕs text over charRange. Returns by reference
1775 // in beforeString and afterString any whitespace that should be added, unless either or both are
1776 // nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
1777 - (void)smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1778 {
1779     // give back nil pointers in case of early returns
1780     if (beforeString)
1781         *beforeString = nil;
1782     if (afterString)
1783         *afterString = nil;
1784         
1785     // inspect destination
1786     NodeImpl *startContainer = [[rangeToReplace startContainer] _nodeImpl];
1787     NodeImpl *endContainer = [[rangeToReplace endContainer] _nodeImpl];
1788
1789     Position startPos(startContainer, [rangeToReplace startOffset]);
1790     Position endPos(endContainer, [rangeToReplace endOffset]);
1791
1792     VisiblePosition startVisiblePos = VisiblePosition(startPos, khtml::VP_DEFAULT_AFFINITY);
1793     VisiblePosition endVisiblePos = VisiblePosition(endPos, khtml::VP_DEFAULT_AFFINITY);
1794     
1795     // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
1796     if (startVisiblePos.isNull() || endVisiblePos.isNull())
1797         return;
1798
1799     bool addLeadingSpace = startPos.leadingWhitespacePosition(khtml::VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
1800     if (addLeadingSpace) {
1801         QChar previousChar = startVisiblePos.previous().character();
1802         if (!previousChar.isNull()) {
1803             addLeadingSpace = !_part->isCharacterSmartReplaceExempt(previousChar, true);
1804         }
1805     }
1806     
1807     bool addTrailingSpace = endPos.trailingWhitespacePosition(khtml::VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
1808     if (addTrailingSpace) {
1809         QChar thisChar = endVisiblePos.character();
1810         if (!thisChar.isNull()) {
1811             addTrailingSpace = !_part->isCharacterSmartReplaceExempt(thisChar, false);
1812         }
1813     }
1814     
1815     // inspect source
1816     bool hasWhitespaceAtStart = false;
1817     bool hasWhitespaceAtEnd = false;
1818     unsigned pasteLength = [pasteString length];
1819     if (pasteLength > 0) {
1820         NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
1821         
1822         if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
1823             hasWhitespaceAtStart = YES;
1824         }
1825         if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
1826             hasWhitespaceAtEnd = YES;
1827         }
1828     }
1829     
1830     // issue the verdict
1831     if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
1832         *beforeString = @" ";
1833     if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
1834         *afterString = @" ";
1835 }
1836
1837 - (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString 
1838 {
1839     if (!_part || !_part->xmlDocImpl())
1840         return 0;
1841
1842     DocumentFragmentImpl *fragment = createFragmentFromMarkup(_part->xmlDocImpl(), QString::fromNSString(markupString), QString::fromNSString(baseURLString));
1843     return [DOMDocumentFragment _documentFragmentWithImpl:fragment];
1844 }
1845
1846 - (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text
1847 {
1848     if (!partHasSelection(self) || !text)
1849         return 0;
1850     
1851     return [DOMDocumentFragment _documentFragmentWithImpl:createFragmentFromText(_part->xmlDocImpl(), QString::fromNSString(text))];
1852 }
1853
1854 - (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1855 {
1856     if (!partHasSelection(self) || !fragment)
1857         return;
1858     
1859     EditCommandPtr(new ReplaceSelectionCommand(_part->xmlDocImpl(), [fragment _fragmentImpl], selectReplacement, smartReplace, matchStyle)).apply();
1860     [self ensureSelectionVisible];
1861 }
1862
1863 - (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1864 {
1865     DOMDocumentFragment *fragment = [[self DOMDocument] createDocumentFragment];
1866     [fragment appendChild:node];
1867     [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1868 }
1869
1870 - (void)replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1871 {
1872     DOMDocumentFragment *fragment = [self documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
1873     [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1874 }
1875
1876 - (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1877 {
1878     [self replaceSelectionWithFragment:[self documentFragmentWithText:text] selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
1879 }
1880
1881 - (void)insertLineBreak
1882 {
1883     if (!partHasSelection(self))
1884         return;
1885     
1886     TypingCommand::insertLineBreak(_part->xmlDocImpl());
1887     [self ensureSelectionVisible];
1888 }
1889
1890 - (void)insertParagraphSeparator
1891 {
1892     if (!partHasSelection(self))
1893         return;
1894     
1895     TypingCommand::insertParagraphSeparator(_part->xmlDocImpl());
1896     [self ensureSelectionVisible];
1897 }
1898
1899 - (void)insertParagraphSeparatorInQuotedContent
1900 {
1901     if (!partHasSelection(self))
1902         return;
1903     
1904     TypingCommand::insertParagraphSeparatorInQuotedContent(_part->xmlDocImpl());
1905     [self ensureSelectionVisible];
1906 }
1907
1908 - (void)insertText:(NSString *)text selectInsertedText:(BOOL)selectInsertedText
1909 {
1910     if (!partHasSelection(self))
1911         return;
1912     
1913     TypingCommand::insertText(_part->xmlDocImpl(), text, selectInsertedText);
1914     [self ensureSelectionVisible];
1915 }
1916
1917 - (void)setSelectionToDragCaret
1918 {
1919     _part->setSelection(_part->dragCaret());
1920 }
1921
1922 - (void)moveSelectionToDragCaret:(DOMDocumentFragment *)selectionFragment smartMove:(BOOL)smartMove
1923 {
1924     Position base = _part->dragCaret().base();
1925     EditCommandPtr(new MoveSelectionCommand(_part->xmlDocImpl(), [selectionFragment _fragmentImpl], base, smartMove)).apply();
1926 }
1927
1928 - (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
1929 {
1930     RenderObject *renderer = _part->renderer();
1931     if (!renderer) {
1932         return VisiblePosition();
1933     }
1934     
1935     RenderObject::NodeInfo nodeInfo(true, true);
1936     renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
1937     NodeImpl *node = nodeInfo.innerNode();
1938     if (!node->renderer())
1939         return VisiblePosition();
1940     
1941     return node->renderer()->positionForCoordinates((int)point.x, (int)point.y);
1942 }
1943
1944 - (void)moveDragCaretToPoint:(NSPoint)point
1945 {   
1946     Selection dragCaret([self _visiblePositionForPoint:point]);
1947     _part->setDragCaret(dragCaret);
1948 }
1949
1950 - (void)removeDragCaret
1951 {
1952     _part->setDragCaret(Selection());
1953 }
1954
1955 - (DOMRange *)dragCaretDOMRange
1956 {
1957     return [DOMRange _rangeWithImpl:_part->dragCaret().toRange().get()];
1958 }
1959
1960 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
1961 {
1962     VisiblePosition position = [self _visiblePositionForPoint:point];
1963     return position.isNull() ? nil : [DOMRange _rangeWithImpl:Selection(position).toRange().get()];
1964 }
1965
1966 - (void)deleteSelectionWithSmartDelete:(BOOL)smartDelete
1967 {
1968     if (!partHasSelection(self))
1969         return;
1970     
1971     EditCommandPtr(new DeleteSelectionCommand(_part->xmlDocImpl(), smartDelete)).apply();
1972 }
1973
1974 - (void)deleteKeyPressedWithSmartDelete:(BOOL)smartDelete
1975 {
1976     if (!_part || !_part->xmlDocImpl())
1977         return;
1978     
1979     TypingCommand::deleteKeyPressed(_part->xmlDocImpl(), smartDelete);
1980     [self ensureSelectionVisible];
1981 }
1982
1983 - (void)forwardDeleteKeyPressedWithSmartDelete:(BOOL)smartDelete
1984 {
1985     if (!_part || !_part->xmlDocImpl())
1986         return;
1987     
1988     TypingCommand::forwardDeleteKeyPressed(_part->xmlDocImpl(), smartDelete);
1989     [self ensureSelectionVisible];
1990 }
1991
1992 - (DOMCSSStyleDeclaration *)typingStyle
1993 {
1994     if (!_part || !_part->typingStyle())
1995         return nil;
1996     return [DOMCSSStyleDeclaration _styleDeclarationWithImpl:_part->typingStyle()];
1997 }
1998
1999 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
2000 {
2001     if (!_part)
2002         return;
2003     _part->computeAndSetTypingStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
2004 }
2005
2006 - (void)applyStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
2007 {
2008     if (!_part)
2009         return;
2010     _part->applyStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
2011 }
2012
2013 - (void)applyParagraphStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
2014 {
2015     if (!_part)
2016         return;
2017     _part->applyParagraphStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
2018 }
2019
2020 - (BOOL)selectionStartHasStyle:(DOMCSSStyleDeclaration *)style
2021 {
2022     if (!_part)
2023         return NO;
2024     return _part->selectionStartHasStyle([style _styleDeclarationImpl]);
2025 }
2026
2027 - (NSCellStateValue)selectionHasStyle:(DOMCSSStyleDeclaration *)style
2028 {
2029     if (!_part)
2030         return NSOffState;
2031     switch (_part->selectionHasStyle([style _styleDeclarationImpl])) {
2032         case KHTMLPart::falseTriState:
2033             return NSOffState;
2034         case KHTMLPart::trueTriState:
2035             return NSOnState;
2036         case KHTMLPart::mixedTriState:
2037             return NSMixedState;
2038     }
2039     return NSOffState;
2040 }
2041
2042 - (void)applyEditingStyleToBodyElement
2043 {
2044     if (!_part)
2045         return;
2046     _part->applyEditingStyleToBodyElement();
2047 }
2048
2049 - (void)removeEditingStyleFromBodyElement
2050 {
2051     if (!_part)
2052         return;
2053     _part->removeEditingStyleFromBodyElement();
2054 }
2055
2056 - (void)applyEditingStyleToElement:(DOMElement *)element
2057 {
2058     if (!_part)
2059         return;
2060     _part->applyEditingStyleToElement([element _elementImpl]);
2061 }
2062
2063 - (void)removeEditingStyleFromElement:(DOMElement *)element
2064 {
2065     if (!_part)
2066         return;
2067     _part->removeEditingStyleFromElement([element _elementImpl]);
2068 }
2069
2070 - (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts
2071 {
2072     bool multipleFonts = false;
2073     NSFont *font = nil;
2074     if (_part)
2075         font = _part->fontForSelection(hasMultipleFonts ? &multipleFonts : 0);
2076     if (hasMultipleFonts)
2077         *hasMultipleFonts = multipleFonts;
2078     return font;
2079 }
2080
2081 - (NSDictionary *)fontAttributesForSelectionStart
2082 {
2083     return _part ? _part->fontAttributesForSelectionStart() : nil;
2084 }
2085
2086 - (NSWritingDirection)baseWritingDirectionForSelectionStart
2087 {
2088     return _part ? _part->baseWritingDirectionForSelectionStart() : NSWritingDirectionLeftToRight;
2089 }
2090
2091 - (void)ensureSelectionVisible
2092 {
2093     if (!partHasSelection(self))
2094         return;
2095     
2096     KHTMLView *v = _part->view();
2097     if (!v)
2098         return;
2099
2100     Position extent = _part->selection().extent();
2101     if (extent.isNull())
2102         return;
2103     
2104     RenderObject *renderer = extent.node()->renderer();
2105     if (!renderer)
2106         return;
2107     
2108     NSView *documentView = v->getDocumentView();
2109     if (!documentView)
2110         return;
2111     
2112     QRect extentRect = renderer->caretRect(extent.offset(), _part->selection().extentAffinity());
2113     if (!NSContainsRect([documentView visibleRect], NSRect(extentRect))) {
2114         v->ensureRectVisibleCentered(extentRect, true);
2115     }
2116 }
2117
2118 // [info draggingLocation] is in window coords
2119
2120 - (BOOL)eventMayStartDrag:(NSEvent *)event
2121 {
2122     return _part ? _part->eventMayStartDrag(event) : NO;
2123 }
2124
2125 - (NSDragOperation)dragOperationForDraggingInfo:(id <NSDraggingInfo>)info
2126 {
2127     NSDragOperation op = NSDragOperationNone;
2128     if (_part) {
2129         KHTMLView *v = _part->view();
2130         if (v) {
2131             // Sending an event can result in the destruction of the view and part.
2132             v->ref();
2133             
2134             KWQClipboard::AccessPolicy policy = _part->baseURL().isLocalFile() ? KWQClipboard::Readable : KWQClipboard::TypesReadable;
2135             KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], policy);
2136             clipboard->ref();
2137             NSDragOperation srcOp = [info draggingSourceOperationMask];
2138             clipboard->setSourceOperation(srcOp);
2139
2140             if (v->updateDragAndDrop(QPoint([info draggingLocation]), clipboard)) {
2141                 // *op unchanged if no source op was set
2142                 if (!clipboard->destinationOperation(&op)) {
2143                     // The element accepted but they didn't pick an operation, so we pick one for them
2144                     // (as does WinIE).
2145                     if (srcOp & NSDragOperationCopy) {
2146                         op = NSDragOperationCopy;
2147                     } else if (srcOp & NSDragOperationMove || srcOp & NSDragOperationGeneric) {
2148                         op = NSDragOperationMove;
2149                     } else if (srcOp & NSDragOperationLink) {
2150                         op = NSDragOperationLink;
2151                     } else {
2152                         op = NSDragOperationGeneric;
2153                     }
2154                 } else if (!(op & srcOp)) {
2155                     // make sure WC picked an op that was offered.  Cocoa doesn't seem to enforce this,
2156                     // but IE does.
2157                     op = NSDragOperationNone;
2158                 }
2159             }
2160             clipboard->setAccessPolicy(KWQClipboard::Numb);    // invalidate clipboard here for security
2161
2162             clipboard->deref();
2163             v->deref();
2164             return op;
2165         }
2166     }
2167     return op;
2168 }
2169
2170 - (void)dragExitedWithDraggingInfo:(id <NSDraggingInfo>)info
2171 {
2172     if (_part) {
2173         KHTMLView *v = _part->view();
2174         if (v) {
2175             // Sending an event can result in the destruction of the view and part.
2176             v->ref();
2177
2178             KWQClipboard::AccessPolicy policy = _part->baseURL().isLocalFile() ? KWQClipboard::Readable : KWQClipboard::TypesReadable;
2179             KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], policy);
2180             clipboard->ref();
2181             clipboard->setSourceOperation([info draggingSourceOperationMask]);
2182             
2183             v->cancelDragAndDrop(QPoint([info draggingLocation]), clipboard);
2184             clipboard->setAccessPolicy(KWQClipboard::Numb);    // invalidate clipboard here for security
2185
2186             clipboard->deref();
2187             v->deref();
2188         }
2189     }
2190 }
2191
2192 - (BOOL)concludeDragForDraggingInfo:(id <NSDraggingInfo>)info
2193 {
2194     if (_part) {
2195         KHTMLView *v = _part->view();
2196         if (v) {
2197             // Sending an event can result in the destruction of the view and part.
2198             v->ref();
2199
2200             KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], KWQClipboard::Readable);
2201             clipboard->ref();
2202             clipboard->setSourceOperation([info draggingSourceOperationMask]);
2203
2204             BOOL result = v->performDragAndDrop(QPoint([info draggingLocation]), clipboard);
2205             clipboard->setAccessPolicy(KWQClipboard::Numb);    // invalidate clipboard here for security
2206
2207             clipboard->deref();
2208             v->deref();
2209
2210             return result;
2211         }
2212     }
2213     return NO;
2214 }
2215
2216 - (void)dragSourceMovedTo:(NSPoint)windowLoc
2217 {
2218     if (_part) {
2219         _part->dragSourceMovedTo(QPoint(windowLoc));
2220     }
2221 }
2222
2223 - (void)dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
2224 {
2225     if (_part) {
2226         _part->dragSourceEndedAt(QPoint(windowLoc), operation);
2227     }
2228 }
2229
2230 - (BOOL)mayDHTMLCut
2231 {
2232     return _part->mayCut();
2233 }
2234
2235 - (BOOL)mayDHTMLCopy
2236 {
2237     return _part->mayCopy();
2238 }
2239
2240 - (BOOL)mayDHTMLPaste
2241 {
2242     return _part->mayPaste();
2243 }
2244
2245 - (BOOL)tryDHTMLCut
2246 {
2247     return _part->tryCut();
2248 }
2249
2250 - (BOOL)tryDHTMLCopy
2251 {
2252     return _part->tryCopy();
2253 }
2254
2255 - (BOOL)tryDHTMLPaste
2256 {
2257     return _part->tryPaste();
2258 }
2259
2260 - (DOMRange *)rangeOfCharactersAroundCaret
2261 {
2262     if (!_part)
2263         return nil;
2264         
2265     Selection selection(_part->selection());
2266     if (!selection.isCaret())
2267         return nil;
2268
2269     VisiblePosition caret(selection.start(), selection.startAffinity());
2270     VisiblePosition next = caret.next();
2271     VisiblePosition previous = caret.previous();
2272     if (previous.isNull() || next.isNull() || caret == next || caret == previous)
2273         return nil;
2274
2275     return [DOMRange _rangeWithImpl:makeRange(previous, next).get()];
2276 }
2277
2278 - (NSMutableDictionary *)dashboardRegions
2279 {
2280     return _part->dashboardRegionsDictionary();
2281 }
2282
2283 @end
2284
2285 @implementation WebCoreBridge (WebCoreBridgeInternal)
2286
2287 - (RootObject *)executionContextForView:(NSView *)aView
2288 {
2289     KWQKHTMLPart *part = [self part];
2290     RootObject *root = new RootObject(aView);    // The root gets deleted by JavaScriptCore.
2291     root->setRootObjectImp(static_cast<ObjectImp *>(Window::retrieveWindow(part)));
2292     root->setInterpreter(KJSProxy::proxy(part)->interpreter());
2293     part->addPluginRootObject(root);
2294     return root;
2295 }
2296
2297 @end