b4a0315d58e525c0726d9573fbdf621a31f6ed93
[WebKit-https.git] / WebCore / page / mac / WebCoreFrameBridge.mm
1 /*
2  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2005, 2006 Alexey Proskuryakov (ap@nypop.com)
4  * Copyright (C) 2006 David Smith (catfish.man@gmail.com)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #import "config.h"
29 #import "WebCoreFrameBridge.h"
30
31 #import "AXObjectCache.h"
32 #import "Cache.h"
33 #import "ClipboardMac.h"
34 #import "DOMImplementation.h"
35 #import "DOMInternal.h"
36 #import "TextResourceDecoder.h"
37 #import "DeleteSelectionCommand.h"
38 #import "DocLoader.h"
39 #import "DocumentFragment.h"
40 #import "DocumentType.h"
41 #import "Editor.h"
42 #import "EditorClient.h"
43 #import "EventHandler.h"
44 #import "FloatRect.h"
45 #import "FontData.h"
46 #import "Frame.h"
47 #import "FrameLoader.h"
48 #import "FrameLoaderClient.h"
49 #import "FrameTree.h"
50 #import "FrameView.h"
51 #import "GraphicsContext.h"
52 #import "HTMLDocument.h"
53 #import "HTMLFormElement.h"
54 #import "HTMLInputElement.h"
55 #import "HTMLNames.h"
56 #import "HitTestResult.h"
57 #import "Image.h"
58 #import "LoaderNSURLExtras.h"
59 #import "MoveSelectionCommand.h"
60 #import "Page.h"
61 #import "PlatformMouseEvent.h"
62 #import "PlugInInfoStore.h"
63 #import "RenderImage.h"
64 #import "RenderPart.h"
65 #import "RenderTreeAsText.h"
66 #import "RenderView.h"
67 #import "RenderWidget.h"
68 #import "ReplaceSelectionCommand.h"
69 #import "ResourceRequest.h"
70 #import "PlatformScreen.h"
71 #import "SelectionController.h"
72 #import "SystemTime.h"
73 #import "TextEncoding.h"
74 #import "TextIterator.h"
75 #import "TypingCommand.h"
76 #import "WebCoreSystemInterface.h"
77 #import "WebCoreViewFactory.h"
78 #import "DocumentLoader.h"
79 #import "FormDataStreamMac.h"
80 #import "SubresourceLoader.h"
81 #import "XMLTokenizer.h"
82 #import "csshelper.h"
83 #import "htmlediting.h"
84 #import "kjs_proxy.h"
85 #import "kjs_window.h"
86 #import "markup.h"
87 #import "visible_units.h"
88 #import <JavaScriptCore/array_instance.h>
89 #import <JavaScriptCore/date_object.h>
90 #import <JavaScriptCore/runtime_root.h>
91 #import <wtf/RetainPtr.h>
92
93 @class NSView;
94
95 using namespace std;
96 using namespace WebCore;
97 using namespace HTMLNames;
98
99 using KJS::ArrayInstance;
100 using KJS::BooleanType;
101 using KJS::DateInstance;
102 using KJS::ExecState;
103 using KJS::GetterSetterType;
104 using KJS::JSImmediate;
105 using KJS::JSLock;
106 using KJS::JSObject;
107 using KJS::JSValue;
108 using KJS::NullType;
109 using KJS::NumberType;
110 using KJS::ObjectType;
111 using KJS::SavedBuiltins;
112 using KJS::SavedProperties;
113 using KJS::StringType;
114 using KJS::UndefinedType;
115 using KJS::UnspecifiedType;
116 using KJS::Window;
117
118 using KJS::Bindings::RootObject;
119
120 static PassRefPtr<RootObject> createRootObject(void* nativeHandle)
121 {
122     NSView *view = (NSView *)nativeHandle;
123     WebCoreFrameBridge *bridge = [[WebCoreViewFactory sharedFactory] bridgeForView:view];
124     if (!bridge)
125         return 0;
126
127     Frame* frame = [bridge _frame];
128     return frame->createRootObject(nativeHandle, frame->scriptProxy()->interpreter());
129 }
130
131 static pthread_t mainThread = 0;
132
133 static void updateRenderingForBindings(ExecState* exec, JSObject* rootObject)
134 {
135     if (pthread_self() != mainThread)
136         return;
137         
138     if (!rootObject)
139         return;
140         
141     Window* window = static_cast<Window*>(rootObject);
142     if (!window)
143         return;
144         
145     if (Document* doc = window->frame()->document())
146         doc->updateRendering();
147 }
148
149 static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue* jsValue)
150 {
151     NSAppleEventDescriptor* aeDesc = 0;
152     switch (jsValue->type()) {
153         case BooleanType:
154             aeDesc = [NSAppleEventDescriptor descriptorWithBoolean:jsValue->getBoolean()];
155             break;
156         case StringType:
157             aeDesc = [NSAppleEventDescriptor descriptorWithString:String(jsValue->getString())];
158             break;
159         case NumberType: {
160             double value = jsValue->getNumber();
161             int intValue = (int)value;
162             if (value == intValue)
163                 aeDesc = [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt32 bytes:&intValue length:sizeof(intValue)];
164             else
165                 aeDesc = [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&value length:sizeof(value)];
166             break;
167         }
168         case ObjectType: {
169             JSObject* object = jsValue->getObject();
170             if (object->inherits(&DateInstance::info)) {
171                 DateInstance* date = static_cast<DateInstance*>(object);
172                 double ms = 0;
173                 int tzOffset = 0;
174                 if (date->getTime(ms, tzOffset)) {
175                     CFAbsoluteTime utcSeconds = ms / 1000 - kCFAbsoluteTimeIntervalSince1970;
176                     LongDateTime ldt;
177                     if (noErr == UCConvertCFAbsoluteTimeToLongDateTime(utcSeconds, &ldt))
178                         aeDesc = [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&ldt length:sizeof(ldt)];
179                 }
180             }
181             else if (object->inherits(&ArrayInstance::info)) {
182                 static HashSet<JSObject*> visitedElems;
183                 if (!visitedElems.contains(object)) {
184                     visitedElems.add(object);
185                     
186                     ArrayInstance* array = static_cast<ArrayInstance*>(object);
187                     aeDesc = [NSAppleEventDescriptor listDescriptor];
188                     unsigned numItems = array->getLength();
189                     for (unsigned i = 0; i < numItems; ++i)
190                         [aeDesc insertDescriptor:aeDescFromJSValue(exec, array->getItem(i)) atIndex:0];
191                     
192                     visitedElems.remove(object);
193                 }
194             }
195             if (!aeDesc) {
196                 JSValue* primitive = object->toPrimitive(exec);
197                 if (exec->hadException()) {
198                     exec->clearException();
199                     return [NSAppleEventDescriptor nullDescriptor];
200                 }
201                 return aeDescFromJSValue(exec, primitive);
202             }
203             break;
204         }
205         case UndefinedType:
206             aeDesc = [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue];
207             break;
208         default:
209             LOG_ERROR("Unknown JavaScript type: %d", jsValue->type());
210             // no break;
211         case UnspecifiedType:
212         case NullType:
213         case GetterSetterType:
214             aeDesc = [NSAppleEventDescriptor nullDescriptor];
215             break;
216     }
217     
218     return aeDesc;
219 }
220
221 @implementation WebCoreFrameBridge
222
223 static inline WebCoreFrameBridge *bridge(Frame *frame)
224 {
225     if (!frame)
226         return nil;
227     return frame->bridge();
228 }
229
230 - (NSString *)domain
231 {
232     Document *doc = m_frame->document();
233     if (doc)
234         return doc->domain();
235     return nil;
236 }
237
238 + (WebCoreFrameBridge *)bridgeForDOMDocument:(DOMDocument *)document
239 {
240     return bridge([document _document]->frame());
241 }
242
243 - (id)init
244 {
245     static bool initializedKJS;
246     if (!initializedKJS) {
247         initializedKJS = true;
248
249         mainThread = pthread_self();
250         RootObject::setCreateRootObject(createRootObject);
251         KJS::Bindings::Instance::setDidExecuteFunction(updateRenderingForBindings);
252     }
253     
254     if (!(self = [super init]))
255         return nil;
256
257     _shouldCreateRenderers = YES;
258     return self;
259 }
260
261 - (void)dealloc
262 {
263     ASSERT(_closed);
264     [super dealloc];
265 }
266
267 - (void)finalize
268 {
269     ASSERT(_closed);
270     [super finalize];
271 }
272
273 - (void)close
274 {
275     [self clearFrame];
276     _closed = YES;
277 }
278
279 - (void)addData:(NSData *)data
280 {
281     Document *doc = m_frame->document();
282     
283     // Document may be nil if the part is about to redirect
284     // as a result of JS executing during load, i.e. one frame
285     // changing another's location before the frame's document
286     // has been created. 
287     if (doc) {
288         doc->setShouldCreateRenderers([self shouldCreateRenderers]);
289         m_frame->loader()->addData((const char *)[data bytes], [data length]);
290     }
291 }
292
293 - (BOOL)scrollOverflowInDirection:(WebScrollDirection)direction granularity:(WebScrollGranularity)granularity
294 {
295     if (!m_frame)
296         return NO;
297     return m_frame->eventHandler()->scrollOverflow((ScrollDirection)direction, (ScrollGranularity)granularity);
298 }
299
300 - (void)clearFrame
301 {
302     m_frame = 0;
303 }
304
305 - (void)createFrameViewWithNSView:(NSView *)view marginWidth:(int)mw marginHeight:(int)mh
306 {
307     // If we own the view, delete the old one - otherwise the render m_frame will take care of deleting the view.
308     if (m_frame)
309         m_frame->setView(0);
310
311     FrameView* frameView = new FrameView(m_frame);
312     m_frame->setView(frameView);
313     frameView->deref();
314
315     frameView->setView(view);
316     if (mw >= 0)
317         frameView->setMarginWidth(mw);
318     if (mh >= 0)
319         frameView->setMarginHeight(mh);
320 }
321
322 - (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString
323 {
324     return m_frame->documentTypeString() + markupString;
325 }
326
327 - (NSArray *)nodesFromList:(Vector<Node*> *)nodesVector
328 {
329     size_t size = nodesVector->size();
330     NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size];
331     for (size_t i = 0; i < size; ++i)
332         [nodes addObject:[DOMNode _wrapNode:(*nodesVector)[i]]];
333     return nodes;
334 }
335
336 - (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes
337 {
338     // FIXME: This is never "for interchange". Is that right? See the next method.
339     Vector<Node*> nodeList;
340     NSString *markupString = createMarkup([node _node], IncludeNode, nodes ? &nodeList : 0).getNSString();
341     if (nodes)
342         *nodes = [self nodesFromList:&nodeList];
343
344     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
345 }
346
347 - (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
348 {
349     // FIXME: This is always "for interchange". Is that right? See the previous method.
350     Vector<Node*> nodeList;
351     NSString *markupString = createMarkup([range _range], nodes ? &nodeList : 0, AnnotateForInterchange).getNSString();
352     if (nodes)
353         *nodes = [self nodesFromList:&nodeList];
354
355     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
356 }
357
358 - (NSString *)selectedString
359 {
360     String text = m_frame->selectedText();
361     text.replace('\\', m_frame->backslashAsCurrencySymbol());
362     return [[(NSString*)text copy] autorelease];
363 }
364
365 - (NSString *)stringForRange:(DOMRange *)range
366 {
367     String text = plainText([range _range]);
368     text.replace('\\', m_frame->backslashAsCurrencySymbol());
369     return [[(NSString*)text copy] autorelease];
370 }
371
372 - (void)reapplyStylesForDeviceType:(WebCoreDeviceType)deviceType
373 {
374     if (m_frame->view())
375         m_frame->view()->setMediaType(deviceType == WebCoreDeviceScreen ? "screen" : "print");
376     Document *doc = m_frame->document();
377     if (doc)
378         doc->setPrinting(deviceType == WebCoreDevicePrinter);
379     m_frame->reparseConfiguration();
380 }
381
382 - (void)forceLayoutAdjustingViewSize:(BOOL)flag
383 {
384     m_frame->forceLayout(!flag);
385     if (flag)
386         m_frame->view()->adjustViewSize();
387 }
388
389 - (void)forceLayoutWithMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)flag
390 {
391     m_frame->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, flag);
392 }
393
394 - (void)sendResizeEvent
395 {
396     m_frame->sendResizeEvent();
397 }
398
399 - (void)sendScrollEvent
400 {
401     m_frame->sendScrollEvent();
402 }
403
404 - (void)drawRect:(NSRect)rect
405 {
406     PlatformGraphicsContext* platformContext = static_cast<PlatformGraphicsContext*>([[NSGraphicsContext currentContext] graphicsPort]);
407     ASSERT([[NSGraphicsContext currentContext] isFlipped]);
408     GraphicsContext context(platformContext);
409     
410     m_frame->paint(&context, enclosingIntRect(rect));
411 }
412
413 // Used by pagination code called from AppKit when a standalone web page is printed.
414 - (NSArray*)computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight
415 {
416     NSMutableArray* pages = [NSMutableArray arrayWithCapacity:5];
417     if (printWidthScaleFactor <= 0) {
418         LOG_ERROR("printWidthScaleFactor has bad value %.2f", printWidthScaleFactor);
419         return pages;
420     }
421     
422     if (printHeight <= 0) {
423         LOG_ERROR("printHeight has bad value %.2f", printHeight);
424         return pages;
425     }
426
427     if (!m_frame || !m_frame->document() || !m_frame->view()) return pages;
428     RenderView* root = static_cast<RenderView *>(m_frame->document()->renderer());
429     if (!root) return pages;
430     
431     FrameView* view = m_frame->view();
432     if (!view)
433         return pages;
434
435     NSView* documentView = view->getDocumentView();
436     if (!documentView)
437         return pages;
438
439     float currPageHeight = printHeight;
440     float docHeight = root->layer()->height();
441     float docWidth = root->layer()->width();
442     float printWidth = docWidth/printWidthScaleFactor;
443     
444     // We need to give the part the opportunity to adjust the page height at each step.
445     for (float i = 0; i < docHeight; i += currPageHeight) {
446         float proposedBottom = min(docHeight, i + printHeight);
447         m_frame->adjustPageHeight(&proposedBottom, i, proposedBottom, i);
448         currPageHeight = max(1.0f, proposedBottom - i);
449         for (float j = 0; j < docWidth; j += printWidth) {
450             NSValue* val = [NSValue valueWithRect: NSMakeRect(j, i, printWidth, currPageHeight)];
451             [pages addObject: val];
452         }
453     }
454     
455     return pages;
456 }
457
458 // This is to support the case where a webview is embedded in the view that's being printed
459 - (void)adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit
460 {
461     m_frame->adjustPageHeight(newBottom, oldTop, oldBottom, bottomLimit);
462 }
463
464 - (NSObject *)copyRenderNode:(RenderObject *)node copier:(id <WebCoreRenderTreeCopier>)copier
465 {
466     NSMutableArray *children = [[NSMutableArray alloc] init];
467     for (RenderObject *child = node->firstChild(); child; child = child->nextSibling()) {
468         [children addObject:[self copyRenderNode:child copier:copier]];
469     }
470           
471     NSString *name = [[NSString alloc] initWithUTF8String:node->renderName()];
472     
473     RenderWidget* renderWidget = node->isWidget() ? static_cast<RenderWidget*>(node) : 0;
474     Widget* widget = renderWidget ? renderWidget->widget() : 0;
475     NSView *view = widget ? widget->getView() : nil;
476     
477     int nx, ny;
478     node->absolutePosition(nx, ny);
479     NSObject *copiedNode = [copier nodeWithName:name
480                                        position:NSMakePoint(nx,ny)
481                                            rect:NSMakeRect(node->xPos(), node->yPos(), node->width(), node->height())
482                                            view:view
483                                        children:children];
484     
485     [name release];
486     [children release];
487     
488     return copiedNode;
489 }
490
491 - (NSObject *)copyRenderTree:(id <WebCoreRenderTreeCopier>)copier
492 {
493     RenderObject *renderer = m_frame->renderer();
494     if (!renderer) {
495         return nil;
496     }
497     return [self copyRenderNode:renderer copier:copier];
498 }
499
500 - (void)installInFrame:(NSView *)view
501 {
502     // If this isn't the main frame, it must have a render m_frame set, or it
503     // won't ever get installed in the view hierarchy.
504     ASSERT(m_frame == m_frame->page()->mainFrame() || m_frame->ownerElement());
505
506     m_frame->view()->setView(view);
507     // FIXME: frame tries to do this too, is it needed?
508     if (m_frame->ownerRenderer()) {
509         m_frame->ownerRenderer()->setWidget(m_frame->view());
510         // Now the render part owns the view, so we don't any more.
511     }
512
513     m_frame->view()->initScrollbars();
514 }
515
516 static HTMLInputElement* inputElementFromDOMElement(DOMElement* element)
517 {
518     Node* node = [element _node];
519     if (node->hasTagName(inputTag))
520         return static_cast<HTMLInputElement*>(node);
521     return nil;
522 }
523
524 static HTMLFormElement *formElementFromDOMElement(DOMElement *element)
525 {
526     Node *node = [element _node];
527     // This should not be necessary, but an XSL file on
528     // maps.google.com crashes otherwise because it is an xslt file
529     // that contains <form> elements that aren't in any namespace, so
530     // they come out as generic CML elements
531     if (node && node->hasTagName(formTag)) {
532         return static_cast<HTMLFormElement *>(node);
533     }
534     return nil;
535 }
536
537 - (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form
538 {
539     HTMLFormElement *formElement = formElementFromDOMElement(form);
540     if (formElement) {
541         Vector<HTMLGenericFormElement*>& elements = formElement->formElements;
542         AtomicString targetName = name;
543         for (unsigned int i = 0; i < elements.size(); i++) {
544             HTMLGenericFormElement *elt = elements[i];
545             // Skip option elements, other duds
546             if (elt->name() == targetName)
547                 return [DOMElement _wrapElement:elt];
548         }
549     }
550     return nil;
551 }
552
553 - (BOOL)elementDoesAutoComplete:(DOMElement *)element
554 {
555     HTMLInputElement *inputElement = inputElementFromDOMElement(element);
556     return inputElement != nil
557         && inputElement->inputType() == HTMLInputElement::TEXT
558         && inputElement->autoComplete();
559 }
560
561 - (BOOL)elementIsPassword:(DOMElement *)element
562 {
563     HTMLInputElement *inputElement = inputElementFromDOMElement(element);
564     return inputElement != nil
565         && inputElement->inputType() == HTMLInputElement::PASSWORD;
566 }
567
568 - (DOMElement *)formForElement:(DOMElement *)element;
569 {
570     HTMLInputElement *inputElement = inputElementFromDOMElement(element);
571     if (inputElement) {
572         HTMLFormElement *formElement = inputElement->form();
573         if (formElement) {
574             return [DOMElement _wrapElement:formElement];
575         }
576     }
577     return nil;
578 }
579
580 - (DOMElement *)currentForm
581 {
582     return [DOMElement _wrapElement:m_frame->currentForm()];
583 }
584
585 - (NSArray *)controlsInForm:(DOMElement *)form
586 {
587     NSMutableArray *results = nil;
588     HTMLFormElement *formElement = formElementFromDOMElement(form);
589     if (formElement) {
590         Vector<HTMLGenericFormElement*>& elements = formElement->formElements;
591         for (unsigned int i = 0; i < elements.size(); i++) {
592             if (elements.at(i)->isEnumeratable()) { // Skip option elements, other duds
593                 DOMElement *de = [DOMElement _wrapElement:elements.at(i)];
594                 if (!results) {
595                     results = [NSMutableArray arrayWithObject:de];
596                 } else {
597                     [results addObject:de];
598                 }
599             }
600         }
601     }
602     return results;
603 }
604
605 - (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element
606 {
607     return m_frame->searchForLabelsBeforeElement(labels, [element _element]);
608 }
609
610 - (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element
611 {
612     return m_frame->matchLabelsAgainstElement(labels, [element _element]);
613 }
614
615 - (NSURL *)URLWithAttributeString:(NSString *)string
616 {
617     Document *doc = m_frame->document();
618     if (!doc)
619         return nil;
620     // FIXME: is parseURL appropriate here?
621     DeprecatedString rel = parseURL(string).deprecatedString();
622     return KURL(doc->completeURL(rel)).getNSURL();
623 }
624
625 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
626 {
627     return m_frame->findString(string, forward, caseFlag, wrapFlag, startInSelection);
628 }
629
630 - (unsigned)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag limit:(unsigned)limit
631 {
632     return m_frame->markAllMatchesForText(string, caseFlag, limit);
633 }
634
635 - (BOOL)markedTextMatchesAreHighlighted
636 {
637     return m_frame->markedTextMatchesAreHighlighted();
638 }
639
640 - (void)setMarkedTextMatchesAreHighlighted:(BOOL)doHighlight
641 {
642     m_frame->setMarkedTextMatchesAreHighlighted(doHighlight);
643 }
644
645 - (void)unmarkAllTextMatches
646 {
647     Document *doc = m_frame->document();
648     if (!doc) {
649         return;
650     }
651     doc->removeMarkers(DocumentMarker::TextMatch);
652 }
653
654 - (NSArray *)rectsForTextMatches
655 {
656     Document *doc = m_frame->document();
657     if (!doc)
658         return [NSArray array];
659     
660     NSMutableArray *result = [NSMutableArray array];
661     Vector<IntRect> rects = doc->renderedRectsForMarkers(DocumentMarker::TextMatch);
662     unsigned count = rects.size();
663     for (unsigned index = 0; index < count; ++index)
664         [result addObject:[NSValue valueWithRect:rects[index]]];
665     
666     return result;
667 }
668
669 - (void)setTextSizeMultiplier:(float)multiplier
670 {
671     int newZoomFactor = (int)rint(multiplier * 100);
672     if (m_frame->zoomFactor() == newZoomFactor) {
673         return;
674     }
675     m_frame->setZoomFactor(newZoomFactor);
676 }
677
678 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string
679 {
680     return [self stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
681 }
682
683 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
684 {
685     ASSERT(m_frame->document());
686     JSValue* result = m_frame->loader()->executeScript(0, string, forceUserGesture);
687
688     // If the value returned isn't an object, we don't need an ExecState to convert it
689     if (result && !result->isObject()) {
690         JSLock lock;
691
692         if (JSImmediate::isImmediate(result))
693             return String(JSImmediate::toString(result));
694
695         return String(result->getString());
696     }
697     
698     // Return nil if the frame was destroyed by the script
699     if (!m_frame)
700         return nil;
701     
702     JSLock lock;
703     return String(result ? result->toString(m_frame->scriptProxy()->interpreter()->globalExec()) : "");
704 }
705
706 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)string
707 {
708     ASSERT(m_frame->document());
709     ASSERT(m_frame == m_frame->page()->mainFrame());
710     JSValue* result = m_frame->loader()->executeScript(0, string, true);
711     if (!result) // FIXME: pass errors
712         return 0;
713     JSLock lock;
714     return aeDescFromJSValue(m_frame->scriptProxy()->interpreter()->globalExec(), result);
715 }
716
717 - (NSRect)caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
718 {
719     return [node _node]->renderer()->caretRect(offset, static_cast<EAffinity>(affinity));
720 }
721
722 - (NSRect)firstRectForDOMRange:(DOMRange *)range
723 {
724     int extraWidthToEndOfLine = 0;
725     IntRect startCaretRect = [[range startContainer] _node]->renderer()->caretRect([range startOffset], DOWNSTREAM, &extraWidthToEndOfLine);
726     IntRect endCaretRect = [[range endContainer] _node]->renderer()->caretRect([range endOffset], UPSTREAM);
727
728     if (startCaretRect.y() == endCaretRect.y()) {
729         // start and end are on the same line
730         return IntRect(MIN(startCaretRect.x(), endCaretRect.x()), 
731                      startCaretRect.y(), 
732                      abs(endCaretRect.x() - startCaretRect.x()),
733                      MAX(startCaretRect.height(), endCaretRect.height()));
734     }
735
736     // start and end aren't on the same line, so go from start to the end of its line
737     return IntRect(startCaretRect.x(), 
738                  startCaretRect.y(),
739                  startCaretRect.width() + extraWidthToEndOfLine,
740                  startCaretRect.height());
741 }
742
743 - (void)scrollDOMRangeToVisible:(DOMRange *)range
744 {
745     NSRect rangeRect = [self firstRectForDOMRange:range];    
746     Node *startNode = [[range startContainer] _node];
747         
748     if (startNode && startNode->renderer()) {
749         RenderLayer *layer = startNode->renderer()->enclosingLayer();
750         if (layer)
751             layer->scrollRectToVisible(enclosingIntRect(rangeRect), RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignToEdgeIfNeeded);
752     }
753 }
754
755 - (NSURL *)baseURL
756 {
757     return m_frame->loader()->completeURL(m_frame->document()->baseURL()).getNSURL();
758 }
759
760 - (NSString *)stringWithData:(NSData *)data
761 {
762     Document* doc = m_frame->document();
763     if (!doc)
764         return nil;
765     TextResourceDecoder* decoder = doc->decoder();
766     if (!decoder)
767         return nil;
768     return decoder->encoding().decode(reinterpret_cast<const char*>([data bytes]), [data length]);
769 }
770
771 + (NSString *)stringWithData:(NSData *)data textEncodingName:(NSString *)textEncodingName
772 {
773     WebCore::TextEncoding encoding(textEncodingName);
774     if (!encoding.isValid())
775         encoding = WindowsLatin1Encoding();
776     return encoding.decode(reinterpret_cast<const char*>([data bytes]), [data length]);
777 }
778
779 - (BOOL)needsLayout
780 {
781     return m_frame->view() ? m_frame->view()->needsLayout() : false;
782 }
783
784 - (void)setNeedsLayout
785 {
786     if (m_frame->view())
787         m_frame->view()->setNeedsLayout();
788 }
789
790 - (NSString *)renderTreeAsExternalRepresentation
791 {
792     return externalRepresentation(m_frame->renderer()).getNSString();
793 }
794
795 - (void)setShouldCreateRenderers:(BOOL)f
796 {
797     _shouldCreateRenderers = f;
798 }
799
800 - (BOOL)shouldCreateRenderers
801 {
802     return _shouldCreateRenderers;
803 }
804
805 - (NSColor *)selectionColor
806 {
807     return m_frame->isActive() ? [NSColor selectedTextBackgroundColor] : [NSColor secondarySelectedControlColor];
808 }
809
810 - (id)accessibilityTree
811 {
812     AXObjectCache::enableAccessibility();
813     if (!m_frame || !m_frame->document())
814         return nil;
815     RenderView* root = static_cast<RenderView *>(m_frame->document()->renderer());
816     if (!root)
817         return nil;
818     return m_frame->document()->axObjectCache()->get(root);
819 }
820
821 - (void)setBaseBackgroundColor:(NSColor *)backgroundColor
822 {
823     if (m_frame && m_frame->view()) {
824         NSColor *deviceColor = [backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
825         Color color = Color(makeRGBA((int)(255 * [deviceColor redComponent]),
826                                      (int)(255 * [deviceColor blueComponent]),
827                                      (int)(255 * [deviceColor greenComponent]),
828                                      (int)(255 * [deviceColor alphaComponent])));
829         m_frame->view()->setBaseBackgroundColor(color);
830     }
831 }
832
833 - (void)setDrawsBackground:(BOOL)drawsBackground
834 {
835     if (m_frame && m_frame->view())
836         m_frame->view()->setTransparent(!drawsBackground);
837 }
838
839 - (DOMRange *)rangeByAlteringCurrentSelection:(SelectionController::EAlteration)alteration direction:(SelectionController::EDirection)direction granularity:(TextGranularity)granularity
840 {
841     if (m_frame->selectionController()->isNone())
842         return nil;
843
844     // NOTE: The enums *must* match the very similar ones declared in SelectionController.h
845     SelectionController selectionController;
846     selectionController.setSelection(m_frame->selectionController()->selection());
847     selectionController.modify(alteration, direction, granularity);
848     return [DOMRange _wrapRange:selectionController.toRange().get()];
849 }
850
851 - (void)alterCurrentSelection:(SelectionController::EAlteration)alteration verticalDistance:(float)verticalDistance
852 {
853     if (m_frame->selectionController()->isNone())
854         return;
855     SelectionController* selectionController = m_frame->selectionController();
856     selectionController->modify(alteration, static_cast<int>(verticalDistance), true);
857 }
858
859 - (TextGranularity)selectionGranularity
860 {
861     // NOTE: The enums *must* match the very similar ones declared in SelectionController.h
862     return m_frame->selectionGranularity();
863 }
864
865 - (NSRange)convertToNSRange:(Range *)range
866 {
867     int exception = 0;
868
869     if (!range || range->isDetached())
870         return NSMakeRange(NSNotFound, 0);
871
872     Element* selectionRoot = m_frame->selectionController()->rootEditableElement();
873     Element* scope = selectionRoot ? selectionRoot : m_frame->document()->documentElement();
874     
875     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
876     // that is not inside the current editable region.  These checks ensure we don't produce
877     // potentially invalid data when responding to such requests.
878     if (range->startContainer(exception) != scope && !range->startContainer(exception)->isDescendantOf(scope))
879         return NSMakeRange(NSNotFound, 0);
880     if(range->endContainer(exception) != scope && !range->endContainer(exception)->isDescendantOf(scope))
881         return NSMakeRange(NSNotFound, 0);
882     
883     RefPtr<Range> testRange = new Range(scope->document(), scope, 0, range->startContainer(exception), range->startOffset(exception));
884     ASSERT(testRange->startContainer(exception) == scope);
885     int startPosition = TextIterator::rangeLength(testRange.get());
886
887     testRange->setEnd(range->endContainer(exception), range->endOffset(exception), exception);
888     ASSERT(testRange->startContainer(exception) == scope);
889     int endPosition = TextIterator::rangeLength(testRange.get());
890
891     return NSMakeRange(startPosition, endPosition - startPosition);
892 }
893
894 - (PassRefPtr<Range>)convertToDOMRange:(NSRange)nsrange
895 {
896     if (nsrange.location > INT_MAX)
897         return 0;
898     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
899         nsrange.length = INT_MAX - nsrange.location;
900
901     // our critical assumption is that we are only called by input methods that
902     // concentrate on a given area containing the selection
903     // We have to do this because of text fields and textareas. The DOM for those is not
904     // directly in the document DOM, so serialization is problematic. Our solution is
905     // to use the root editable element of the selection start as the positional base.
906     // That fits with AppKit's idea of an input context.
907     Element* selectionRoot = m_frame->selectionController()->rootEditableElement();
908     Element* scope = selectionRoot ? selectionRoot : m_frame->document()->documentElement();
909     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
910 }
911
912 - (DOMRange *)convertNSRangeToDOMRange:(NSRange)nsrange
913 {
914     return [DOMRange _wrapRange:[self convertToDOMRange:nsrange].get()];
915 }
916
917 - (NSRange)convertDOMRangeToNSRange:(DOMRange *)range
918 {
919     return [self convertToNSRange:[range _range]];
920 }
921
922 - (void)selectNSRange:(NSRange)range
923 {
924     RefPtr<Range> domRange = [self convertToDOMRange:range];
925     if (domRange)
926         m_frame->selectionController()->setSelection(Selection(domRange.get(), SEL_DEFAULT_AFFINITY));
927 }
928
929 - (NSRange)selectedNSRange
930 {
931     return [self convertToNSRange:m_frame->selectionController()->toRange().get()];
932 }
933
934 - (void)setMarkDOMRange:(DOMRange *)range
935 {
936     Range* r = [range _range];
937     m_frame->setMark(Selection(startPosition(r), endPosition(r), SEL_DEFAULT_AFFINITY));
938 }
939
940 - (DOMRange *)markDOMRange
941 {
942     return [DOMRange _wrapRange:m_frame->mark().toRange().get()];
943 }
944
945 - (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges
946 {
947     m_frame->setMarkedTextRange([range _range], attributes, ranges);
948 }
949
950 - (DOMRange *)markedTextDOMRange
951 {
952     return [DOMRange _wrapRange:m_frame->markedTextRange()];
953 }
954
955 - (NSRange)markedTextNSRange
956 {
957     return [self convertToNSRange:m_frame->markedTextRange()];
958 }
959
960 - (void)replaceMarkedTextWithText:(NSString *)text
961 {
962     if (m_frame->selectionController()->isNone())
963         return;
964     
965     int exception = 0;
966
967     Range *markedTextRange = m_frame->markedTextRange();
968     if (markedTextRange && !markedTextRange->collapsed(exception))
969         TypingCommand::deleteKeyPressed(m_frame->document(), NO);
970     
971     if ([text length] > 0)
972         TypingCommand::insertText(m_frame->document(), text, YES);
973     
974     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
975 }
976
977 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
978 // be deleted along with the proposed range in order to preserve proper spacing and punctuation of
979 // the text surrounding the deletion.
980 - (DOMRange *)smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
981 {
982     Node *startContainer = [[proposedRange startContainer] _node];
983     Node *endContainer = [[proposedRange endContainer] _node];
984     if (startContainer == nil || endContainer == nil)
985         return nil;
986
987     ASSERT(startContainer->document() == endContainer->document());
988     
989     m_frame->document()->updateLayoutIgnorePendingStylesheets();
990
991     Position start(startContainer, [proposedRange startOffset]);
992     Position end(endContainer, [proposedRange endOffset]);
993     Position newStart = start.upstream().leadingWhitespacePosition(DOWNSTREAM, true);
994     if (newStart.isNull())
995         newStart = start;
996     Position newEnd = end.downstream().trailingWhitespacePosition(DOWNSTREAM, true);
997     if (newEnd.isNull())
998         newEnd = end;
999
1000     RefPtr<Range> range = m_frame->document()->createRange();
1001     int exception = 0;
1002     range->setStart(newStart.node(), newStart.offset(), exception);
1003     range->setEnd(newStart.node(), newStart.offset(), exception);
1004     return [DOMRange _wrapRange:range.get()];
1005 }
1006
1007 // Determines whether whitespace needs to be added around aString to preserve proper spacing and
1008 // punctuation when itÕs inserted into the receiverÕs text over charRange. Returns by reference
1009 // in beforeString and afterString any whitespace that should be added, unless either or both are
1010 // nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
1011 - (void)smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1012 {
1013     // give back nil pointers in case of early returns
1014     if (beforeString)
1015         *beforeString = nil;
1016     if (afterString)
1017         *afterString = nil;
1018         
1019     // inspect destination
1020     Node *startContainer = [[rangeToReplace startContainer] _node];
1021     Node *endContainer = [[rangeToReplace endContainer] _node];
1022
1023     Position startPos(startContainer, [rangeToReplace startOffset]);
1024     Position endPos(endContainer, [rangeToReplace endOffset]);
1025
1026     VisiblePosition startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
1027     VisiblePosition endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY);
1028     
1029     // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
1030     if (startVisiblePos.isNull() || endVisiblePos.isNull())
1031         return;
1032
1033     bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
1034     if (addLeadingSpace)
1035         if (UChar previousChar = startVisiblePos.previous().characterAfter())
1036             addLeadingSpace = !m_frame->isCharacterSmartReplaceExempt(previousChar, true);
1037     
1038     bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
1039     if (addTrailingSpace)
1040         if (UChar thisChar = endVisiblePos.characterAfter())
1041             addTrailingSpace = !m_frame->isCharacterSmartReplaceExempt(thisChar, false);
1042     
1043     // inspect source
1044     bool hasWhitespaceAtStart = false;
1045     bool hasWhitespaceAtEnd = false;
1046     unsigned pasteLength = [pasteString length];
1047     if (pasteLength > 0) {
1048         NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
1049         
1050         if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
1051             hasWhitespaceAtStart = YES;
1052         }
1053         if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
1054             hasWhitespaceAtEnd = YES;
1055         }
1056     }
1057     
1058     // issue the verdict
1059     if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
1060         *beforeString = @" ";
1061     if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
1062         *afterString = @" ";
1063 }
1064
1065 - (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString 
1066 {
1067     if (!m_frame || !m_frame->document())
1068         return 0;
1069
1070     return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromMarkup(m_frame->document(), markupString, baseURLString).get()];
1071 }
1072
1073 - (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text inContext:(DOMRange *)context
1074 {
1075     return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromText([context _range], text).get()];
1076 }
1077
1078 - (DOMDocumentFragment *)documentFragmentWithNodesAsParagraphs:(NSArray *)nodes
1079 {
1080     if (!m_frame || !m_frame->document())
1081         return 0;
1082     
1083     NSEnumerator *nodeEnum = [nodes objectEnumerator];
1084     Vector<Node*> nodesVector;
1085     DOMNode *node;
1086     while ((node = [nodeEnum nextObject]))
1087         nodesVector.append([node _node]);
1088     
1089     return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromNodes(m_frame->document(), nodesVector).get()];
1090 }
1091
1092 - (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1093 {
1094     if (m_frame->selectionController()->isNone() || !fragment)
1095         return;
1096     
1097     applyCommand(new ReplaceSelectionCommand(m_frame->document(), [fragment _documentFragment], selectReplacement, smartReplace, matchStyle));
1098     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1099 }
1100
1101 - (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1102 {
1103     DOMDocumentFragment *fragment = [DOMDocumentFragment _wrapDocumentFragment:m_frame->document()->createDocumentFragment().get()];
1104     [fragment appendChild:node];
1105     [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle];
1106 }
1107
1108 - (void)replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1109 {
1110     DOMDocumentFragment *fragment = [self documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
1111     [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1112 }
1113
1114 - (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1115 {
1116     [self replaceSelectionWithFragment:[self documentFragmentWithText:text
1117         inContext:[DOMRange _wrapRange:m_frame->selectionController()->toRange().get()]]
1118         selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
1119 }
1120
1121 - (void)insertParagraphSeparatorInQuotedContent
1122 {
1123     if (m_frame->selectionController()->isNone())
1124         return;
1125     
1126     TypingCommand::insertParagraphSeparatorInQuotedContent(m_frame->document());
1127     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1128 }
1129
1130 - (void)setSelectionToDragCaret
1131 {
1132     m_frame->selectionController()->setSelection(m_frame->dragCaretController()->selection());
1133 }
1134
1135 - (void)moveSelectionToDragCaret:(DOMDocumentFragment *)selectionFragment smartMove:(BOOL)smartMove
1136 {
1137     applyCommand(new MoveSelectionCommand([selectionFragment _documentFragment], m_frame->dragCaretController()->base(), smartMove));
1138 }
1139
1140 - (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
1141 {
1142     IntPoint outerPoint(point);
1143     HitTestResult result = m_frame->eventHandler()->hitTestResultAtPoint(outerPoint, true);
1144     Node* node = result.innerNode();
1145     if (!node)
1146         return VisiblePosition();
1147     RenderObject* renderer = node->renderer();
1148     if (!renderer)
1149         return VisiblePosition();
1150     VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y());
1151     if (visiblePos.isNull())
1152         visiblePos = VisiblePosition(Position(node, 0));
1153     return visiblePos;
1154 }
1155
1156 - (void)moveDragCaretToPoint:(NSPoint)point
1157 {   
1158     Selection dragCaret([self _visiblePositionForPoint:point]);
1159     m_frame->dragCaretController()->setSelection(dragCaret);
1160 }
1161
1162 - (DOMRange *)dragCaretDOMRange
1163 {
1164     return [DOMRange _wrapRange:m_frame->dragCaretController()->toRange().get()];
1165 }
1166
1167 - (BOOL)isDragCaretRichlyEditable
1168 {
1169     return m_frame->dragCaretController()->isContentRichlyEditable();
1170 }
1171
1172 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
1173 {
1174     VisiblePosition position = [self _visiblePositionForPoint:point];
1175     return position.isNull() ? nil : [DOMRange _wrapRange:Selection(position).toRange().get()];
1176 }
1177
1178 - (DOMRange *)characterRangeAtPoint:(NSPoint)point
1179 {
1180     VisiblePosition position = [self _visiblePositionForPoint:point];
1181     if (position.isNull())
1182         return nil;
1183     
1184     VisiblePosition previous = position.previous();
1185     if (previous.isNotNull()) {
1186         DOMRange *previousCharacterRange = [DOMRange _wrapRange:makeRange(previous, position).get()];
1187         NSRect rect = [self firstRectForDOMRange:previousCharacterRange];
1188         if (NSPointInRect(point, rect))
1189             return previousCharacterRange;
1190     }
1191
1192     VisiblePosition next = position.next();
1193     if (next.isNotNull()) {
1194         DOMRange *nextCharacterRange = [DOMRange _wrapRange:makeRange(position, next).get()];
1195         NSRect rect = [self firstRectForDOMRange:nextCharacterRange];
1196         if (NSPointInRect(point, rect))
1197             return nextCharacterRange;
1198     }
1199     
1200     return nil;
1201 }
1202
1203 - (void)deleteKeyPressedWithSmartDelete:(BOOL)smartDelete granularity:(TextGranularity)granularity
1204 {
1205     if (!m_frame || !m_frame->document())
1206         return;
1207     
1208     TypingCommand::deleteKeyPressed(m_frame->document(), smartDelete, granularity);
1209     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1210 }
1211
1212 - (void)forwardDeleteKeyPressedWithSmartDelete:(BOOL)smartDelete granularity:(TextGranularity)granularity
1213 {
1214     if (!m_frame || !m_frame->document())
1215         return;
1216     
1217     TypingCommand::forwardDeleteKeyPressed(m_frame->document(), smartDelete, granularity);
1218     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1219 }
1220
1221 - (DOMCSSStyleDeclaration *)typingStyle
1222 {
1223     if (!m_frame || !m_frame->typingStyle())
1224         return nil;
1225     return [DOMCSSStyleDeclaration _wrapCSSStyleDeclaration:m_frame->typingStyle()->copy().get()];
1226 }
1227
1228 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
1229 {
1230     if (!m_frame)
1231         return;
1232     m_frame->computeAndSetTypingStyle([style _CSSStyleDeclaration], undoAction);
1233 }
1234
1235 - (NSCellStateValue)selectionHasStyle:(DOMCSSStyleDeclaration *)style
1236 {
1237     if (!m_frame)
1238         return NSOffState;
1239     switch (m_frame->selectionHasStyle([style _CSSStyleDeclaration])) {
1240         case Frame::falseTriState:
1241             return NSOffState;
1242         case Frame::trueTriState:
1243             return NSOnState;
1244         case Frame::mixedTriState:
1245             return NSMixedState;
1246     }
1247     return NSOffState;
1248 }
1249
1250 - (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts
1251 {
1252     bool multipleFonts = false;
1253     NSFont *font = nil;
1254     if (m_frame) {
1255         const FontData* fd = m_frame->editor()->fontForSelection(multipleFonts);
1256         if (fd)
1257             font = fd->getNSFont();
1258     }
1259     
1260     if (hasMultipleFonts)
1261         *hasMultipleFonts = multipleFonts;
1262     return font;
1263 }
1264
1265 - (NSWritingDirection)baseWritingDirectionForSelectionStart
1266 {
1267     return m_frame ? m_frame->baseWritingDirectionForSelectionStart() : (NSWritingDirection)NSWritingDirectionLeftToRight;
1268 }
1269
1270 - (void)dragSourceMovedTo:(NSPoint)windowLoc
1271 {
1272     if (m_frame) {
1273         // FIXME: Fake modifier keys here.
1274         PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [self window]),
1275             LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());
1276         m_frame->eventHandler()->dragSourceMovedTo(event);
1277     }
1278 }
1279
1280 - (void)dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
1281 {
1282     if (m_frame) {
1283         // FIXME: Fake modifier keys here.
1284         PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [self window]),
1285             LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());
1286         m_frame->eventHandler()->dragSourceEndedAt(event, (DragOperation)operation);
1287     }
1288 }
1289
1290 - (DOMRange *)rangeOfCharactersAroundCaret
1291 {
1292     if (!m_frame)
1293         return nil;
1294         
1295     Selection selection(m_frame->selectionController()->selection());
1296     if (!selection.isCaret())
1297         return nil;
1298
1299     VisiblePosition caret(selection.visibleStart());
1300     VisiblePosition next = caret.next();
1301     VisiblePosition previous = caret.previous();
1302     if (previous.isNull() || next.isNull() || caret == next || caret == previous)
1303         return nil;
1304
1305     return [DOMRange _wrapRange:makeRange(previous, next).get()];
1306 }
1307
1308 // FIXME: The following 2 functions are copied from AppKit. It would be best to share code.
1309
1310 // MF:!!! For now we will use static character sets for the computation, but we should eventually probably make these keys in the language dictionaries.
1311 // MF:!!! The following characters (listed with their nextstep encoding values) were in the preSmartTable in the old text objet, but aren't yet in the new text object: NS_FIGSPACE (0x80), exclamdown (0xa1), sterling (0xa3), yen (0xa5), florin (0xa6) section (0xa7), currency (0xa8), quotesingle (0xa9), quotedblleft (0xaa), guillemotleft (0xab), guilsinglleft (0xac), endash (0xb1), quotesinglbase (0xb8), quotedblbase (0xb9), questiondown (0xbf), emdash (0xd0), plusminus (0xd1).
1312 // MF:!!! The following characters (listed with their nextstep encoding values) were in the postSmartTable in the old text objet, but aren't yet in the new text object: NS_FIGSPACE (0x80), cent (0xa2), guilsinglright (0xad), registered (0xb0), dagger (0xa2), daggerdbl (0xa3), endash (0xb1), quotedblright (0xba), guillemotright (0xbb), perthousand (0xbd), onesuperior (0xc0), twosuperior (0xc9), threesuperior (0xcc), emdash (0xd0), ordfeminine (0xe3), ordmasculine (0xeb).
1313 // MF:!!! Another difference in both of these sets from the old text object is we include all the whitespace in whitespaceAndNewlineCharacterSet.
1314 #define _preSmartString @"([\"\'#$/-`{"
1315 #define _postSmartString @")].,;:?\'!\"%*-/}"
1316
1317 static NSCharacterSet *_getPreSmartSet(void)
1318 {
1319     static RetainPtr<NSMutableCharacterSet> _preSmartSet = nil;
1320     if (!_preSmartSet) {
1321         _preSmartSet = [[NSMutableCharacterSet characterSetWithCharactersInString:_preSmartString] retain];
1322         [_preSmartSet.get() formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
1323         // Adding CJK ranges
1324         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0x1100, 256)]; // Hangul Jamo (0x1100 - 0x11FF)
1325         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0x2E80, 352)]; // CJK & Kangxi Radicals (0x2E80 - 0x2FDF)
1326         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0x2FF0, 464)]; // Ideograph Descriptions, CJK Symbols, Hiragana, Katakana, Bopomofo, Hangul Compatibility Jamo, Kanbun, & Bopomofo Ext (0x2FF0 - 0x31BF)
1327         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0x3200, 29392)]; // Enclosed CJK, CJK Ideographs (Uni Han & Ext A), & Yi (0x3200 - 0xA4CF)
1328         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0xAC00, 11183)]; // Hangul Syllables (0xAC00 - 0xD7AF)
1329         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0xF900, 352)]; // CJK Compatibility Ideographs (0xF900 - 0xFA5F)
1330         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0xFE30, 32)]; // CJK Compatibility From (0xFE30 - 0xFE4F)
1331         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0xFF00, 240)]; // Half/Full Width Form (0xFF00 - 0xFFEF)
1332         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0x20000, 0xA6D7)]; // CJK Ideograph Exntension B
1333         [_preSmartSet.get() addCharactersInRange:NSMakeRange(0x2F800, 0x021E)]; // CJK Compatibility Ideographs (0x2F800 - 0x2FA1D)
1334     }
1335     return _preSmartSet.get();
1336 }
1337
1338 static NSCharacterSet *_getPostSmartSet(void)
1339 {
1340     static RetainPtr<NSMutableCharacterSet> _postSmartSet = nil;
1341     if (!_postSmartSet) {
1342         _postSmartSet = [[NSMutableCharacterSet characterSetWithCharactersInString:_postSmartString] retain];
1343         [_postSmartSet.get() formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
1344         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0x1100, 256)]; // Hangul Jamo (0x1100 - 0x11FF)
1345         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0x2E80, 352)]; // CJK & Kangxi Radicals (0x2E80 - 0x2FDF)
1346         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0x2FF0, 464)]; // Ideograph Descriptions, CJK Symbols, Hiragana, Katakana, Bopomofo, Hangul Compatibility Jamo, Kanbun, & Bopomofo Ext (0x2FF0 - 0x31BF)
1347         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0x3200, 29392)]; // Enclosed CJK, CJK Ideographs (Uni Han & Ext A), & Yi (0x3200 - 0xA4CF)
1348         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0xAC00, 11183)]; // Hangul Syllables (0xAC00 - 0xD7AF)
1349         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0xF900, 352)]; // CJK Compatibility Ideographs (0xF900 - 0xFA5F)
1350         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0xFE30, 32)]; // CJK Compatibility From (0xFE30 - 0xFE4F)
1351         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0xFF00, 240)]; // Half/Full Width Form (0xFF00 - 0xFFEF)
1352         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0x20000, 0xA6D7)]; // CJK Ideograph Exntension B
1353         [_postSmartSet.get() addCharactersInRange:NSMakeRange(0x2F800, 0x021E)]; // CJK Compatibility Ideographs (0x2F800 - 0x2FA1D)        
1354         [_postSmartSet.get() formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
1355     }
1356     return _postSmartSet.get();
1357 }
1358
1359 - (BOOL)isCharacterSmartReplaceExempt:(unichar)c isPreviousCharacter:(BOOL)isPreviousCharacter
1360 {
1361     return [isPreviousCharacter ? _getPreSmartSet() : _getPostSmartSet() characterIsMember:c];
1362 }
1363
1364 - (BOOL)getData:(NSData **)data andResponse:(NSURLResponse **)response forURL:(NSString *)URL
1365 {
1366     Document* doc = m_frame->document();
1367     if (!doc)
1368         return NO;
1369
1370     CachedResource* resource = doc->docLoader()->cachedResource(URL);
1371     if (!resource)
1372         return NO;
1373
1374     SharedBuffer* buffer = resource->data();
1375     if (buffer)
1376         *data = [buffer->createNSData() autorelease];
1377     else
1378         *data = nil;
1379
1380     *response = resource->response().nsURLResponse();
1381     return YES;
1382 }
1383
1384 - (void)getAllResourceDatas:(NSArray **)datas andResponses:(NSArray **)responses
1385 {
1386     Document* doc = m_frame->document();
1387     if (!doc) {
1388         NSArray* emptyArray = [NSArray array];
1389         *datas = emptyArray;
1390         *responses = emptyArray;
1391         return;
1392     }
1393
1394     const HashMap<String, CachedResource*>& allResources = doc->docLoader()->allCachedResources();
1395
1396     NSMutableArray *d = [[NSMutableArray alloc] initWithCapacity:allResources.size()];
1397     NSMutableArray *r = [[NSMutableArray alloc] initWithCapacity:allResources.size()];
1398
1399     HashMap<String, CachedResource*>::const_iterator end = allResources.end();
1400     for (HashMap<String, CachedResource*>::const_iterator it = allResources.begin(); it != end; ++it) {
1401         SharedBuffer* buffer = it->second->data();
1402         NSData *data;
1403         
1404         if (buffer)
1405             data = buffer->createNSData();
1406         else
1407             data = nil;
1408         
1409         // It's clearly a bug to pass a nil value for data here, and doing so is part of the problem in
1410         // <rdar://problem/5268311>. However, fixing this in the obvious ways makes the symptom in 5268311
1411         // worse, so don't just fix this without investigating that bug further.
1412         [d addObject:data];
1413         [data release];
1414         [r addObject:it->second->response().nsURLResponse()];
1415     }
1416
1417     *datas = [d autorelease];
1418     *responses = [r autorelease];
1419 }
1420
1421 - (BOOL)canProvideDocumentSource
1422 {
1423     String mimeType = m_frame->loader()->responseMIMEType();
1424     
1425     if (WebCore::DOMImplementation::isTextMIMEType(mimeType) ||
1426         Image::supportsType(mimeType) ||
1427         PlugInInfoStore::supportsMIMEType(mimeType))
1428         return NO;
1429     
1430     return YES;
1431 }
1432
1433 - (BOOL)canSaveAsWebArchive
1434 {
1435     // Currently, all documents that we can view source for
1436     // (HTML and XML documents) can also be saved as web archives
1437     return [self canProvideDocumentSource];
1438 }
1439
1440 - (void)receivedData:(NSData *)data textEncodingName:(NSString *)textEncodingName
1441 {
1442     // Set the encoding. This only needs to be done once, but it's harmless to do it again later.
1443     String encoding;
1444     if (m_frame)
1445         encoding = m_frame->loader()->documentLoader()->overrideEncoding();
1446     bool userChosen = !encoding.isNull();
1447     if (encoding.isNull())
1448         encoding = textEncodingName;
1449     m_frame->loader()->setEncoding(encoding, userChosen);
1450     [self addData:data];
1451 }
1452
1453 // -------------------
1454
1455 - (Frame*)_frame
1456 {
1457     return m_frame;
1458 }
1459
1460 @end