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