2010-09-08 MORITA Hajime <morrita@google.com>
[WebKit.git] / WebKit / mac / WebView / WebFrame.mm
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebFrameInternal.h"
30
31 #import "DOMCSSStyleDeclarationInternal.h"
32 #import "DOMDocumentFragmentInternal.h"
33 #import "DOMDocumentInternal.h"
34 #import "DOMElementInternal.h"
35 #import "DOMHTMLElementInternal.h"
36 #import "DOMNodeInternal.h"
37 #import "DOMRangeInternal.h"
38 #import "WebArchiveInternal.h"
39 #import "WebChromeClient.h"
40 #import "WebDataSourceInternal.h"
41 #import "WebDocumentLoaderMac.h"
42 #import "WebDynamicScrollBarsView.h"
43 #import "WebFrameLoaderClient.h"
44 #import "WebFrameViewInternal.h"
45 #import "WebHTMLView.h"
46 #import "WebHTMLViewInternal.h"
47 #import "WebIconFetcherInternal.h"
48 #import "WebKitStatisticsPrivate.h"
49 #import "WebKitVersionChecks.h"
50 #import "WebNSObjectExtras.h"
51 #import "WebNSURLExtras.h"
52 #import "WebScriptDebugger.h"
53 #import "WebScriptWorldInternal.h"
54 #import "WebViewInternal.h"
55 #import <JavaScriptCore/APICast.h>
56 #import <WebCore/AXObjectCache.h>
57 #import <WebCore/AccessibilityObject.h>
58 #import <WebCore/AnimationController.h>
59 #import <WebCore/CSSMutableStyleDeclaration.h>
60 #import <WebCore/Chrome.h>
61 #import <WebCore/ColorMac.h>
62 #import <WebCore/DOMImplementation.h>
63 #import <WebCore/CachedResourceLoader.h>
64 #import <WebCore/DocumentFragment.h>
65 #import <WebCore/EventHandler.h>
66 #import <WebCore/EventNames.h>
67 #import <WebCore/Frame.h>
68 #import <WebCore/FrameLoader.h>
69 #import <WebCore/FrameLoaderStateMachine.h>
70 #import <WebCore/FrameTree.h>
71 #import <WebCore/GraphicsContext.h>
72 #import <WebCore/HTMLFrameOwnerElement.h>
73 #import <WebCore/HistoryItem.h>
74 #import <WebCore/HitTestResult.h>
75 #import <WebCore/LegacyWebArchive.h>
76 #import <WebCore/Page.h>
77 #import <WebCore/PluginData.h>
78 #import <WebCore/PrintContext.h>
79 #import <WebCore/RenderLayer.h>
80 #import <WebCore/RenderPart.h>
81 #import <WebCore/RenderView.h>
82 #import <WebCore/ReplaceSelectionCommand.h>
83 #import <WebCore/RuntimeApplicationChecks.h>
84 #import <WebCore/ScriptValue.h>
85 #import <WebCore/SmartReplace.h>
86 #import <WebCore/SVGSMILElement.h>
87 #import <WebCore/TextIterator.h>
88 #import <WebCore/ThreadCheck.h>
89 #import <WebCore/TypingCommand.h>
90 #import <WebCore/htmlediting.h>
91 #import <WebCore/markup.h>
92 #import <WebCore/visible_units.h>
93 #import <WebKitSystemInterface.h>
94 #import <runtime/JSLock.h>
95 #import <runtime/JSObject.h>
96 #import <runtime/JSValue.h>
97 #import <wtf/CurrentTime.h>
98
99 using namespace std;
100 using namespace WebCore;
101 using namespace HTMLNames;
102
103 using JSC::JSGlobalObject;
104 using JSC::JSLock;
105 using JSC::JSValue;
106 using JSC::SilenceAssertionsOnly;
107
108 /*
109 Here is the current behavior matrix for four types of navigations:
110
111 Standard Nav:
112
113  Restore form state:   YES
114  Restore scroll and focus state:  YES
115  Cache policy: NSURLRequestUseProtocolCachePolicy
116  Add to back/forward list: YES
117  
118 Back/Forward:
119
120  Restore form state:   YES
121  Restore scroll and focus state:  YES
122  Cache policy: NSURLRequestReturnCacheDataElseLoad
123  Add to back/forward list: NO
124
125 Reload (meaning only the reload button):
126
127  Restore form state:   NO
128  Restore scroll and focus state:  YES
129  Cache policy: NSURLRequestReloadIgnoringCacheData
130  Add to back/forward list: NO
131
132 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
133
134  Restore form state:   NO
135  Restore scroll and focus state:  NO, reset to initial conditions
136  Cache policy: NSURLRequestReloadIgnoringCacheData
137  Add to back/forward list: NO
138 */
139
140 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
141 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
142 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
143
144 NSString *WebFrameMainDocumentError = @"WebFrameMainDocumentErrorKey";
145 NSString *WebFrameHasPlugins = @"WebFrameHasPluginsKey";
146 NSString *WebFrameHasUnloadListener = @"WebFrameHasUnloadListenerKey";
147 NSString *WebFrameUsesDatabases = @"WebFrameUsesDatabasesKey";
148 NSString *WebFrameUsesGeolocation = @"WebFrameUsesGeolocationKey";
149 NSString *WebFrameUsesApplicationCache = @"WebFrameUsesApplicationCacheKey";
150 NSString *WebFrameCanSuspendActiveDOMObjects = @"WebFrameCanSuspendActiveDOMObjectsKey";
151
152 // FIXME: Remove when this key becomes publicly defined
153 NSString *NSAccessibilityEnhancedUserInterfaceAttribute = @"AXEnhancedUserInterface";
154
155 @implementation WebFramePrivate
156
157 - (void)dealloc
158 {
159     [webFrameView release];
160
161     delete scriptDebugger;
162
163     [super dealloc];
164 }
165
166 - (void)finalize
167 {
168     delete scriptDebugger;
169
170     [super finalize];
171 }
172
173 - (void)setWebFrameView:(WebFrameView *)v 
174
175     [v retain];
176     [webFrameView release];
177     webFrameView = v;
178 }
179
180 @end
181
182 EditableLinkBehavior core(WebKitEditableLinkBehavior editableLinkBehavior)
183 {
184     switch (editableLinkBehavior) {
185         case WebKitEditableLinkDefaultBehavior:
186             return EditableLinkDefaultBehavior;
187         case WebKitEditableLinkAlwaysLive:
188             return EditableLinkAlwaysLive;
189         case WebKitEditableLinkOnlyLiveWithShiftKey:
190             return EditableLinkOnlyLiveWithShiftKey;
191         case WebKitEditableLinkLiveWhenNotFocused:
192             return EditableLinkLiveWhenNotFocused;
193         case WebKitEditableLinkNeverLive:
194             return EditableLinkNeverLive;
195     }
196     ASSERT_NOT_REACHED();
197     return EditableLinkDefaultBehavior;
198 }
199
200 WebCore::EditingBehaviorType core(WebKitEditingBehavior behavior)
201 {
202     switch (behavior) {
203         case WebKitEditingMacBehavior:
204             return WebCore::EditingMacBehavior;
205         case WebKitEditingWinBehavior:
206             return WebCore::EditingWindowsBehavior;
207     }
208     ASSERT_NOT_REACHED();
209     return WebCore::EditingMacBehavior;
210 }
211
212 TextDirectionSubmenuInclusionBehavior core(WebTextDirectionSubmenuInclusionBehavior behavior)
213 {
214     switch (behavior) {
215         case WebTextDirectionSubmenuNeverIncluded:
216             return TextDirectionSubmenuNeverIncluded;
217         case WebTextDirectionSubmenuAutomaticallyIncluded:
218             return TextDirectionSubmenuAutomaticallyIncluded;
219         case WebTextDirectionSubmenuAlwaysIncluded:
220             return TextDirectionSubmenuAlwaysIncluded;
221     }
222     ASSERT_NOT_REACHED();
223     return TextDirectionSubmenuNeverIncluded;
224 }
225
226 @implementation WebFrame (WebInternal)
227
228 Frame* core(WebFrame *frame)
229 {
230     return frame ? frame->_private->coreFrame : 0;
231 }
232
233 WebFrame *kit(Frame* frame)
234 {
235     return frame ? static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame() : nil;
236 }
237
238 Page* core(WebView *webView)
239 {
240     return [webView page];
241 }
242
243 WebView *kit(Page* page)
244 {
245     return page ? static_cast<WebChromeClient*>(page->chrome()->client())->webView() : nil;
246 }
247
248 WebView *getWebView(WebFrame *webFrame)
249 {
250     Frame* coreFrame = core(webFrame);
251     if (!coreFrame)
252         return nil;
253     return kit(coreFrame->page());
254 }
255
256 + (PassRefPtr<Frame>)_createFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView ownerElement:(HTMLFrameOwnerElement*)ownerElement
257 {
258     WebView *webView = kit(page);
259
260     WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
261     RefPtr<Frame> coreFrame = Frame::create(page, ownerElement, new WebFrameLoaderClient(frame));
262     [frame release];
263     frame->_private->coreFrame = coreFrame.get();
264
265     coreFrame->tree()->setName(name);
266     if (ownerElement) {
267         ASSERT(ownerElement->document()->frame());
268         ownerElement->document()->frame()->tree()->appendChild(coreFrame.get());
269     }
270
271     coreFrame->init();
272
273     [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
274
275     return coreFrame.release();
276 }
277
278 + (void)_createMainFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView
279 {
280     [self _createFrameWithPage:page frameName:name frameView:frameView ownerElement:0];
281 }
282
283 + (PassRefPtr<WebCore::Frame>)_createSubframeWithOwnerElement:(HTMLFrameOwnerElement*)ownerElement frameName:(const String&)name frameView:(WebFrameView *)frameView
284 {
285     return [self _createFrameWithPage:ownerElement->document()->frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
286 }
287
288 - (BOOL)_isIncludedInWebKitStatistics
289 {
290     return _private && _private->includedInWebKitStatistics;
291 }
292
293 - (void)_attachScriptDebugger
294 {
295     ScriptController* scriptController = _private->coreFrame->script();
296
297     // Calling ScriptController::globalObject() would create a window shell, and dispatch corresponding callbacks, which may be premature
298     // if the script debugger is attached before a document is created.  These calls use the debuggerWorld(), we will need to pass a world
299     // to be able to debug isolated worlds.
300     if (!scriptController->existingWindowShell(debuggerWorld()))
301         return;
302
303     JSGlobalObject* globalObject = scriptController->globalObject(debuggerWorld());
304     if (!globalObject)
305         return;
306
307     if (_private->scriptDebugger) {
308         ASSERT(_private->scriptDebugger == globalObject->debugger());
309         return;
310     }
311
312     _private->scriptDebugger = new WebScriptDebugger(globalObject);
313 }
314
315 - (void)_detachScriptDebugger
316 {
317     if (!_private->scriptDebugger)
318         return;
319
320     delete _private->scriptDebugger;
321     _private->scriptDebugger = 0;
322 }
323
324 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v
325 {
326     self = [super init];
327     if (!self)
328         return nil;
329
330     _private = [[WebFramePrivate alloc] init];
331
332     // Set includedInWebKitStatistics before calling WebFrameView _setWebFrame, since
333     // it calls WebFrame _isIncludedInWebKitStatistics.
334     if ((_private->includedInWebKitStatistics = [[v class] shouldIncludeInWebKitStatistics]))
335         ++WebFrameCount;
336
337     if (fv) {
338         [_private setWebFrameView:fv];
339         [fv _setWebFrame:self];
340     }
341
342     _private->shouldCreateRenderers = YES;
343
344     return self;
345 }
346
347 - (void)_clearCoreFrame
348 {
349     _private->coreFrame = 0;
350 }
351
352 - (void)_updateBackgroundAndUpdatesWhileOffscreen
353 {
354     WebView *webView = getWebView(self);
355     BOOL drawsBackground = [webView drawsBackground];
356     NSColor *backgroundColor = [webView backgroundColor];
357
358     Frame* coreFrame = _private->coreFrame;
359     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
360         if ([webView _usesDocumentViews]) {
361             // Don't call setDrawsBackground:YES here because it may be NO because of a load
362             // in progress; WebFrameLoaderClient keeps it set to NO during the load process.
363             WebFrame *webFrame = kit(frame);
364             if (!drawsBackground)
365                 [[[webFrame frameView] _scrollView] setDrawsBackground:NO];
366             [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor];
367             id documentView = [[webFrame frameView] documentView];
368             if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
369                 [documentView setDrawsBackground:drawsBackground];
370             if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
371                 [documentView setBackgroundColor:backgroundColor];
372         }
373
374         if (FrameView* view = frame->view()) {
375             view->setTransparent(!drawsBackground);
376             view->setBaseBackgroundColor(colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
377             view->setShouldUpdateWhileOffscreen([webView shouldUpdateWhileOffscreen]);
378         }
379     }
380 }
381
382 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
383 {
384     _private->internalLoadDelegate = internalLoadDelegate;
385 }
386
387 - (id)_internalLoadDelegate
388 {
389     return _private->internalLoadDelegate;
390 }
391
392 #ifndef BUILDING_ON_TIGER
393 - (void)_unmarkAllBadGrammar
394 {
395     Frame* coreFrame = _private->coreFrame;
396     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
397         if (Document* document = frame->document())
398             document->markers()->removeMarkers(DocumentMarker::Grammar);
399     }
400 }
401 #endif
402
403 - (void)_unmarkAllMisspellings
404 {
405     Frame* coreFrame = _private->coreFrame;
406     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
407         if (Document* document = frame->document())
408             document->markers()->removeMarkers(DocumentMarker::Spelling);
409     }
410 }
411
412 - (BOOL)_hasSelection
413 {
414     if ([getWebView(self) _usesDocumentViews]) {
415         id documentView = [_private->webFrameView documentView];    
416
417         // optimization for common case to avoid creating potentially large selection string
418         if ([documentView isKindOfClass:[WebHTMLView class]])
419             if (Frame* coreFrame = _private->coreFrame)
420                 return coreFrame->selection()->isRange();
421
422         if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
423             return [[documentView selectedString] length] > 0;
424         
425         return NO;
426     }
427
428     Frame* coreFrame = _private->coreFrame;
429     return coreFrame && coreFrame->selection()->isRange();
430 }
431
432 - (void)_clearSelection
433 {
434     ASSERT([getWebView(self) _usesDocumentViews]);
435     id documentView = [_private->webFrameView documentView];    
436     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
437         [documentView deselectAll];
438 }
439
440 #if !ASSERT_DISABLED
441 - (BOOL)_atMostOneFrameHasSelection
442 {
443     // FIXME: 4186050 is one known case that makes this debug check fail.
444     BOOL found = NO;
445     Frame* coreFrame = _private->coreFrame;
446     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
447         if ([kit(frame) _hasSelection]) {
448             if (found)
449                 return NO;
450             found = YES;
451         }
452     return YES;
453 }
454 #endif
455
456 - (WebFrame *)_findFrameWithSelection
457 {
458     Frame* coreFrame = _private->coreFrame;
459     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
460         WebFrame *webFrame = kit(frame);
461         if ([webFrame _hasSelection])
462             return webFrame;
463     }
464     return nil;
465 }
466
467 - (void)_clearSelectionInOtherFrames
468 {
469     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
470     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
471     // notification sent when the first responder changes in general (Radar 2573089).
472     WebFrame *frameWithSelection = [[getWebView(self) mainFrame] _findFrameWithSelection];
473     if (frameWithSelection != self)
474         [frameWithSelection _clearSelection];
475
476     // While we're in the general area of selection and frames, check that there is only one now.
477     ASSERT([[getWebView(self) mainFrame] _atMostOneFrameHasSelection]);
478 }
479
480 static inline WebDataSource *dataSource(DocumentLoader* loader)
481 {
482     return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil;
483 }
484
485 - (WebDataSource *)_dataSource
486 {
487     return dataSource(_private->coreFrame->loader()->documentLoader());
488 }
489
490 - (void)_addData:(NSData *)data
491 {
492     Document* document = _private->coreFrame->document();
493     
494     // Document may be nil if the part is about to redirect
495     // as a result of JS executing during load, i.e. one frame
496     // changing another's location before the frame's document
497     // has been created. 
498     if (!document)
499         return;
500
501     document->setShouldCreateRenderers(_private->shouldCreateRenderers);
502     _private->coreFrame->loader()->addData((const char *)[data bytes], [data length]);
503 }
504
505 - (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString
506 {
507     return _private->coreFrame->documentTypeString() + markupString;
508 }
509
510 - (NSArray *)_nodesFromList:(Vector<Node*> *)nodesVector
511 {
512     size_t size = nodesVector->size();
513     NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size];
514     for (size_t i = 0; i < size; ++i)
515         [nodes addObject:kit((*nodesVector)[i])];
516     return nodes;
517 }
518
519 - (NSString *)_markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
520 {
521     // FIXME: This is always "for interchange". Is that right? See the previous method.
522     Vector<Node*> nodeList;
523     NSString *markupString = createMarkup(core(range), nodes ? &nodeList : 0, AnnotateForInterchange);
524     if (nodes)
525         *nodes = [self _nodesFromList:&nodeList];
526
527     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
528 }
529
530 - (NSString *)_selectedString
531 {
532     return _private->coreFrame->displayStringModifiedByEncoding(_private->coreFrame->selectedText());
533 }
534
535 - (NSString *)_stringForRange:(DOMRange *)range
536 {
537     // This will give a system malloc'd buffer that can be turned directly into an NSString
538     unsigned length;
539     UChar* buf = plainTextToMallocAllocatedBuffer(core(range), length, true);
540     
541     if (!buf)
542         return [NSString string];
543
544     // Transfer buffer ownership to NSString
545     return [[[NSString alloc] initWithCharactersNoCopy:buf length:length freeWhenDone:YES] autorelease];
546 }
547
548 - (void)_drawRect:(NSRect)rect contentsOnly:(BOOL)contentsOnly
549 {
550     ASSERT([[NSGraphicsContext currentContext] isFlipped]);
551
552     CGContextRef ctx = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
553     GraphicsContext context(ctx);
554
555     FrameView* view = _private->coreFrame->view();
556     
557     bool shouldFlatten = false;
558     if (Frame* parentFrame = _private->coreFrame->tree()->parent()) {
559         // For subframes, we need to inherit the paint behavior from our parent
560         FrameView* parentView = parentFrame ? parentFrame->view() : 0;
561         if (parentView)
562             shouldFlatten = parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
563     } else
564         shouldFlatten = WKCGContextIsBitmapContext(ctx) && [getWebView(self) _includesFlattenedCompositingLayersWhenDrawingToBitmap];
565
566     PaintBehavior oldBehavior = PaintBehaviorNormal;
567     if (shouldFlatten) {
568         oldBehavior = view->paintBehavior();
569         view->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
570     }
571     
572     if (contentsOnly)
573         _private->coreFrame->view()->paintContents(&context, enclosingIntRect(rect));
574     else
575         _private->coreFrame->view()->paint(&context, enclosingIntRect(rect));
576
577     if (shouldFlatten)
578         view->setPaintBehavior(oldBehavior);
579 }
580
581 // Used by pagination code called from AppKit when a standalone web page is printed.
582 - (NSArray*)_computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight
583 {
584     NSMutableArray* pages = [NSMutableArray arrayWithCapacity:5];
585     if (printWidthScaleFactor <= 0) {
586         LOG_ERROR("printWidthScaleFactor has bad value %.2f", printWidthScaleFactor);
587         return pages;
588     }
589     
590     if (printHeight <= 0) {
591         LOG_ERROR("printHeight has bad value %.2f", printHeight);
592         return pages;
593     }
594
595     if (!_private->coreFrame || !_private->coreFrame->document() || !_private->coreFrame->view()) return pages;
596     RenderView* root = toRenderView(_private->coreFrame->document()->renderer());
597     if (!root) return pages;
598     
599     FrameView* view = _private->coreFrame->view();
600     if (!view)
601         return pages;
602
603     NSView* documentView = view->documentView();
604     if (!documentView)
605         return pages;
606
607     float docWidth = root->layer()->width();
608     float printWidth = docWidth / printWidthScaleFactor;
609
610     PrintContext printContext(_private->coreFrame);
611     printContext.computePageRectsWithPageSize(FloatSize(printWidth, printHeight), true);
612
613     const Vector<IntRect>& pageRects = printContext.pageRects();
614     const size_t pageCount = pageRects.size();
615     for (size_t pageNumber = 0; pageNumber < pageCount; ++pageNumber)
616         [pages addObject: [NSValue valueWithRect: NSRect(pageRects[pageNumber])]];
617     return pages;
618 }
619
620 - (BOOL)_getVisibleRect:(NSRect*)rect
621 {
622     ASSERT_ARG(rect, rect);
623     if (RenderPart* ownerRenderer = _private->coreFrame->ownerRenderer()) {
624         if (ownerRenderer->needsLayout())
625             return NO;
626         *rect = ownerRenderer->absoluteClippedOverflowRect();
627         return YES;
628     }
629
630     return NO;
631 }
632
633 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string
634 {
635     return [self _stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
636 }
637
638 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
639 {
640     ASSERT(_private->coreFrame->document());
641     
642     JSValue result = _private->coreFrame->script()->executeScript(string, forceUserGesture).jsValue();
643
644     if (!_private->coreFrame) // In case the script removed our frame from the page.
645         return @"";
646
647     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
648     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
649     // JSEvaluateScript instead, since they have less surprising semantics.
650     if (!result || !result.isBoolean() && !result.isString() && !result.isNumber())
651         return @"";
652
653     JSLock lock(SilenceAssertionsOnly);
654     return ustringToString(result.toString(_private->coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()));
655 }
656
657 - (NSRect)_caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
658 {
659     VisiblePosition visiblePosition(core(node), offset, static_cast<EAffinity>(affinity));
660     return visiblePosition.absoluteCaretBounds();
661 }
662
663 - (NSRect)_firstRectForDOMRange:(DOMRange *)range
664 {
665    return _private->coreFrame->firstRectForRange(core(range));
666 }
667
668 - (void)_scrollDOMRangeToVisible:(DOMRange *)range
669 {
670     NSRect rangeRect = [self _firstRectForDOMRange:range];    
671     Node *startNode = core([range startContainer]);
672         
673     if (startNode && startNode->renderer()) {
674         RenderLayer *layer = startNode->renderer()->enclosingLayer();
675         if (layer)
676             layer->scrollRectToVisible(enclosingIntRect(rangeRect), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
677     }
678 }
679
680 - (BOOL)_needsLayout
681 {
682     return _private->coreFrame->view() ? _private->coreFrame->view()->needsLayout() : false;
683 }
684
685 - (id)_accessibilityTree
686 {
687 #if HAVE(ACCESSIBILITY)
688     if (!AXObjectCache::accessibilityEnabled()) {
689         AXObjectCache::enableAccessibility();
690         if ([[NSApp accessibilityAttributeValue:NSAccessibilityEnhancedUserInterfaceAttribute] boolValue])
691             AXObjectCache::enableEnhancedUserInterfaceAccessibility();
692     }
693
694     if (!_private->coreFrame || !_private->coreFrame->document())
695         return nil;
696     RenderView* root = toRenderView(_private->coreFrame->document()->renderer());
697     if (!root)
698         return nil;
699     return _private->coreFrame->document()->axObjectCache()->getOrCreate(root)->wrapper();
700 #else
701     return nil;
702 #endif
703 }
704
705 - (DOMRange *)_rangeByAlteringCurrentSelection:(SelectionController::EAlteration)alteration direction:(SelectionController::EDirection)direction granularity:(TextGranularity)granularity
706 {
707     if (_private->coreFrame->selection()->isNone())
708         return nil;
709
710     SelectionController selection;
711     selection.setSelection(_private->coreFrame->selection()->selection());
712     selection.modify(alteration, direction, granularity);
713     return kit(selection.toNormalizedRange().get());
714 }
715
716 - (TextGranularity)_selectionGranularity
717 {
718     return _private->coreFrame->selectionGranularity();
719 }
720
721 - (NSRange)_convertToNSRange:(Range *)range
722 {
723     if (!range || !range->startContainer())
724         return NSMakeRange(NSNotFound, 0);
725
726     Element* selectionRoot = _private->coreFrame->selection()->rootEditableElement();
727     Element* scope = selectionRoot ? selectionRoot : _private->coreFrame->document()->documentElement();
728     
729     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
730     // that is not inside the current editable region.  These checks ensure we don't produce
731     // potentially invalid data when responding to such requests.
732     if (range->startContainer() != scope && !range->startContainer()->isDescendantOf(scope))
733         return NSMakeRange(NSNotFound, 0);
734     if (range->endContainer() != scope && !range->endContainer()->isDescendantOf(scope))
735         return NSMakeRange(NSNotFound, 0);
736     
737     RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
738     ASSERT(testRange->startContainer() == scope);
739     int startPosition = TextIterator::rangeLength(testRange.get());
740
741     ExceptionCode ec;
742     testRange->setEnd(range->endContainer(), range->endOffset(), ec);
743     ASSERT(testRange->startContainer() == scope);
744     int endPosition = TextIterator::rangeLength(testRange.get());
745
746     return NSMakeRange(startPosition, endPosition - startPosition);
747 }
748
749 - (PassRefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
750 {
751     if (nsrange.location > INT_MAX)
752         return 0;
753     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
754         nsrange.length = INT_MAX - nsrange.location;
755
756     // our critical assumption is that we are only called by input methods that
757     // concentrate on a given area containing the selection
758     // We have to do this because of text fields and textareas. The DOM for those is not
759     // directly in the document DOM, so serialization is problematic. Our solution is
760     // to use the root editable element of the selection start as the positional base.
761     // That fits with AppKit's idea of an input context.
762     Element* selectionRoot = _private->coreFrame->selection()->rootEditableElement();
763     Element* scope = selectionRoot ? selectionRoot : _private->coreFrame->document()->documentElement();
764     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
765 }
766
767 - (DOMRange *)convertNSRangeToDOMRange:(NSRange)nsrange
768 {
769     // This method exists to maintain compatibility with Leopard's Dictionary.app. <rdar://problem/6002160>
770     return [self _convertNSRangeToDOMRange:nsrange];
771 }
772
773 - (DOMRange *)_convertNSRangeToDOMRange:(NSRange)nsrange
774 {
775     return kit([self _convertToDOMRange:nsrange].get());
776 }
777
778 - (NSRange)convertDOMRangeToNSRange:(DOMRange *)range
779 {
780     // This method exists to maintain compatibility with Leopard's Dictionary.app. <rdar://problem/6002160>
781     return [self _convertDOMRangeToNSRange:range];
782 }
783
784 - (NSRange)_convertDOMRangeToNSRange:(DOMRange *)range
785 {
786     return [self _convertToNSRange:core(range)];
787 }
788
789 - (DOMRange *)_markDOMRange
790 {
791     return kit(_private->coreFrame->mark().toNormalizedRange().get());
792 }
793
794 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
795 // be deleted along with the proposed range in order to preserve proper spacing and punctuation of
796 // the text surrounding the deletion.
797 - (DOMRange *)_smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
798 {
799     Node* startContainer = core([proposedRange startContainer]);
800     Node* endContainer = core([proposedRange endContainer]);
801     if (startContainer == nil || endContainer == nil)
802         return nil;
803
804     ASSERT(startContainer->document() == endContainer->document());
805     
806     _private->coreFrame->document()->updateLayoutIgnorePendingStylesheets();
807
808     Position start(startContainer, [proposedRange startOffset]);
809     Position end(endContainer, [proposedRange endOffset]);
810     Position newStart = start.upstream().leadingWhitespacePosition(DOWNSTREAM, true);
811     if (newStart.isNull())
812         newStart = start;
813     Position newEnd = end.downstream().trailingWhitespacePosition(DOWNSTREAM, true);
814     if (newEnd.isNull())
815         newEnd = end;
816
817     newStart = rangeCompliantEquivalent(newStart);
818     newEnd = rangeCompliantEquivalent(newEnd);
819
820     RefPtr<Range> range = _private->coreFrame->document()->createRange();
821     int exception = 0;
822     range->setStart(newStart.node(), newStart.deprecatedEditingOffset(), exception);
823     range->setEnd(newStart.node(), newStart.deprecatedEditingOffset(), exception);
824     return kit(range.get());
825 }
826
827 - (DOMDocumentFragment *)_documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString 
828 {
829     if (!_private->coreFrame || !_private->coreFrame->document())
830         return nil;
831
832     return kit(createFragmentFromMarkup(_private->coreFrame->document(), markupString, baseURLString, FragmentScriptingNotAllowed).get());
833 }
834
835 - (DOMDocumentFragment *)_documentFragmentWithNodesAsParagraphs:(NSArray *)nodes
836 {
837     if (!_private->coreFrame || !_private->coreFrame->document())
838         return nil;
839     
840     NSEnumerator *nodeEnum = [nodes objectEnumerator];
841     Vector<Node*> nodesVector;
842     DOMNode *node;
843     while ((node = [nodeEnum nextObject]))
844         nodesVector.append(core(node));
845     
846     return kit(createFragmentFromNodes(_private->coreFrame->document(), nodesVector).get());
847 }
848
849 - (void)_replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
850 {
851     DOMDocumentFragment *fragment = kit(_private->coreFrame->document()->createDocumentFragment().get());
852     [fragment appendChild:node];
853     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle];
854 }
855
856 - (void)_insertParagraphSeparatorInQuotedContent
857 {
858     if (_private->coreFrame->selection()->isNone())
859         return;
860     
861     TypingCommand::insertParagraphSeparatorInQuotedContent(_private->coreFrame->document());
862     _private->coreFrame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
863 }
864
865 - (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
866 {
867     // FIXME: Someone with access to Apple's sources could remove this needless wrapper call.
868     return _private->coreFrame->visiblePositionForPoint(IntPoint(point));
869 }
870
871 - (DOMRange *)_characterRangeAtPoint:(NSPoint)point
872 {
873     VisiblePosition position = [self _visiblePositionForPoint:point];
874     if (position.isNull())
875         return nil;
876     
877     VisiblePosition previous = position.previous();
878     if (previous.isNotNull()) {
879         DOMRange *previousCharacterRange = kit(makeRange(previous, position).get());
880         NSRect rect = [self _firstRectForDOMRange:previousCharacterRange];
881         if (NSPointInRect(point, rect))
882             return previousCharacterRange;
883     }
884
885     VisiblePosition next = position.next();
886     if (next.isNotNull()) {
887         DOMRange *nextCharacterRange = kit(makeRange(position, next).get());
888         NSRect rect = [self _firstRectForDOMRange:nextCharacterRange];
889         if (NSPointInRect(point, rect))
890             return nextCharacterRange;
891     }
892     
893     return nil;
894 }
895
896 - (DOMCSSStyleDeclaration *)_typingStyle
897 {
898     if (!_private->coreFrame || !_private->coreFrame->typingStyle())
899         return nil;
900     return kit(_private->coreFrame->typingStyle()->copy().get());
901 }
902
903 - (void)_setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
904 {
905     if (!_private->coreFrame)
906         return;
907     _private->coreFrame->computeAndSetTypingStyle(core(style), undoAction);
908 }
909
910 - (void)_dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
911 {
912     if (!_private->coreFrame)
913         return;
914     FrameView* view = _private->coreFrame->view();
915     if (!view)
916         return;
917     ASSERT([getWebView(self) _usesDocumentViews]);
918     // FIXME: These are fake modifier keys here, but they should be real ones instead.
919     PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [view->platformWidget() window]),
920         LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());
921     _private->coreFrame->eventHandler()->dragSourceEndedAt(event, (DragOperation)operation);
922 }
923
924 - (BOOL)_canProvideDocumentSource
925 {
926     Frame* frame = _private->coreFrame;
927     String mimeType = frame->loader()->writer()->mimeType();
928     PluginData* pluginData = frame->page() ? frame->page()->pluginData() : 0;
929
930     if (WebCore::DOMImplementation::isTextMIMEType(mimeType) ||
931         Image::supportsType(mimeType) ||
932         (pluginData && pluginData->supportsMimeType(mimeType)))
933         return NO;
934
935     return YES;
936 }
937
938 - (BOOL)_canSaveAsWebArchive
939 {
940     // Currently, all documents that we can view source for
941     // (HTML and XML documents) can also be saved as web archives
942     return [self _canProvideDocumentSource];
943 }
944
945 - (void)_receivedData:(NSData *)data textEncodingName:(NSString *)textEncodingName
946 {
947     // Set the encoding. This only needs to be done once, but it's harmless to do it again later.
948     String encoding = _private->coreFrame->loader()->documentLoader()->overrideEncoding();
949     bool userChosen = !encoding.isNull();
950     if (encoding.isNull())
951         encoding = textEncodingName;
952     _private->coreFrame->loader()->writer()->setEncoding(encoding, userChosen);
953     [self _addData:data];
954 }
955
956 @end
957
958 @implementation WebFrame (WebPrivate)
959
960 // FIXME: This exists only as a convenience for Safari, consider moving there.
961 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
962 {
963     Frame* coreFrame = _private->coreFrame;
964     return coreFrame && coreFrame->tree()->isDescendantOf(core(ancestor));
965 }
966
967 - (void)_setShouldCreateRenderers:(BOOL)shouldCreateRenderers
968 {
969     _private->shouldCreateRenderers = shouldCreateRenderers;
970 }
971
972 - (NSColor *)_bodyBackgroundColor
973 {
974     Document* document = _private->coreFrame->document();
975     if (!document)
976         return nil;
977     HTMLElement* body = document->body();
978     if (!body)
979         return nil;
980     RenderObject* bodyRenderer = body->renderer();
981     if (!bodyRenderer)
982         return nil;
983     Color color = bodyRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
984     if (!color.isValid())
985         return nil;
986     return nsColor(color);
987 }
988
989 - (BOOL)_isFrameSet
990 {
991     Document* document = _private->coreFrame->document();
992     return document && document->isFrameSet();
993 }
994
995 - (BOOL)_firstLayoutDone
996 {
997     return _private->coreFrame->loader()->stateMachine()->firstLayoutDone();
998 }
999
1000 - (WebFrameLoadType)_loadType
1001 {
1002     return (WebFrameLoadType)_private->coreFrame->loader()->loadType();
1003 }
1004
1005 - (NSRange)_selectedNSRange
1006 {
1007     return [self _convertToNSRange:_private->coreFrame->selection()->toNormalizedRange().get()];
1008 }
1009
1010 - (void)_selectNSRange:(NSRange)range
1011 {
1012     RefPtr<Range> domRange = [self _convertToDOMRange:range];
1013     if (domRange)
1014         _private->coreFrame->selection()->setSelection(VisibleSelection(domRange.get(), SEL_DEFAULT_AFFINITY));
1015 }
1016
1017 - (BOOL)_isDisplayingStandaloneImage
1018 {
1019     Document* document = _private->coreFrame->document();
1020     return document && document->isImageDocument();
1021 }
1022
1023 - (unsigned)_pendingFrameUnloadEventCount
1024 {
1025     return _private->coreFrame->domWindow()->pendingUnloadEventListeners();
1026 }
1027
1028 - (WebIconFetcher *)fetchApplicationIcon:(id)target
1029                                 selector:(SEL)selector
1030 {
1031     return [WebIconFetcher _fetchApplicationIconForFrame:self
1032                                                   target:target
1033                                                 selector:selector];
1034 }
1035
1036 - (void)_setIsDisconnected:(bool)isDisconnected
1037 {
1038     _private->coreFrame->setIsDisconnected(isDisconnected);
1039 }
1040
1041 - (void)_setExcludeFromTextSearch:(bool)exclude
1042 {
1043     _private->coreFrame->setExcludeFromTextSearch(exclude);
1044 }
1045
1046 #if ENABLE(NETSCAPE_PLUGIN_API)
1047 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
1048 {
1049     Frame* coreFrame = core(self);
1050     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
1051         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
1052         if ([documentView isKindOfClass:[WebHTMLView class]])
1053             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
1054     }
1055 }
1056
1057 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
1058 {
1059     Frame* coreFrame = core(self);
1060     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
1061         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
1062         if ([documentView isKindOfClass:[WebHTMLView class]])
1063             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
1064     }
1065 }
1066 #endif
1067
1068 - (BOOL)_pauseAnimation:(NSString*)name onNode:(DOMNode *)node atTime:(NSTimeInterval)time
1069 {
1070     Frame* frame = core(self);
1071     if (!frame)
1072         return false;
1073
1074     AnimationController* controller = frame->animation();
1075     if (!controller)
1076         return false;
1077
1078     Node* coreNode = core(node);
1079     if (!coreNode || !coreNode->renderer())
1080         return false;
1081
1082     return controller->pauseAnimationAtTime(coreNode->renderer(), name, time);
1083 }
1084
1085 - (BOOL)_pauseTransitionOfProperty:(NSString*)name onNode:(DOMNode*)node atTime:(NSTimeInterval)time
1086 {
1087     Frame* frame = core(self);
1088     if (!frame)
1089         return false;
1090
1091     AnimationController* controller = frame->animation();
1092     if (!controller)
1093         return false;
1094
1095     Node* coreNode = core(node);
1096     if (!coreNode || !coreNode->renderer())
1097         return false;
1098
1099     return controller->pauseTransitionAtTime(coreNode->renderer(), name, time);
1100 }
1101
1102 // Pause a given SVG animation on the target node at a specific time.
1103 // This method is only intended to be used for testing the SVG animation system.
1104 - (BOOL)_pauseSVGAnimation:(NSString*)elementId onSMILNode:(DOMNode *)node atTime:(NSTimeInterval)time
1105 {
1106     Frame* frame = core(self);
1107     if (!frame)
1108         return false;
1109  
1110     Document* document = frame->document();
1111     if (!document || !document->svgExtensions())
1112         return false;
1113
1114     Node* coreNode = core(node);
1115     if (!coreNode || !SVGSMILElement::isSMILElement(coreNode))
1116         return false;
1117
1118 #if ENABLE(SVG)
1119     return document->accessSVGExtensions()->sampleAnimationAtTime(elementId, static_cast<SVGSMILElement*>(coreNode), time);
1120 #else
1121     return false;
1122 #endif
1123 }
1124
1125 - (unsigned) _numberOfActiveAnimations
1126 {
1127     Frame* frame = core(self);
1128     if (!frame)
1129         return false;
1130
1131     AnimationController* controller = frame->animation();
1132     if (!controller)
1133         return false;
1134
1135     return controller->numberOfActiveAnimations();
1136 }
1137
1138 - (void) _suspendAnimations
1139 {
1140     Frame* frame = core(self);
1141     if (!frame)
1142         return;
1143
1144     AnimationController* controller = frame->animation();
1145     if (!controller)
1146         return;
1147
1148     controller->suspendAnimations(frame->document());
1149 }
1150
1151 - (void) _resumeAnimations
1152 {
1153     Frame* frame = core(self);
1154     if (!frame)
1155         return;
1156
1157     AnimationController* controller = frame->animation();
1158     if (!controller)
1159         return;
1160
1161     controller->resumeAnimations(frame->document());
1162 }
1163
1164 - (void)_replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1165 {
1166     if (_private->coreFrame->selection()->isNone() || !fragment)
1167         return;
1168     
1169     applyCommand(ReplaceSelectionCommand::create(_private->coreFrame->document(), core(fragment), selectReplacement, smartReplace, matchStyle));
1170     _private->coreFrame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
1171 }
1172
1173 - (void)_replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1174 {   
1175     DOMDocumentFragment* fragment = kit(createFragmentFromText(_private->coreFrame->selection()->toNormalizedRange().get(), text).get());
1176     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
1177 }
1178
1179 - (void)_replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1180 {
1181     DOMDocumentFragment *fragment = [self _documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
1182     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1183 }
1184
1185 // Determines whether whitespace needs to be added around aString to preserve proper spacing and
1186 // punctuation when it's inserted into the receiver's text over charRange. Returns by reference
1187 // in beforeString and afterString any whitespace that should be added, unless either or both are
1188 // nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
1189 - (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1190 {
1191     // give back nil pointers in case of early returns
1192     if (beforeString)
1193         *beforeString = nil;
1194     if (afterString)
1195         *afterString = nil;
1196         
1197     // inspect destination
1198     Node *startContainer = core([rangeToReplace startContainer]);
1199     Node *endContainer = core([rangeToReplace endContainer]);
1200
1201     Position startPos(startContainer, [rangeToReplace startOffset]);
1202     Position endPos(endContainer, [rangeToReplace endOffset]);
1203
1204     VisiblePosition startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
1205     VisiblePosition endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY);
1206     
1207     // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
1208     if (startVisiblePos.isNull() || endVisiblePos.isNull())
1209         return;
1210
1211     bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
1212     if (addLeadingSpace)
1213         if (UChar previousChar = startVisiblePos.previous().characterAfter())
1214             addLeadingSpace = !isCharacterSmartReplaceExempt(previousChar, true);
1215     
1216     bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
1217     if (addTrailingSpace)
1218         if (UChar thisChar = endVisiblePos.characterAfter())
1219             addTrailingSpace = !isCharacterSmartReplaceExempt(thisChar, false);
1220     
1221     // inspect source
1222     bool hasWhitespaceAtStart = false;
1223     bool hasWhitespaceAtEnd = false;
1224     unsigned pasteLength = [pasteString length];
1225     if (pasteLength > 0) {
1226         NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
1227         
1228         if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
1229             hasWhitespaceAtStart = YES;
1230         }
1231         if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
1232             hasWhitespaceAtEnd = YES;
1233         }
1234     }
1235     
1236     // issue the verdict
1237     if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
1238         *beforeString = @" ";
1239     if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
1240         *afterString = @" ";
1241 }
1242
1243 - (NSMutableDictionary *)_cacheabilityDictionary
1244 {
1245     NSMutableDictionary *result = [NSMutableDictionary dictionary];
1246     
1247     FrameLoader* frameLoader = _private->coreFrame->loader();
1248     DocumentLoader* documentLoader = frameLoader->documentLoader();
1249     if (documentLoader && !documentLoader->mainDocumentError().isNull())
1250         [result setObject:(NSError *)documentLoader->mainDocumentError() forKey:WebFrameMainDocumentError];
1251         
1252     if (frameLoader->subframeLoader()->containsPlugins())
1253         [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasPlugins];
1254     
1255     if (DOMWindow* domWindow = _private->coreFrame->domWindow()) {
1256         if (domWindow->hasEventListeners(eventNames().unloadEvent))
1257             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasUnloadListener];
1258             
1259 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1260         if (domWindow->optionalApplicationCache())
1261             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesApplicationCache];
1262 #endif
1263     }
1264     
1265     if (Document* document = _private->coreFrame->document()) {
1266 #if ENABLE(DATABASE)
1267         if (document->hasOpenDatabases())
1268             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesDatabases];
1269 #endif
1270             
1271         if (document->usingGeolocation())
1272             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesGeolocation];
1273             
1274         if (!document->canSuspendActiveDOMObjects())
1275             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameCanSuspendActiveDOMObjects];
1276     }
1277     
1278     return result;
1279 }
1280
1281 - (BOOL)_allowsFollowingLink:(NSURL *)URL
1282 {
1283     if (!_private->coreFrame)
1284         return YES;
1285     return SecurityOrigin::canDisplay(URL, String(), _private->coreFrame->document());
1286 }
1287
1288 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string withGlobalObject:(JSObjectRef)globalObjectRef inScriptWorld:(WebScriptWorld *)world
1289 {
1290     // Start off with some guess at a frame and a global object, we'll try to do better...!
1291     JSDOMWindow* anyWorldGlobalObject = _private->coreFrame->script()->globalObject(mainThreadNormalWorld());
1292
1293     // The global object is probably a shell object? - if so, we know how to use this!
1294     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
1295     if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
1296         anyWorldGlobalObject = static_cast<JSDOMWindowShell*>(globalObjectObj)->window();
1297
1298     // Get the frame frome the global object we've settled on.
1299     Frame* frame = anyWorldGlobalObject->impl()->frame();
1300     ASSERT(frame->document());
1301     JSValue result = frame->script()->executeScriptInWorld(core(world), string, true).jsValue();
1302
1303     if (!frame) // In case the script removed our frame from the page.
1304         return @"";
1305
1306     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
1307     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
1308     // JSEvaluateScript instead, since they have less surprising semantics.
1309     if (!result || !result.isBoolean() && !result.isString() && !result.isNumber())
1310         return @"";
1311
1312     JSLock lock(SilenceAssertionsOnly);
1313     return ustringToString(result.toString(anyWorldGlobalObject->globalExec()));
1314 }
1315
1316 - (JSGlobalContextRef)_globalContextForScriptWorld:(WebScriptWorld *)world
1317 {
1318     Frame* coreFrame = _private->coreFrame;
1319     if (!coreFrame)
1320         return 0;
1321     DOMWrapperWorld* coreWorld = core(world);
1322     if (!coreWorld)
1323         return 0;
1324     return toGlobalRef(coreFrame->script()->globalObject(coreWorld)->globalExec());
1325 }
1326
1327 - (void)setAllowsScrollersToOverlapContent:(BOOL)flag
1328 {
1329     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1330     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAllowsScrollersToOverlapContent:flag];
1331 }
1332
1333 - (void)setAlwaysHideHorizontalScroller:(BOOL)flag
1334 {
1335     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1336     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideHorizontalScroller:flag];
1337 }
1338 - (void)setAlwaysHideVerticalScroller:(BOOL)flag
1339 {
1340     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1341     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideVerticalScroller:flag];
1342 }
1343
1344 - (void)setAccessibleName:(NSString *)name
1345 {
1346 #if HAVE(ACCESSIBILITY)
1347     if (!AXObjectCache::accessibilityEnabled())
1348         return;
1349     
1350     RenderView* root = toRenderView(_private->coreFrame->document()->renderer());
1351     if (!root)
1352         return;
1353     
1354     AccessibilityObject* rootObject = _private->coreFrame->document()->axObjectCache()->getOrCreate(root);
1355     String strName(name);
1356     rootObject->setAccessibleName(strName);
1357 #endif
1358 }
1359
1360 - (NSString*)_layerTreeAsText
1361 {
1362     Frame* coreFrame = _private->coreFrame;
1363     if (!coreFrame)
1364         return @"";
1365
1366     return coreFrame->layerTreeAsText();
1367 }
1368
1369 static Node* spellingNode(Frame* coreFrame)
1370 {
1371     Node* focusedNode = coreFrame->selection()->start().node();
1372     if (!focusedNode || !focusedNode->renderer())
1373         return 0;
1374
1375     for (const RenderObject* renderer = focusedNode->renderer(); renderer; renderer = renderer->childAt(0)) {
1376         if (renderer->isText())
1377             return renderer->node();
1378     }
1379     return 0;
1380 }
1381
1382 - (BOOL)hasSpellingMarker:(int)from length:(int)length
1383 {
1384     Frame* coreFrame = _private->coreFrame;
1385     if (!coreFrame)
1386         return NO;
1387
1388     Node* node = spellingNode(coreFrame);
1389     if (!node)
1390         return NO;
1391
1392     unsigned int startOffset = static_cast<unsigned int>(from);
1393     unsigned int endOffset = static_cast<unsigned int>(from + length);
1394     Vector<DocumentMarker> markers = coreFrame->document()->markers()->markersForNode(node);
1395     for (size_t i = 0; i < markers.size(); ++i) {
1396         DocumentMarker marker = markers[i];
1397         if (marker.startOffset <= startOffset && endOffset <= marker.endOffset && marker.type == DocumentMarker::Spelling)
1398             return YES;
1399     }
1400     return NO;
1401 }
1402
1403 @end
1404
1405 @implementation WebFrame
1406
1407 - (id)init
1408 {
1409     return nil;
1410 }
1411
1412 // Should be deprecated.
1413 - (id)initWithName:(NSString *)name webFrameView:(WebFrameView *)view webView:(WebView *)webView
1414 {
1415     return nil;
1416 }
1417
1418 - (void)dealloc
1419 {
1420     if (_private && _private->includedInWebKitStatistics)
1421         --WebFrameCount;
1422
1423     [_private release];
1424
1425     [super dealloc];
1426 }
1427
1428 - (void)finalize
1429 {
1430     if (_private && _private->includedInWebKitStatistics)
1431         --WebFrameCount;
1432
1433     [super finalize];
1434 }
1435
1436 - (NSString *)name
1437 {
1438     Frame* coreFrame = _private->coreFrame;
1439     if (!coreFrame)
1440         return nil;
1441     return coreFrame->tree()->name();
1442 }
1443
1444 - (WebFrameView *)frameView
1445 {
1446     ASSERT(!getWebView(self) || [getWebView(self) _usesDocumentViews]);
1447     return _private->webFrameView;
1448 }
1449
1450 - (WebView *)webView
1451 {
1452     return getWebView(self);
1453 }
1454
1455 static bool needsMicrosoftMessengerDOMDocumentWorkaround()
1456 {
1457     static bool needsWorkaround = applicationIsMicrosoftMessenger() && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] compare:@"7.1" options:NSNumericSearch] == NSOrderedAscending;
1458     return needsWorkaround;
1459 }
1460
1461 - (DOMDocument *)DOMDocument
1462 {
1463     if (needsMicrosoftMessengerDOMDocumentWorkaround() && !pthread_main_np())
1464         return nil;
1465
1466     Frame* coreFrame = _private->coreFrame;
1467     if (!coreFrame)
1468         return nil;
1469     
1470     // FIXME: <rdar://problem/5145841> When loading a custom view/representation 
1471     // into a web frame, the old document can still be around. This makes sure that
1472     // we'll return nil in those cases.
1473     if (![[self _dataSource] _isDocumentHTML]) 
1474         return nil; 
1475
1476     Document* document = coreFrame->document();
1477     
1478     // According to the documentation, we should return nil if the frame doesn't have a document.
1479     // While full-frame images and plugins do have an underlying HTML document, we return nil here to be
1480     // backwards compatible.
1481     if (document && (document->isPluginDocument() || document->isImageDocument()))
1482         return nil;
1483     
1484     return kit(coreFrame->document());
1485 }
1486
1487 - (DOMHTMLElement *)frameElement
1488 {
1489     Frame* coreFrame = _private->coreFrame;
1490     if (!coreFrame)
1491         return nil;
1492     return kit(coreFrame->ownerElement());
1493 }
1494
1495 - (WebDataSource *)provisionalDataSource
1496 {
1497     Frame* coreFrame = _private->coreFrame;
1498     return coreFrame ? dataSource(coreFrame->loader()->provisionalDocumentLoader()) : nil;
1499 }
1500
1501 - (WebDataSource *)dataSource
1502 {
1503     Frame* coreFrame = _private->coreFrame;
1504     return coreFrame && coreFrame->loader()->frameHasLoaded() ? [self _dataSource] : nil;
1505 }
1506
1507 - (void)loadRequest:(NSURLRequest *)request
1508 {
1509     Frame* coreFrame = _private->coreFrame;
1510     if (!coreFrame)
1511         return;
1512     coreFrame->loader()->load(request, false);
1513 }
1514
1515 static NSURL *createUniqueWebDataURL()
1516 {
1517     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
1518     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
1519     CFRelease(UUIDRef);
1520     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"applewebdata://%@", UUIDString]];
1521     CFRelease(UUIDString);
1522     return URL;
1523 }
1524
1525 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
1526 {
1527     if (!pthread_main_np())
1528         return [[self _webkit_invokeOnMainThread] _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:unreachableURL];
1529     
1530     KURL responseURL;
1531     if (!baseURL) {
1532         baseURL = blankURL();
1533         responseURL = createUniqueWebDataURL();
1534     }
1535     
1536     ResourceRequest request([baseURL absoluteURL]);
1537
1538     // hack because Mail checks for this property to detect data / archive loads
1539     [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest()];
1540
1541     SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData(data), MIMEType, encodingName, [unreachableURL absoluteURL], responseURL);
1542
1543     _private->coreFrame->loader()->load(request, substituteData, false);
1544 }
1545
1546
1547 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
1548 {
1549     WebCoreThreadViolationCheckRoundTwo();
1550     
1551     if (!MIMEType)
1552         MIMEType = @"text/html";
1553     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:nil];
1554 }
1555
1556 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
1557 {
1558     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
1559     [self _loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL unreachableURL:unreachableURL];
1560 }
1561
1562 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
1563 {
1564     WebCoreThreadViolationCheckRoundTwo();
1565
1566     [self _loadHTMLString:string baseURL:baseURL unreachableURL:nil];
1567 }
1568
1569 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
1570 {
1571     WebCoreThreadViolationCheckRoundTwo();
1572
1573     [self _loadHTMLString:string baseURL:baseURL unreachableURL:unreachableURL];
1574 }
1575
1576 - (void)loadArchive:(WebArchive *)archive
1577 {
1578     if (LegacyWebArchive* coreArchive = [archive _coreLegacyWebArchive])
1579         _private->coreFrame->loader()->loadArchive(coreArchive);
1580 }
1581
1582 - (void)stopLoading
1583 {
1584     if (!_private->coreFrame)
1585         return;
1586     _private->coreFrame->loader()->stopForUserCancel();
1587 }
1588
1589 - (void)reload
1590 {
1591     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_RELOAD_FROM_ORIGIN) && applicationIsSafari())
1592         _private->coreFrame->loader()->reload(GetCurrentKeyModifiers() & shiftKey);
1593     else
1594         _private->coreFrame->loader()->reload(false);
1595 }
1596
1597 - (void)reloadFromOrigin
1598 {
1599     _private->coreFrame->loader()->reload(true);
1600 }
1601
1602 - (WebFrame *)findFrameNamed:(NSString *)name
1603 {
1604     Frame* coreFrame = _private->coreFrame;
1605     if (!coreFrame)
1606         return nil;
1607     return kit(coreFrame->tree()->find(name));
1608 }
1609
1610 - (WebFrame *)parentFrame
1611 {
1612     Frame* coreFrame = _private->coreFrame;
1613     if (!coreFrame)
1614         return nil;
1615     return [[kit(coreFrame->tree()->parent()) retain] autorelease];
1616 }
1617
1618 - (NSArray *)childFrames
1619 {
1620     Frame* coreFrame = _private->coreFrame;
1621     if (!coreFrame)
1622         return [NSArray array];
1623     NSMutableArray *children = [NSMutableArray arrayWithCapacity:coreFrame->tree()->childCount()];
1624     for (Frame* child = coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1625         [children addObject:kit(child)];
1626     return children;
1627 }
1628
1629 - (WebScriptObject *)windowObject
1630 {
1631     Frame* coreFrame = _private->coreFrame;
1632     if (!coreFrame)
1633         return 0;
1634     return coreFrame->script()->windowScriptObject();
1635 }
1636
1637 - (JSGlobalContextRef)globalContext
1638 {
1639     Frame* coreFrame = _private->coreFrame;
1640     if (!coreFrame)
1641         return 0;
1642     return toGlobalRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
1643 }
1644
1645 @end