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