2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #import "WebCoreBridge.h"
28 #include <CoreFoundation/CFCharacterSetPriv.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"
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"
43 #import "htmlediting.h"
45 #import "khtml_part.h"
48 #import "kjs_window.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"
58 #import "visible_position.h"
59 #import "visible_units.h"
60 #import "xml_tokenizer.h"
62 #import <JavaScriptCore/npruntime.h>
63 #import <JavaScriptCore/jni_jsobject.h>
64 #import <JavaScriptCore/object.h>
65 #import <JavaScriptCore/runtime_root.h>
66 #import <JavaScriptCore/property_map.h>
68 #import "KWQAssertions.h"
69 #import "KWQCharsets.h"
70 #import "KWQClipboard.h"
71 #import "KWQDOMNode.h"
72 #import "KWQEditCommand.h"
74 #import "KWQFoundationExtras.h"
76 #import "KWQKHTMLPart.h"
78 #import "KWQPageState.h"
79 #import "KWQRenderTreeDebug.h"
81 #import "KWQPrinter.h"
82 #import "KWQAccObjectCache.h"
84 #import "DOMInternal.h"
85 #import "WebCoreImageRenderer.h"
86 #import "WebCoreTextRendererFactory.h"
87 #import "WebCoreViewFactory.h"
88 #import "WebCoreSettings.h"
92 using DOM::AtomicString;
93 using DOM::CSSStyleDeclarationImpl;
94 using DOM::DocumentFragmentImpl;
95 using DOM::DocumentImpl;
96 using DOM::DocumentTypeImpl;
99 using DOM::ElementImpl;
100 using DOM::HTMLElementImpl;
101 using DOM::HTMLFormElementImpl;
102 using DOM::HTMLGenericFormElementImpl;
103 using DOM::HTMLImageElementImpl;
104 using DOM::HTMLInputElementImpl;
110 using khtml::ChildrenOnly;
111 using khtml::createMarkup;
112 using khtml::Decoder;
113 using khtml::DeleteSelectionCommand;
114 using khtml::DOWNSTREAM;
115 using khtml::EAffinity;
116 using khtml::EditAction;
117 using khtml::EditCommandPtr;
118 using khtml::ETextGranularity;
119 using khtml::IncludeNode;
120 using khtml::MoveSelectionCommand;
121 using khtml::parseURL;
122 using khtml::RenderCanvas;
123 using khtml::RenderImage;
124 using khtml::RenderObject;
125 using khtml::RenderPart;
126 using khtml::RenderStyle;
127 using khtml::RenderWidget;
128 using khtml::ReplaceSelectionCommand;
129 using khtml::Selection;
130 using khtml::setAffinityUsingLinePosition;
131 using khtml::Tokenizer;
132 using khtml::TypingCommand;
133 using khtml::UPSTREAM;
134 using khtml::VisiblePosition;
136 using KJS::ExecState;
137 using KJS::ObjectImp;
138 using KJS::SavedProperties;
139 using KJS::SavedBuiltins;
142 using KParts::URLArgs;
144 using KJS::Bindings::RootObject;
146 NSString *WebCoreElementDOMNodeKey = @"WebElementDOMNode";
147 NSString *WebCoreElementFrameKey = @"WebElementFrame";
148 NSString *WebCoreElementImageAltStringKey = @"WebElementImageAltString";
149 NSString *WebCoreElementImageKey = @"WebElementImage";
150 NSString *WebCoreElementImageRectKey = @"WebElementImageRect";
151 NSString *WebCoreElementImageURLKey = @"WebElementImageURL";
152 NSString *WebCoreElementIsSelectedKey = @"WebElementIsSelected";
153 NSString *WebCoreElementLinkURLKey = @"WebElementLinkURL";
154 NSString *WebCoreElementLinkTargetFrameKey = @"WebElementTargetFrame";
155 NSString *WebCoreElementLinkLabelKey = @"WebElementLinkLabel";
156 NSString *WebCoreElementLinkTitleKey = @"WebElementLinkTitle";
157 NSString *WebCoreElementNameKey = @"WebElementName";
158 NSString *WebCoreElementTitleKey = @"WebCoreElementTitle"; // not in WebKit API for now, could be in API some day
160 NSString *WebCorePageCacheStateKey = @"WebCorePageCacheState";
162 @interface WebCoreBridge (WebCoreBridgeInternal)
163 - (RootObject *)executionContextForView:(NSView *)aView;
166 static RootObject *rootForView(void *v)
168 NSView *aView = (NSView *)v;
169 WebCoreBridge *aBridge = [[WebCoreViewFactory sharedFactory] bridgeForView:aView];
170 RootObject *root = 0;
173 root = [aBridge executionContextForView:aView];
178 static pthread_t mainThread = 0;
180 static void updateRenderingForBindings (ExecState *exec, ObjectImp *rootObject)
182 if (pthread_self() != mainThread)
188 Window *window = static_cast<Window*>(rootObject);
192 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(window->part()->document().handle());
194 doc->updateRendering();
197 static BOOL partHasSelection(WebCoreBridge *bridge)
202 KHTMLPart *part = bridge->_part;
206 if (part->selection().isNone())
209 // If a part has a selection, it should also have a document.
210 ASSERT(part->xmlDocImpl());
215 static BOOL hasCaseInsensitivePrefix(NSString *string, NSString *prefix)
217 return [string rangeOfString:prefix options:(NSCaseInsensitiveSearch | NSAnchoredSearch)].location !=
221 @implementation WebCoreBridge
223 static bool initializedObjectCacheSize = FALSE;
224 static bool initializedKJS = FALSE;
226 + (WebCoreBridge *)bridgeForDOMDocument:(DOMDocument *)document
228 return ((KWQKHTMLPart *)[document _documentImpl]->part())->bridge();
235 _part = new KWQKHTMLPart;
236 _part->setBridge(self);
238 if (!initializedObjectCacheSize){
239 khtml::Cache::setSize([self getObjectCacheSize]);
240 initializedObjectCacheSize = TRUE;
243 if (!initializedKJS) {
244 mainThread = pthread_self();
246 RootObject::setFindRootObjectForNativeHandleFunction (rootForView);
248 KJS::Bindings::Instance::setDidExecuteFunction(updateRenderingForBindings);
250 initializedKJS = TRUE;
253 _shouldCreateRenderers = YES;
258 - (void)initializeSettings: (WebCoreSettings *)settings
260 _part->setSettings ([settings settings]);
265 [self removeFromFrame];
268 _renderPart->deref(_renderPartArena);
270 _part->setBridge(nil);
278 // FIXME: This work really should not be done at deallocation time.
279 // We need to do it at some well-defined time instead.
281 [self removeFromFrame];
284 _renderPart->deref(_renderPartArena);
286 _part->setBridge(nil);
292 - (KWQKHTMLPart *)part
297 - (void)setRenderPart:(KHTMLRenderPart *)newPart;
299 RenderArena *arena = newPart->ref();
301 _renderPart->deref(_renderPartArena);
303 _renderPart = newPart;
304 _renderPartArena = arena;
307 - (KHTMLRenderPart *)renderPart
312 - (void)setParent:(WebCoreBridge *)parent
314 _part->setParent([parent part]);
317 - (void)provisionalLoadStarted
319 _part->provisionalLoadStarted();
322 - (void)openURL:(NSURL *)URL reload:(BOOL)reload contentType:(NSString *)contentType refresh:(NSString *)refresh lastModified:(NSDate *)lastModified pageCache:(NSDictionary *)pageCache
325 KWQPageState *state = [pageCache objectForKey:WebCorePageCacheStateKey];
326 _part->openURLFromPageCache(state);
332 URLArgs args(_part->browserExtension()->urlArgs());
333 args.reload = reload;
335 args.serviceType = QString::fromNSString(contentType);
337 _part->browserExtension()->setURLArgs(args);
340 if (_part->didOpenURL(URL)) {
341 // things we have to set up after calling didOpenURL
343 _part->addMetaData("http-refresh", QString::fromNSString(refresh));
346 NSString *modifiedString = [lastModified descriptionWithCalendarFormat:@"%a %b %d %Y %H:%M:%S" timeZone:nil locale:nil];
347 _part->addMetaData("modified", QString::fromNSString(modifiedString));
352 - (void)setEncoding:(NSString *)encoding userChosen:(BOOL)userChosen
354 _part->setEncoding(QString::fromNSString(encoding), userChosen);
357 - (void)addData:(NSData *)data
359 DocumentImpl *doc = _part->xmlDocImpl();
361 // Document may be nil if the part is about to redirect
362 // as a result of JS executing during load, i.e. one frame
363 // changing another's location before the frame's document
366 doc->setShouldCreateRenderers([self shouldCreateRenderers]);
367 _part->addData((const char *)[data bytes], [data length]);
376 - (void)didNotOpenURL:(NSURL *)URL pageCache:(NSDictionary *)pageCache
378 _part->didNotOpenURL(KURL(URL).url());
380 // We might have made a page cache item, but now we're bailing out due to an error before we ever
381 // transitioned to the new page (before WebFrameState==commit). The goal here is to restore any state
382 // so that the existing view (that wenever got far enough to replace) can continue being used.
383 DocumentImpl *doc = _part->xmlDocImpl();
385 doc->setInPageCache(NO);
387 KWQPageState *state = [pageCache objectForKey:WebCorePageCacheStateKey];
391 - (BOOL)canLoadURL:(NSURL *)URL fromReferrer:(NSString *)referrer hideReferrer:(BOOL *)hideReferrer
393 BOOL referrerIsWebURL = hasCaseInsensitivePrefix(referrer, @"http:") || hasCaseInsensitivePrefix(referrer, @"https:");
394 BOOL referrerIsLocalURL = hasCaseInsensitivePrefix(referrer, @"file:") || hasCaseInsensitivePrefix(referrer, @"applewebdata:");
395 BOOL URLIsFileURL = [URL scheme] != NULL && [[URL scheme] compare:@"file" options:(NSCaseInsensitiveSearch|NSLiteralSearch)] == NSOrderedSame;
397 *hideReferrer = !referrerIsWebURL;
398 return !URLIsFileURL || referrerIsLocalURL;
401 - (void)saveDocumentState
403 DocumentImpl *doc = _part->xmlDocImpl();
405 QStringList list = doc->docState();
406 NSMutableArray *documentState = [[[NSMutableArray alloc] init] autorelease];
408 for (uint i = 0; i < list.count(); i++){
410 [documentState addObject: [NSString stringWithCharacters: (const unichar *)s.unicode() length: s.length()]];
412 [self saveDocumentState: documentState];
416 - (void)restoreDocumentState
418 DocumentImpl *doc = _part->xmlDocImpl();
421 NSArray *documentState = [self documentState];
424 for (uint i = 0; i < [documentState count]; i++){
425 NSString *string = [documentState objectAtIndex: i];
426 s.append(QString::fromNSString(string));
429 doc->setRestoreState(s);
433 - (void)scrollToAnchorWithURL:(NSURL *)URL
435 _part->scrollToAnchor(KURL(URL).url().latin1());
438 - (BOOL)scrollOverflowInDirection:(WebScrollDirection)direction granularity:(WebScrollGranularity)granularity
443 return _part->scrollOverflow((KWQScrollDirection)direction, (KWQScrollGranularity)granularity);
446 - (BOOL)scrollOverflowWithScrollWheelEvent:(NSEvent *)event
451 return _part->scrollOverflowWithScrollWheelEvent(event);
454 - (BOOL)saveDocumentToPageCache
456 DocumentImpl *doc = _part->xmlDocImpl();
464 _part->clearTimers();
466 SavedProperties *windowProperties = new SavedProperties;
467 _part->saveWindowProperties(windowProperties);
469 SavedProperties *locationProperties = new SavedProperties;
470 _part->saveLocationProperties(locationProperties);
472 SavedBuiltins *interpreterBuiltins = new SavedBuiltins;
473 _part->saveInterpreterBuiltins(*interpreterBuiltins);
475 KWQPageState *pageState = [[[KWQPageState alloc] initWithDocument:doc
477 windowProperties:windowProperties
478 locationProperties:locationProperties
479 interpreterBuiltins:interpreterBuiltins] autorelease];
480 [pageState setPausedActions: _part->pauseActions((const void *)pageState)];
482 return [self saveDocumentToPageCache:pageState];
487 return _part->canCachePage();
505 - (void)createKHTMLViewWithNSView:(NSView *)view marginWidth:(int)mw marginHeight:(int)mh
507 // If we own the view, delete the old one - otherwise the render _part will take care of deleting the view.
508 [self removeFromFrame];
510 KHTMLView *kview = new KHTMLView(_part, 0);
511 _part->setView(kview);
514 kview->setView(view);
516 kview->setMarginWidth(mw);
518 kview->setMarginHeight(mh);
521 - (void)scrollToAnchor:(NSString *)a
523 _part->gotoAnchor(QString::fromNSString(a));
526 - (BOOL)isSelectionEditable
528 // EDIT FIXME: This needs to consider the entire selected range
529 NodeImpl *startNode = _part->selection().start().node();
530 return startNode ? startNode->isContentEditable() : NO;
533 - (WebSelectionState)selectionState
535 switch (_part->selection().state()) {
536 case Selection::NONE:
537 return WebSelectionStateNone;
538 case Selection::CARET:
539 return WebSelectionStateCaret;
540 case Selection::RANGE:
541 return WebSelectionStateRange;
544 ASSERT_NOT_REACHED();
545 return WebSelectionStateNone;
548 - (NSString *)_documentTypeString
550 NSString *documentTypeString = nil;
551 DOM::DocumentImpl *doc = _part->xmlDocImpl();
553 DocumentTypeImpl *doctype = doc->doctype();
555 documentTypeString = doctype->toString().string().getNSString();
558 return documentTypeString;
561 - (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString
563 NSString *documentTypeString = [self _documentTypeString];
564 if (documentTypeString && markupString) {
565 return [NSString stringWithFormat:@"%@%@", documentTypeString, markupString];
566 } else if (documentTypeString) {
567 return documentTypeString;
568 } else if (markupString) {
575 - (NSArray *)nodesFromList:(QPtrList<NodeImpl> *)nodeList
577 NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:nodeList->count()];
578 for (QPtrListIterator<NodeImpl> i(*nodeList); i.current(); ++i) {
579 [nodes addObject:[DOMNode _nodeWithImpl:i.current()]];
584 - (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes
586 // FIXME: This is never "for interchange". Is that right? See the next method.
587 QPtrList<NodeImpl> nodeList;
588 NSString *markupString = createMarkup([node _nodeImpl], IncludeNode, nodes ? &nodeList : 0).getNSString();
590 *nodes = [self nodesFromList:&nodeList];
592 return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
595 - (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
597 // FIXME: This is always "for interchange". Is that right? See the previous method.
598 QPtrList<NodeImpl> nodeList;
599 NSString *markupString = createMarkup([range _rangeImpl], nodes ? &nodeList : 0, AnnotateForInterchange).getNSString();
601 *nodes = [self nodesFromList:&nodeList];
603 return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
606 - (NSString *)selectedString
608 QString text = _part->selectedText();
609 text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
610 return [[text.getNSString() copy] autorelease];
613 - (NSString *)stringForRange:(DOMRange *)range
615 QString text = _part->text([range _rangeImpl]);
616 text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
617 return [[text.getNSString() copy] autorelease];
628 DocumentImpl *doc = _part->xmlDocImpl();
630 doc->setFocusNode(0);
636 _part->clearSelection();
641 return _part->isFrameSet();
644 - (void)reapplyStylesForDeviceType:(WebCoreDeviceType)deviceType
646 _part->setMediaType(deviceType == WebCoreDeviceScreen ? "screen" : "print");
647 DocumentImpl *doc = _part->xmlDocImpl();
649 static QPaintDevice screen;
650 static QPrinter printer;
651 doc->setPaintDevice(deviceType == WebCoreDeviceScreen ? &screen : &printer);
653 return _part->reparseConfiguration();
656 static BOOL nowPrinting(WebCoreBridge *self)
658 DocumentImpl *doc = self->_part->xmlDocImpl();
659 return doc && doc->paintDevice() && doc->paintDevice()->devType() == QInternal::Printer;
662 // Set or unset the printing mode in the view. We only toy with this if we're printing.
663 - (void)_setupRootForPrinting:(BOOL)onOrOff
665 if (nowPrinting(self)) {
666 RenderCanvas *root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
668 root->setPrintingMode(onOrOff);
673 - (void)forceLayoutAdjustingViewSize:(BOOL)flag
675 [self _setupRootForPrinting:YES];
676 _part->forceLayout();
678 [self adjustViewSize];
680 [self _setupRootForPrinting:NO];
683 - (void)forceLayoutWithMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)flag
685 [self _setupRootForPrinting:YES];
686 _part->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth);
688 [self adjustViewSize];
690 [self _setupRootForPrinting:NO];
693 - (void)sendResizeEvent
695 _part->sendResizeEvent();
698 - (void)sendScrollEvent
700 _part->sendScrollEvent();
703 - (void)drawRect:(NSRect)rect withPainter:(QPainter *)p
705 [self _setupRootForPrinting:YES];
706 _part->paint(p, QRect(rect));
707 [self _setupRootForPrinting:NO];
710 - (void)drawRect:(NSRect)rect
712 QPainter painter(nowPrinting(self));
713 bool displaysWithFocusAttributes = _part->displaysWithFocusAttributes();
714 painter.setUsesInactiveTextBackgroundColor(!displaysWithFocusAttributes);
715 painter.setDrawsFocusRing(displaysWithFocusAttributes);
716 [self drawRect:rect withPainter:&painter];
719 // Used by pagination code called from AppKit when a standalone web page is printed.
720 - (NSArray*)computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight
722 [self _setupRootForPrinting:YES];
723 NSMutableArray* pages = [NSMutableArray arrayWithCapacity:5];
724 if (printWidthScaleFactor <= 0) {
725 ERROR("printWidthScaleFactor has bad value %.2f", printWidthScaleFactor);
729 if (printHeight <= 0) {
730 ERROR("printHeight has bad value %.2f", printHeight);
734 if (!_part || !_part->xmlDocImpl() || !_part->view()) return pages;
735 RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
736 if (!root) return pages;
738 KHTMLView* view = _part->view();
739 NSView* documentView = view->getDocumentView();
743 float currPageHeight = printHeight;
744 float docHeight = root->layer()->height();
745 float docWidth = root->layer()->width();
746 float printWidth = docWidth/printWidthScaleFactor;
748 // We need to give the part the opportunity to adjust the page height at each step.
749 for (float i = 0; i < docHeight; i += currPageHeight) {
750 float proposedBottom = kMin(docHeight, i + printHeight);
751 _part->adjustPageHeight(&proposedBottom, i, proposedBottom, i);
752 currPageHeight = kMax(1.0f, proposedBottom - i);
753 for (float j = 0; j < docWidth; j += printWidth) {
754 NSValue* val = [NSValue valueWithRect: NSMakeRect(j, i, printWidth, currPageHeight)];
755 [pages addObject: val];
758 [self _setupRootForPrinting:NO];
763 // This is to support the case where a webview is embedded in the view that's being printed
764 - (void)adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit
766 [self _setupRootForPrinting:YES];
767 _part->adjustPageHeight(newBottom, oldTop, oldBottom, bottomLimit);
768 [self _setupRootForPrinting:NO];
771 - (NSObject *)copyDOMNode:(NodeImpl *)node copier:(id <WebCoreDOMTreeCopier>)copier
773 NSMutableArray *children = [[NSMutableArray alloc] init];
774 for (NodeImpl *child = node->firstChild(); child; child = child->nextSibling()) {
775 [children addObject:[self copyDOMNode:child copier:copier]];
777 NSObject *copiedNode = [copier nodeWithName:node->nodeName().string().getNSString()
778 value:node->nodeValue().string().getNSString()
779 source:createMarkup(node, ChildrenOnly).getNSString()
785 - (NSObject *)copyDOMTree:(id <WebCoreDOMTreeCopier>)copier
787 DocumentImpl *doc = _part->xmlDocImpl();
791 return [self copyDOMNode:doc copier:copier];
794 - (NSObject *)copyRenderNode:(RenderObject *)node copier:(id <WebCoreRenderTreeCopier>)copier
796 NSMutableArray *children = [[NSMutableArray alloc] init];
797 for (RenderObject *child = node->firstChild(); child; child = child->nextSibling()) {
798 [children addObject:[self copyRenderNode:child copier:copier]];
801 NSString *name = [[NSString alloc] initWithUTF8String:node->renderName()];
803 RenderPart *nodeRenderPart = dynamic_cast<RenderPart *>(node);
804 QWidget *widget = nodeRenderPart ? nodeRenderPart->widget() : 0;
805 NSView *view = widget ? widget->getView() : nil;
808 node->absolutePosition(nx,ny);
809 NSObject *copiedNode = [copier nodeWithName:name
810 position:NSMakePoint(nx,ny)
811 rect:NSMakeRect(node->xPos(), node->yPos(), node->width(), node->height())
821 - (NSObject *)copyRenderTree:(id <WebCoreRenderTreeCopier>)copier
823 RenderObject *renderer = _part->renderer();
827 return [self copyRenderNode:renderer copier:copier];
830 - (void)removeFromFrame
835 - (void)installInFrame:(NSView *)view
837 // If this isn't the main frame, it must have a render _part set, or it
838 // won't ever get installed in the view hierarchy.
839 ASSERT(self == [self mainFrame] || _renderPart != nil);
841 _part->view()->setView(view);
843 _renderPart->setWidget(_part->view());
844 // Now the render part owns the view, so we don't any more.
847 _part->view()->initScrollBars();
850 - (void)setActivationEventNumber:(int)num
852 _part->setActivationEventNumber(num);
855 - (void)mouseDown:(NSEvent *)event
857 _part->mouseDown(event);
860 - (void)mouseDragged:(NSEvent *)event
862 _part->mouseDragged(event);
865 - (void)mouseUp:(NSEvent *)event
867 _part->mouseUp(event);
870 - (void)mouseMoved:(NSEvent *)event
872 _part->mouseMoved(event);
875 - (BOOL)sendContextMenuEvent:(NSEvent *)event
877 return _part->sendContextMenuEvent(event);
880 - (DOMElement *)elementForView:(NSView *)view
882 // FIXME: implemented currently for only a subset of the KWQ widgets
883 if ([view conformsToProtocol:@protocol(KWQWidgetHolder)]) {
884 NSView <KWQWidgetHolder> *widgetHolder = view;
885 QWidget *widget = [widgetHolder widget];
887 NodeImpl *node = static_cast<const RenderWidget *>(widget->eventFilterObject())->element();
888 return [DOMElement _elementWithImpl:static_cast<ElementImpl *>(node)];
894 static NSView *viewForElement(ElementImpl *elementImpl)
896 RenderObject *renderer = elementImpl->renderer();
897 if (renderer && renderer->isWidget()) {
898 QWidget *widget = static_cast<const RenderWidget *>(renderer)->widget();
901 return widget->getView();
907 static HTMLInputElementImpl *inputElementFromDOMElement(DOMElement *element)
909 NodeImpl *node = [element _nodeImpl];
910 if (node && idFromNode(node) == ID_INPUT) {
911 return static_cast<HTMLInputElementImpl *>(node);
916 static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
918 NodeImpl *node = [element _nodeImpl];
919 // This should not be necessary, but an XSL file on
920 // maps.google.com crashes otherwise because it is an xslt file
921 // that contains <form> elements that aren't in any namespace, so
922 // they come out as generic CML elements
923 if (node && node->isHTMLElement() && idFromNode(node) == ID_FORM) {
924 return static_cast<HTMLFormElementImpl *>(node);
929 - (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form
931 HTMLFormElementImpl *formElement = formElementFromDOMElement(form);
933 QPtrVector<HTMLGenericFormElementImpl> &elements = formElement->formElements;
934 QString targetName = QString::fromNSString(name);
935 for (unsigned int i = 0; i < elements.count(); i++) {
936 HTMLGenericFormElementImpl *elt = elements.at(i);
937 // Skip option elements, other duds
938 if (elt->name() == targetName) {
939 return [DOMElement _elementWithImpl:elt];
946 - (BOOL)elementDoesAutoComplete:(DOMElement *)element
948 HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
949 return inputElement != nil
950 && inputElement->inputType() == HTMLInputElementImpl::TEXT
951 && inputElement->autoComplete();
954 - (BOOL)elementIsPassword:(DOMElement *)element
956 HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
957 return inputElement != nil
958 && inputElement->inputType() == HTMLInputElementImpl::PASSWORD;
961 - (DOMElement *)formForElement:(DOMElement *)element;
963 HTMLInputElementImpl *inputElement = inputElementFromDOMElement(element);
965 HTMLFormElementImpl *formElement = inputElement->form();
967 return [DOMElement _elementWithImpl:formElement];
973 - (DOMElement *)currentForm
975 HTMLFormElementImpl *formElement = _part->currentForm();
976 return formElement ? [DOMElement _elementWithImpl:formElement] : nil;
979 - (NSArray *)controlsInForm:(DOMElement *)form
981 NSMutableArray *results = nil;
982 HTMLFormElementImpl *formElement = formElementFromDOMElement(form);
984 QPtrVector<HTMLGenericFormElementImpl> &elements = formElement->formElements;
985 for (unsigned int i = 0; i < elements.count(); i++) {
986 if (elements.at(i)->isEnumeratable()) { // Skip option elements, other duds
987 NSView *view = viewForElement(elements.at(i));
990 results = [NSMutableArray arrayWithObject:view];
992 [results addObject:view];
1001 - (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element
1003 return _part->searchForLabelsBeforeElement(labels, [element _elementImpl]);
1006 - (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element
1008 return _part->matchLabelsAgainstElement(labels, [element _elementImpl]);
1011 - (NSDictionary *)elementAtPoint:(NSPoint)point
1013 RenderObject *renderer = _part->renderer();
1017 RenderObject::NodeInfo nodeInfo(true, true);
1018 renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
1020 NSMutableDictionary *element = [NSMutableDictionary dictionary];
1021 [element setObject:[NSNumber numberWithBool:_part->isPointInsideSelection((int)point.x, (int)point.y)]
1022 forKey:WebCoreElementIsSelectedKey];
1024 // Find the title in the nearest enclosing DOM node.
1025 // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
1026 for (NodeImpl *titleNode = nodeInfo.innerNode(); titleNode; titleNode = titleNode->parentNode()) {
1027 if (titleNode->isElementNode()) {
1028 const AtomicString& title = static_cast<ElementImpl *>(titleNode)->getAttribute(ATTR_TITLE);
1029 if (!title.isNull()) {
1030 // We found a node with a title.
1031 QString titleText = title.string();
1032 titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1033 [element setObject:titleText.getNSString() forKey:WebCoreElementTitleKey];
1039 NodeImpl *URLNode = nodeInfo.URLElement();
1041 ElementImpl *e = static_cast<ElementImpl *>(URLNode);
1042 DocumentImpl *doc = e->getDocument();
1045 const AtomicString& title = e->getAttribute(ATTR_TITLE);
1046 if (!title.isEmpty()) {
1047 QString titleText = title.string();
1048 titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1049 [element setObject:titleText.getNSString() forKey:WebCoreElementLinkTitleKey];
1052 const AtomicString& link = e->getAttribute(ATTR_HREF);
1053 if (!link.isNull()) {
1054 if (e->firstChild()) {
1056 r.setStartBefore(e->firstChild());
1057 r.setEndAfter(e->lastChild());
1058 QString t = _part->text(r);
1060 [element setObject:t.getNSString() forKey:WebCoreElementLinkLabelKey];
1063 QString URLString = parseURL(link).string();
1064 [element setObject:doc->completeURL(URLString).getNSString() forKey:WebCoreElementLinkURLKey];
1067 DOMString target = e->getAttribute(ATTR_TARGET);
1068 if (target.isEmpty() && doc) { // FIXME: Take out this doc check when we're not just before a release.
1069 target = doc->baseTarget();
1071 if (!target.isEmpty()) {
1072 [element setObject:target.string().getNSString() forKey:WebCoreElementLinkTargetFrameKey];
1076 NodeImpl *node = nodeInfo.innerNonSharedNode();
1078 [element setObject:[DOMNode _nodeWithImpl:node] forKey:WebCoreElementDOMNodeKey];
1080 if (node->renderer() && node->renderer()->isImage()) {
1081 RenderImage *r = static_cast<RenderImage *>(node->renderer());
1082 NSImage *image = r->pixmap().image();
1083 // Only return image information if there is an image.
1084 if (image && !r->isDisplayingError()) {
1085 [element setObject:r->pixmap().image() forKey:WebCoreElementImageKey];
1089 if (r->absolutePosition(x, y)) {
1090 NSValue *rect = [NSValue valueWithRect:NSMakeRect(x, y, r->contentWidth(), r->contentHeight())];
1091 [element setObject:rect forKey:WebCoreElementImageRectKey];
1094 ElementImpl *i = static_cast<ElementImpl*>(node);
1096 // FIXME: Code copied from RenderImage::updateFromElement; should share.
1098 if (idFromNode(i) == ID_OBJECT) {
1099 attr = i->getAttribute(ATTR_DATA);
1101 attr = i->getAttribute(ATTR_SRC);
1103 if (!attr.isEmpty()) {
1104 QString URLString = parseURL(attr).string();
1105 [element setObject:i->getDocument()->completeURL(URLString).getNSString() forKey:WebCoreElementImageURLKey];
1108 // FIXME: Code copied from RenderImage::updateFromElement; should share.
1110 if (idFromNode(i) == ID_INPUT)
1111 alt = static_cast<HTMLInputElementImpl *>(i)->altText();
1112 else if (idFromNode(i) == ID_IMG)
1113 alt = static_cast<HTMLImageElementImpl *>(i)->altText();
1114 if (!alt.isNull()) {
1115 QString altText = alt.string();
1116 altText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
1117 [element setObject:altText.getNSString() forKey:WebCoreElementImageAltStringKey];
1125 - (NSURL *)URLWithAttributeString:(NSString *)string
1127 DocumentImpl *doc = _part->xmlDocImpl();
1131 QString rel = parseURL(QString::fromNSString(string)).string();
1132 return KURL(doc->baseURL(), rel, doc->decoder() ? doc->decoder()->codec() : 0).getNSURL();
1135 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
1137 return _part->findString(string, forward, caseFlag, wrapFlag);
1140 - (void)jumpToSelection
1142 _part->jumpToSelection();
1145 - (NSString *)advanceToNextMisspelling
1147 return _part->advanceToNextMisspelling().getNSString();
1150 - (NSString *)advanceToNextMisspellingStartingJustBeforeSelection
1152 return _part->advanceToNextMisspelling(true).getNSString();
1155 - (void)unmarkAllMisspellings
1157 DocumentImpl *doc = _part->xmlDocImpl();
1161 doc->removeAllMarkers();
1164 - (void)setTextSizeMultiplier:(float)multiplier
1166 int newZoomFactor = (int)rint(multiplier * 100);
1167 if (_part->zoomFactor() == newZoomFactor) {
1170 _part->setZoomFactor(newZoomFactor);
1173 - (CFStringEncoding)textEncoding
1175 return KWQCFStringEncodingFromIANACharsetName(_part->encoding().latin1());
1178 - (NSView *)nextKeyView
1180 DocumentImpl *doc = _part->xmlDocImpl();
1184 return _part->nextKeyView(doc->focusNode(), KWQSelectingNext);
1187 - (NSView *)previousKeyView
1189 DocumentImpl *doc = _part->xmlDocImpl();
1193 return _part->nextKeyView(doc->focusNode(), KWQSelectingPrevious);
1196 - (NSView *)nextKeyViewInsideWebFrameViews
1198 DocumentImpl *doc = _part->xmlDocImpl();
1203 return _part->nextKeyViewInFrameHierarchy(doc->focusNode(), KWQSelectingNext);
1206 - (NSView *)previousKeyViewInsideWebFrameViews
1208 DocumentImpl *doc = _part->xmlDocImpl();
1213 return _part->nextKeyViewInFrameHierarchy(doc->focusNode(), KWQSelectingPrevious);
1216 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string
1218 return [self stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
1222 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
1224 _part->createEmptyDocument();
1225 return _part->executeScript(QString::fromNSString(string), forceUserGesture).asString().getNSString();
1228 - (WebScriptObject *)windowScriptObject
1230 return _part->windowScriptObject();
1233 - (NPObject *)windowScriptNPObject
1235 return _part->windowScriptNPObject();
1238 - (DOMDocument *)DOMDocument
1240 return [DOMDocument _documentWithImpl:_part->xmlDocImpl()];
1243 - (DOMHTMLElement *)frameElement
1245 return (DOMHTMLElement *)[[self DOMDocument] _ownerElement];
1248 - (NSAttributedString *)selectedAttributedString
1250 return _part->attributedString(_part->selectionStart(), _part->selectionStartOffset(), _part->selectionEnd(), _part->selectionEndOffset());
1253 - (NSAttributedString *)attributedStringFrom:(DOMNode *)start startOffset:(int)startOffset to:(DOMNode *)end endOffset:(int)endOffset
1255 DOMNode *startNode = start;
1256 DOMNode *endNode = end;
1257 return _part->attributedString([startNode _nodeImpl], startOffset, [endNode _nodeImpl], endOffset);
1260 - (NSRect)selectionRect
1262 return _part->selectionRect();
1265 - (NSRect)visibleSelectionRect
1267 return _part->visibleSelectionRect();
1270 - (void)centerSelectionInVisibleArea
1272 _part->centerSelectionInVisibleArea();
1275 - (NSRect)caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
1277 return [node _nodeImpl]->renderer()->caretRect(offset, static_cast<EAffinity>(affinity));
1279 - (NSRect)firstRectForDOMRange:(DOMRange *)range
1281 int extraWidthToEndOfLine = 0;
1282 QRect startCaretRect = [[range startContainer] _nodeImpl]->renderer()->caretRect([range startOffset], UPSTREAM, &extraWidthToEndOfLine);
1283 QRect endCaretRect = [[range startContainer] _nodeImpl]->renderer()->caretRect([range endOffset], UPSTREAM);
1285 if (startCaretRect.y() == endCaretRect.y()) {
1286 // start and end are on the same line
1287 return QRect(MIN(startCaretRect.x(), endCaretRect.x()),
1289 abs(endCaretRect.x() - startCaretRect.x()),
1290 MAX(startCaretRect.height(), endCaretRect.height()));
1293 // start and end aren't on the same line, so go from start to the end of its line
1294 return QRect(startCaretRect.x(),
1296 startCaretRect.width() + extraWidthToEndOfLine,
1297 startCaretRect.height());
1300 - (NSImage *)selectionImage
1302 return _part->selectionImage();
1305 - (void)setName:(NSString *)name
1307 _part->KHTMLPart::setName(QString::fromNSString(name));
1312 return _part->name().getNSString();
1317 return _part->url().getNSURL();
1322 return _part->completeURL(_part->xmlDocImpl()->baseURL()).getNSURL();
1325 - (NSString *)referrer
1327 return _part->referrer().getNSString();
1330 - (NSString *)domain
1332 DocumentImpl *doc = _part->xmlDocImpl();
1333 if (doc && doc->isHTMLDocument()) {
1334 return doc->domain().string().getNSString();
1339 - (WebCoreBridge *)opener
1341 KHTMLPart *openerPart = _part->opener();
1344 return KWQ(openerPart)->bridge();
1349 + (NSString *)stringWithData:(NSData *)data textEncoding:(CFStringEncoding)textEncoding
1351 if (textEncoding == kCFStringEncodingInvalidId || textEncoding == kCFStringEncodingISOLatin1) {
1352 textEncoding = kCFStringEncodingWindowsLatin1;
1354 return QTextCodec(textEncoding).toUnicode((const char*)[data bytes], [data length]).getNSString();
1357 + (NSString *)stringWithData:(NSData *)data textEncodingName:(NSString *)textEncodingName
1359 CFStringEncoding textEncoding = KWQCFStringEncodingFromIANACharsetName([textEncodingName lossyCString]);
1360 return [WebCoreBridge stringWithData:data textEncoding:textEncoding];
1365 RenderObject *renderer = _part->renderer();
1366 return renderer ? renderer->needsLayout() : false;
1369 - (void)setNeedsLayout
1371 RenderObject *renderer = _part->renderer();
1373 renderer->setNeedsLayout(true);
1376 - (BOOL)interceptKeyEvent:(NSEvent *)event toView:(NSView *)view
1378 return _part->keyEvent(event);
1381 - (NSString *)renderTreeAsExternalRepresentation
1383 return externalRepresentation(_part->renderer()).getNSString();
1386 - (void)setSelectionFromNone
1388 _part->setSelectionFromNone();
1391 - (void)setDisplaysWithFocusAttributes:(BOOL)flag
1393 _part->setDisplaysWithFocusAttributes(flag);
1396 - (void)setWindowHasFocus:(BOOL)flag
1398 _part->setWindowHasFocus(flag);
1401 - (void)setShouldCreateRenderers:(BOOL)f
1403 _shouldCreateRenderers = f;
1406 - (BOOL)shouldCreateRenderers
1408 return _shouldCreateRenderers;
1411 - (int)numPendingOrLoadingRequests
1413 DocumentImpl *doc = _part->xmlDocImpl();
1416 return KWQNumberOfPendingOrLoadingRequests (doc->docLoader());
1420 - (BOOL)doneProcessingData
1422 DocumentImpl *doc = _part->xmlDocImpl();
1424 Tokenizer* tok = doc->tokenizer();
1426 return !tok->processingData();
1431 - (NSColor *)bodyBackgroundColor
1433 return _part->bodyBackgroundColor();
1436 - (NSColor *)selectionColor
1438 RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
1440 RenderStyle *pseudoStyle = root->getPseudoStyle(RenderStyle::SELECTION);
1441 if (pseudoStyle && pseudoStyle->backgroundColor().isValid()) {
1442 return pseudoStyle->backgroundColor().getNSColor();
1445 return _part->displaysWithFocusAttributes() ? [NSColor selectedTextBackgroundColor] : [NSColor secondarySelectedControlColor];
1448 - (void)adjustViewSize
1450 KHTMLView *view = _part->view();
1452 view->adjustViewSize();
1455 -(id)accessibilityTree
1457 KWQAccObjectCache::enableAccessibility();
1458 if (!_part || !_part->xmlDocImpl()) return nil;
1459 RenderCanvas* root = static_cast<khtml::RenderCanvas *>(_part->xmlDocImpl()->renderer());
1460 if (!root) return nil;
1461 return _part->xmlDocImpl()->getAccObjectCache()->accObject(root);
1464 - (void)setDrawsBackground:(BOOL)drawsBackground
1466 if (_part && _part->view())
1467 _part->view()->setTransparent(!drawsBackground);
1470 - (void)undoEditing:(id)arg
1472 ASSERT([arg isKindOfClass:[KWQEditCommand class]]);
1473 [arg command]->unapply();
1476 - (void)redoEditing:(id)arg
1478 ASSERT([arg isKindOfClass:[KWQEditCommand class]]);
1479 [arg command]->reapply();
1482 - (DOMRange *)rangeByExpandingSelectionWithGranularity:(WebSelectionGranularity)granularity
1484 if (!partHasSelection(self))
1487 // NOTE: The enums *must* match the very similar ones declared in ktml_selection.h
1488 Selection selection(_part->selection());
1489 selection.expandUsingGranularity(static_cast<ETextGranularity>(granularity));
1490 return [DOMRange _rangeWithImpl:selection.toRange().handle()];
1493 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
1495 if (!partHasSelection(self))
1498 // NOTE: The enums *must* match the very similar ones declared in ktml_selection.h
1499 Selection selection(_part->selection());
1500 selection.modify(static_cast<Selection::EAlter>(alteration),
1501 static_cast<Selection::EDirection>(direction),
1502 static_cast<ETextGranularity>(granularity));
1503 return [DOMRange _rangeWithImpl:selection.toRange().handle()];
1506 - (void)alterCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
1508 if (!partHasSelection(self))
1511 // NOTE: The enums *must* match the very similar ones declared in dom_selection.h
1512 Selection selection(_part->selection());
1513 selection.modify(static_cast<Selection::EAlter>(alteration),
1514 static_cast<Selection::EDirection>(direction),
1515 static_cast<ETextGranularity>(granularity));
1517 // save vertical navigation x position if necessary; many types of motion blow it away
1518 int xPos = KHTMLPart::NoXPosForVerticalArrowNavigation;
1519 switch (granularity) {
1520 case WebSelectByLine:
1521 case WebSelectByParagraph:
1522 xPos = _part->xPosForVerticalArrowNavigation();
1524 case WebSelectByCharacter:
1525 case WebSelectByWord:
1526 case WebSelectToLineBoundary:
1527 case WebSelectToParagraphBoundary:
1528 case WebSelectToDocumentBoundary:
1533 // setting the selection always clears saved vertical navigation x position
1534 _part->setSelection(selection);
1536 // altering the selection also sets the granularity back to character
1537 // NOTE: The one exception is that we need to keep word granularity
1538 // to preserve smart delete behavior when extending by word. e.g. double-click,
1539 // then shift-option-rightarrow, then delete needs to smart delete, per TextEdit.
1540 if (!((alteration == WebSelectByExtending) &&
1541 (granularity == WebSelectByWord) && (_part->selectionGranularity() == khtml::WORD)))
1542 _part->setSelectionGranularity(static_cast<ETextGranularity>(WebSelectByCharacter));
1544 // restore vertical navigation x position if necessary
1545 if (xPos != KHTMLPart::NoXPosForVerticalArrowNavigation)
1546 _part->setXPosForVerticalArrowNavigation(xPos);
1548 _part->selectFrameElementInParentIfFullySelected();
1550 [self ensureSelectionVisible];
1553 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration verticalDistance:(float)verticalDistance
1555 if (!partHasSelection(self))
1558 Selection selection(_part->selection());
1559 selection.modify(static_cast<Selection::EAlter>(alteration), static_cast<int>(verticalDistance));
1560 return [DOMRange _rangeWithImpl:selection.toRange().handle()];
1563 - (void)alterCurrentSelection:(WebSelectionAlteration)alteration verticalDistance:(float)verticalDistance
1565 if (!partHasSelection(self))
1568 Selection selection(_part->selection());
1569 selection.modify(static_cast<Selection::EAlter>(alteration), static_cast<int>(verticalDistance));
1571 // setting the selection always clears saved vertical navigation x position, so preserve it
1572 int xPos = _part->xPosForVerticalArrowNavigation();
1573 _part->setSelection(selection);
1574 _part->setSelectionGranularity(static_cast<ETextGranularity>(WebSelectByCharacter));
1575 _part->setXPosForVerticalArrowNavigation(xPos);
1577 _part->selectFrameElementInParentIfFullySelected();
1579 [self ensureSelectionVisible];
1582 - (WebSelectionGranularity)selectionGranularity
1584 // NOTE: The enums *must* match the very similar ones declared in dom_selection.h
1585 return static_cast<WebSelectionGranularity>(_part->selectionGranularity());
1588 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity closeTyping:(BOOL)closeTyping
1590 NodeImpl *startContainer = [[range startContainer] _nodeImpl];
1591 NodeImpl *endContainer = [[range endContainer] _nodeImpl];
1592 ASSERT(startContainer);
1593 ASSERT(endContainer);
1594 ASSERT(startContainer->getDocument());
1595 ASSERT(startContainer->getDocument() == endContainer->getDocument());
1597 _part->xmlDocImpl()->updateLayout();
1599 EAffinity affinity = static_cast<EAffinity>(selectionAffinity);
1601 bool rangeCollapsed = [range collapsed];
1602 if (!rangeCollapsed)
1603 affinity = DOWNSTREAM;
1605 // Work around bug where isRenderedContent returns false for <br> elements at the ends of lines.
1606 // If that bug wasn't an issue, we could just make the position from the range directly.
1607 Position start(startContainer, [range startOffset]);
1608 Position end(endContainer, [range endOffset]);
1609 VisiblePosition visibleStart(start, affinity, khtml::VisiblePosition::INIT_UP);
1610 start = visibleStart.deepEquivalent();
1612 if (rangeCollapsed) {
1613 setAffinityUsingLinePosition(visibleStart);
1614 affinity = visibleStart.affinity();
1617 // FIXME: Can we provide extentAffinity?
1618 Selection selection(start, affinity, end, khtml::SEL_DEFAULT_AFFINITY);
1619 _part->setSelection(selection, closeTyping);
1622 - (DOMRange *)selectedDOMRange
1624 return [DOMRange _rangeWithImpl:_part->selection().toRange().handle()];
1627 - (NSSelectionAffinity)selectionAffinity
1629 return static_cast<NSSelectionAffinity>(_part->selection().startAffinity());
1632 - (void)setMarkDOMRange:(DOMRange *)range
1634 _part->setMark(Selection([range _rangeImpl], khtml::SEL_DEFAULT_AFFINITY, khtml::SEL_DEFAULT_AFFINITY));
1637 - (DOMRange *)markDOMRange
1639 return [DOMRange _rangeWithImpl:_part->mark().toRange().handle()];
1642 - (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges
1644 _part->setMarkedTextRange([range _rangeImpl], attributes, ranges);
1647 - (DOMRange *)markedTextDOMRange
1649 return [DOMRange _rangeWithImpl:_part->markedTextRange().handle()];
1652 - (void)replaceMarkedTextWithText:(NSString *)text
1654 if (!partHasSelection(self))
1657 Range markedTextRange = _part->markedTextRange();
1658 if (!markedTextRange.isNull() && !markedTextRange.collapsed())
1659 TypingCommand::deleteKeyPressed(_part->xmlDocImpl(), NO);
1661 if ([text length] > 0)
1662 TypingCommand::insertText(_part->xmlDocImpl(), text, YES);
1664 [self ensureSelectionVisible];
1667 - (BOOL)canDeleteRange:(DOMRange *)range
1669 NodeImpl *startContainer = [[range startContainer] _nodeImpl];
1670 NodeImpl *endContainer = [[range endContainer] _nodeImpl];
1671 if (startContainer == nil || endContainer == nil)
1674 if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
1677 if ([range collapsed]) {
1678 VisiblePosition start(startContainer, [range startOffset], DOWNSTREAM);
1679 if (isStartOfEditableContent(start))
1686 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
1687 // be deleted along with the proposed range in order to preserve proper spacing and punctuation of
1688 // the text surrounding the deletion.
1689 - (DOMRange *)smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
1691 NodeImpl *startContainer = [[proposedRange startContainer] _nodeImpl];
1692 NodeImpl *endContainer = [[proposedRange endContainer] _nodeImpl];
1693 if (startContainer == nil || endContainer == nil)
1696 ASSERT(startContainer->getDocument());
1697 ASSERT(startContainer->getDocument() == endContainer->getDocument());
1699 _part->xmlDocImpl()->updateLayout();
1701 Position start(startContainer, [proposedRange startOffset]);
1702 Position end(endContainer, [proposedRange endOffset]);
1703 Position newStart = start.upstream(DOM::StayInBlock).leadingWhitespacePosition(khtml::DOWNSTREAM, true);
1704 if (newStart.isNull())
1706 Position newEnd = end.downstream(DOM::StayInBlock).trailingWhitespacePosition(khtml::DOWNSTREAM, true);
1707 if (newEnd.isNull())
1710 return [DOMRange _rangeWithImpl:Range(newStart.node(), newStart.offset(), newEnd.node(), newEnd.offset()).handle()];
1713 // Determines whether whitespace needs to be added around aString to preserve proper spacing and
1714 // punctuation when itÕs inserted into the receiverÕs text over charRange. Returns by reference
1715 // in beforeString and afterString any whitespace that should be added, unless either or both are
1716 // nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
1717 - (void)smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1719 // give back nil pointers in case of early returns
1721 *beforeString = nil;
1725 // inspect destination
1726 NodeImpl *startContainer = [[rangeToReplace startContainer] _nodeImpl];
1727 NodeImpl *endContainer = [[rangeToReplace endContainer] _nodeImpl];
1729 Position startPos(startContainer, [rangeToReplace startOffset]);
1730 Position endPos(endContainer, [rangeToReplace endOffset]);
1732 VisiblePosition startVisiblePos = VisiblePosition(startPos, khtml::VP_DEFAULT_AFFINITY);
1733 VisiblePosition endVisiblePos = VisiblePosition(endPos, khtml::VP_DEFAULT_AFFINITY);
1735 // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
1736 if (startVisiblePos.isNull() || endVisiblePos.isNull())
1739 bool addLeadingSpace = startPos.leadingWhitespacePosition(khtml::VP_DEFAULT_AFFINITY, true).isNull() && !isFirstVisiblePositionInParagraph(startVisiblePos);
1740 if (addLeadingSpace) {
1741 QChar previousChar = startVisiblePos.previous().character();
1742 if (!previousChar.isNull()) {
1743 addLeadingSpace = !_part->isCharacterSmartReplaceExempt(previousChar, true);
1747 bool addTrailingSpace = endPos.trailingWhitespacePosition(khtml::VP_DEFAULT_AFFINITY, true).isNull() && !isLastVisiblePositionInParagraph(endVisiblePos);
1748 if (addTrailingSpace) {
1749 QChar thisChar = endVisiblePos.character();
1750 if (!thisChar.isNull()) {
1751 addTrailingSpace = !_part->isCharacterSmartReplaceExempt(thisChar, false);
1756 bool hasWhitespaceAtStart = false;
1757 bool hasWhitespaceAtEnd = false;
1758 unsigned pasteLength = [pasteString length];
1759 if (pasteLength > 0) {
1760 NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
1762 if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
1763 hasWhitespaceAtStart = YES;
1765 if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
1766 hasWhitespaceAtEnd = YES;
1770 // issue the verdict
1771 if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
1772 *beforeString = @" ";
1773 if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
1774 *afterString = @" ";
1777 - (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString
1779 if (!_part || !_part->xmlDocImpl())
1782 DocumentFragmentImpl *fragment = createFragmentFromMarkup(_part->xmlDocImpl(), QString::fromNSString(markupString), QString::fromNSString(baseURLString));
1783 return [DOMDocumentFragment _documentFragmentWithImpl:fragment];
1786 - (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text
1788 if (!partHasSelection(self) || !text)
1791 return [DOMDocumentFragment _documentFragmentWithImpl:createFragmentFromText(_part->xmlDocImpl(), QString::fromNSString(text))];
1794 - (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1796 if (!partHasSelection(self) || !fragment)
1799 EditCommandPtr(new ReplaceSelectionCommand(_part->xmlDocImpl(), [fragment _fragmentImpl], selectReplacement, smartReplace, matchStyle)).apply();
1800 [self ensureSelectionVisible];
1803 - (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1805 DOMDocumentFragment *fragment = [[self DOMDocument] createDocumentFragment];
1806 [fragment appendChild:node];
1807 [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1810 - (void)replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1812 DOMDocumentFragment *fragment = [self documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
1813 [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1816 - (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1818 [self replaceSelectionWithFragment:[self documentFragmentWithText:text] selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
1821 - (void)insertLineBreak
1823 if (!partHasSelection(self))
1826 TypingCommand::insertLineBreak(_part->xmlDocImpl());
1827 [self ensureSelectionVisible];
1830 - (void)insertParagraphSeparator
1832 if (!partHasSelection(self))
1835 TypingCommand::insertParagraphSeparator(_part->xmlDocImpl());
1836 [self ensureSelectionVisible];
1839 - (void)insertParagraphSeparatorInQuotedContent
1841 if (!partHasSelection(self))
1844 TypingCommand::insertParagraphSeparatorInQuotedContent(_part->xmlDocImpl());
1845 [self ensureSelectionVisible];
1848 - (void)insertText:(NSString *)text selectInsertedText:(BOOL)selectInsertedText
1850 if (!partHasSelection(self))
1853 TypingCommand::insertText(_part->xmlDocImpl(), text, selectInsertedText);
1854 [self ensureSelectionVisible];
1857 - (void)setSelectionToDragCaret
1859 _part->setSelection(_part->dragCaret());
1862 - (void)moveSelectionToDragCaret:(DOMDocumentFragment *)selectionFragment smartMove:(BOOL)smartMove
1864 Position base = _part->dragCaret().base();
1865 EditCommandPtr(new MoveSelectionCommand(_part->xmlDocImpl(), [selectionFragment _fragmentImpl], base, smartMove)).apply();
1868 - (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
1870 RenderObject *renderer = _part->renderer();
1872 return VisiblePosition();
1875 RenderObject::NodeInfo nodeInfo(true, true);
1876 renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
1877 NodeImpl *node = nodeInfo.innerNode();
1878 if (!node->renderer())
1879 return VisiblePosition();
1881 return node->renderer()->positionForCoordinates((int)point.x, (int)point.y);
1884 - (void)moveDragCaretToPoint:(NSPoint)point
1886 Selection dragCaret([self _visiblePositionForPoint:point]);
1887 _part->setDragCaret(dragCaret);
1890 - (void)removeDragCaret
1892 _part->setDragCaret(Selection());
1895 - (DOMRange *)dragCaretDOMRange
1897 return [DOMRange _rangeWithImpl:_part->dragCaret().toRange().handle()];
1900 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
1902 VisiblePosition position = [self _visiblePositionForPoint:point];
1903 return position.isNull() ? nil : [DOMRange _rangeWithImpl:Selection(position).toRange().handle()];
1906 - (void)deleteSelectionWithSmartDelete:(BOOL)smartDelete
1908 if (!partHasSelection(self))
1911 EditCommandPtr(new DeleteSelectionCommand(_part->xmlDocImpl(), smartDelete)).apply();
1914 - (void)deleteKeyPressedWithSmartDelete:(BOOL)smartDelete
1916 if (!_part || !_part->xmlDocImpl())
1919 TypingCommand::deleteKeyPressed(_part->xmlDocImpl(), smartDelete);
1920 [self ensureSelectionVisible];
1923 - (void)forwardDeleteKeyPressedWithSmartDelete:(BOOL)smartDelete
1925 if (!_part || !_part->xmlDocImpl())
1928 TypingCommand::forwardDeleteKeyPressed(_part->xmlDocImpl(), smartDelete);
1929 [self ensureSelectionVisible];
1932 - (DOMCSSStyleDeclaration *)typingStyle
1934 if (!_part || !_part->typingStyle())
1936 return [DOMCSSStyleDeclaration _styleDeclarationWithImpl:_part->typingStyle()];
1939 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
1943 _part->computeAndSetTypingStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
1946 - (void)applyStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
1950 _part->applyStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
1953 - (void)applyParagraphStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebUndoAction)undoAction
1957 _part->applyParagraphStyle([style _styleDeclarationImpl], static_cast<EditAction>(undoAction));
1960 - (BOOL)selectionStartHasStyle:(DOMCSSStyleDeclaration *)style
1964 return _part->selectionStartHasStyle([style _styleDeclarationImpl]);
1967 - (NSCellStateValue)selectionHasStyle:(DOMCSSStyleDeclaration *)style
1971 switch (_part->selectionHasStyle([style _styleDeclarationImpl])) {
1972 case KHTMLPart::falseTriState:
1974 case KHTMLPart::trueTriState:
1976 case KHTMLPart::mixedTriState:
1977 return NSMixedState;
1982 - (void)applyEditingStyleToBodyElement
1986 _part->applyEditingStyleToBodyElement();
1989 - (void)removeEditingStyleFromBodyElement
1993 _part->removeEditingStyleFromBodyElement();
1996 - (void)applyEditingStyleToElement:(DOMElement *)element
2000 _part->applyEditingStyleToElement([element _elementImpl]);
2003 - (void)removeEditingStyleFromElement:(DOMElement *)element
2007 _part->removeEditingStyleFromElement([element _elementImpl]);
2010 - (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts
2012 bool multipleFonts = false;
2015 font = _part->fontForSelection(hasMultipleFonts ? &multipleFonts : 0);
2016 if (hasMultipleFonts)
2017 *hasMultipleFonts = multipleFonts;
2021 - (NSDictionary *)fontAttributesForSelectionStart
2023 return _part ? _part->fontAttributesForSelectionStart() : nil;
2026 - (NSWritingDirection)baseWritingDirectionForSelectionStart
2028 return _part ? _part->baseWritingDirectionForSelectionStart() : NSWritingDirectionLeftToRight;
2031 - (void)ensureSelectionVisible
2033 if (!partHasSelection(self))
2036 KHTMLView *v = _part->view();
2040 Position extent = _part->selection().extent();
2041 if (extent.isNull())
2044 RenderObject *renderer = extent.node()->renderer();
2048 NSView *documentView = v->getDocumentView();
2052 QRect extentRect = renderer->caretRect(extent.offset(), _part->selection().extentAffinity());
2053 if (!NSContainsRect([documentView visibleRect], NSRect(extentRect))) {
2054 v->ensureRectVisibleCentered(extentRect, true);
2058 // [info draggingLocation] is in window coords
2060 - (BOOL)eventMayStartDrag:(NSEvent *)event
2062 return _part ? _part->eventMayStartDrag(event) : NO;
2065 - (NSDragOperation)dragOperationForDraggingInfo:(id <NSDraggingInfo>)info
2067 NSDragOperation op = NSDragOperationNone;
2069 KHTMLView *v = _part->view();
2071 // Sending an event can result in the destruction of the view and part.
2074 KWQClipboard::AccessPolicy policy = _part->baseURL().isLocalFile() ? KWQClipboard::Readable : KWQClipboard::TypesReadable;
2075 KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], policy);
2077 NSDragOperation srcOp = [info draggingSourceOperationMask];
2078 clipboard->setSourceOperation(srcOp);
2080 if (v->updateDragAndDrop(QPoint([info draggingLocation]), clipboard)) {
2081 // *op unchanged if no source op was set
2082 if (!clipboard->destinationOperation(&op)) {
2083 // The element accepted but they didn't pick an operation, so we pick one for them
2085 if (srcOp & NSDragOperationCopy) {
2086 op = NSDragOperationCopy;
2087 } else if (srcOp & NSDragOperationMove || srcOp & NSDragOperationGeneric) {
2088 op = NSDragOperationMove;
2089 } else if (srcOp & NSDragOperationLink) {
2090 op = NSDragOperationLink;
2092 op = NSDragOperationGeneric;
2094 } else if (!(op & srcOp)) {
2095 // make sure WC picked an op that was offered. Cocoa doesn't seem to enforce this,
2097 op = NSDragOperationNone;
2100 clipboard->setAccessPolicy(KWQClipboard::Numb); // invalidate clipboard here for security
2110 - (void)dragExitedWithDraggingInfo:(id <NSDraggingInfo>)info
2113 KHTMLView *v = _part->view();
2115 // Sending an event can result in the destruction of the view and part.
2118 KWQClipboard::AccessPolicy policy = _part->baseURL().isLocalFile() ? KWQClipboard::Readable : KWQClipboard::TypesReadable;
2119 KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], policy);
2121 clipboard->setSourceOperation([info draggingSourceOperationMask]);
2123 v->cancelDragAndDrop(QPoint([info draggingLocation]), clipboard);
2124 clipboard->setAccessPolicy(KWQClipboard::Numb); // invalidate clipboard here for security
2132 - (BOOL)concludeDragForDraggingInfo:(id <NSDraggingInfo>)info
2135 KHTMLView *v = _part->view();
2137 // Sending an event can result in the destruction of the view and part.
2140 KWQClipboard *clipboard = new KWQClipboard(true, [info draggingPasteboard], KWQClipboard::Readable);
2142 clipboard->setSourceOperation([info draggingSourceOperationMask]);
2144 BOOL result = v->performDragAndDrop(QPoint([info draggingLocation]), clipboard);
2145 clipboard->setAccessPolicy(KWQClipboard::Numb); // invalidate clipboard here for security
2156 - (void)dragSourceMovedTo:(NSPoint)windowLoc
2159 _part->dragSourceMovedTo(QPoint(windowLoc));
2163 - (void)dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
2166 _part->dragSourceEndedAt(QPoint(windowLoc), operation);
2172 return _part->mayCut();
2175 - (BOOL)mayDHTMLCopy
2177 return _part->mayCopy();
2180 - (BOOL)mayDHTMLPaste
2182 return _part->mayPaste();
2187 return _part->tryCut();
2190 - (BOOL)tryDHTMLCopy
2192 return _part->tryCopy();
2195 - (BOOL)tryDHTMLPaste
2197 return _part->tryPaste();
2200 - (DOMRange *)rangeOfCharactersAroundCaret
2205 Selection selection(_part->selection());
2206 if (!selection.isCaret())
2209 VisiblePosition caret(selection.start(), selection.startAffinity());
2210 VisiblePosition next = caret.next();
2211 VisiblePosition previous = caret.previous();
2212 if (caret == next || caret == previous)
2215 return [DOMRange _rangeWithImpl:makeRange(previous, next).handle()];
2218 - (NSMutableDictionary *)dashboardRegions
2220 return _part->dashboardRegionsDictionary();
2225 @implementation WebCoreBridge (WebCoreBridgeInternal)
2227 - (RootObject *)executionContextForView:(NSView *)aView
2229 KWQKHTMLPart *part = [self part];
2230 RootObject *root = new RootObject(aView); // The root gets deleted by JavaScriptCore.
2231 root->setRootObjectImp(static_cast<ObjectImp *>(Window::retrieveWindow(part)));
2232 root->setInterpreter(KJSProxy::proxy(part)->interpreter());
2233 part->addPluginRootObject(root);