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