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