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