0156babf9fec36b9486d36b58a7c9b273711056f
[WebKit-https.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 "WebKitStatisticsPrivate.h"
48 #import "WebKitVersionChecks.h"
49 #import "WebNSObjectExtras.h"
50 #import "WebNSURLExtras.h"
51 #import "WebScriptDebugger.h"
52 #import "WebScriptWorldInternal.h"
53 #import "WebViewInternal.h"
54 #import <JavaScriptCore/APICast.h>
55 #import <WebCore/AXObjectCache.h>
56 #import <WebCore/AccessibilityObject.h>
57 #import <WebCore/AnimationController.h>
58 #import <WebCore/CSSMutableStyleDeclaration.h>
59 #import <WebCore/CachedResourceLoader.h>
60 #import <WebCore/Chrome.h>
61 #import <WebCore/ColorMac.h>
62 #import <WebCore/DOMImplementation.h>
63 #import <WebCore/DocumentFragment.h>
64 #import <WebCore/DocumentMarkerController.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         case WebKitEditingUnixBehavior:
208             return WebCore::EditingUnixBehavior;
209     }
210     ASSERT_NOT_REACHED();
211     return WebCore::EditingMacBehavior;
212 }
213
214 TextDirectionSubmenuInclusionBehavior core(WebTextDirectionSubmenuInclusionBehavior behavior)
215 {
216     switch (behavior) {
217         case WebTextDirectionSubmenuNeverIncluded:
218             return TextDirectionSubmenuNeverIncluded;
219         case WebTextDirectionSubmenuAutomaticallyIncluded:
220             return TextDirectionSubmenuAutomaticallyIncluded;
221         case WebTextDirectionSubmenuAlwaysIncluded:
222             return TextDirectionSubmenuAlwaysIncluded;
223     }
224     ASSERT_NOT_REACHED();
225     return TextDirectionSubmenuNeverIncluded;
226 }
227
228 @implementation WebFrame (WebInternal)
229
230 Frame* core(WebFrame *frame)
231 {
232     return frame ? frame->_private->coreFrame : 0;
233 }
234
235 WebFrame *kit(Frame* frame)
236 {
237     return frame ? static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame() : nil;
238 }
239
240 Page* core(WebView *webView)
241 {
242     return [webView page];
243 }
244
245 WebView *kit(Page* page)
246 {
247     return page ? static_cast<WebChromeClient*>(page->chrome()->client())->webView() : nil;
248 }
249
250 WebView *getWebView(WebFrame *webFrame)
251 {
252     Frame* coreFrame = core(webFrame);
253     if (!coreFrame)
254         return nil;
255     return kit(coreFrame->page());
256 }
257
258 + (PassRefPtr<Frame>)_createFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView ownerElement:(HTMLFrameOwnerElement*)ownerElement
259 {
260     WebView *webView = kit(page);
261
262     WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
263     RefPtr<Frame> coreFrame = Frame::create(page, ownerElement, new WebFrameLoaderClient(frame));
264     [frame release];
265     frame->_private->coreFrame = coreFrame.get();
266
267     coreFrame->tree()->setName(name);
268     if (ownerElement) {
269         ASSERT(ownerElement->document()->frame());
270         ownerElement->document()->frame()->tree()->appendChild(coreFrame.get());
271     }
272
273     coreFrame->init();
274
275     [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
276
277     return coreFrame.release();
278 }
279
280 + (void)_createMainFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView
281 {
282     [self _createFrameWithPage:page frameName:name frameView:frameView ownerElement:0];
283 }
284
285 + (PassRefPtr<WebCore::Frame>)_createSubframeWithOwnerElement:(HTMLFrameOwnerElement*)ownerElement frameName:(const String&)name frameView:(WebFrameView *)frameView
286 {
287     return [self _createFrameWithPage:ownerElement->document()->frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
288 }
289
290 - (BOOL)_isIncludedInWebKitStatistics
291 {
292     return _private && _private->includedInWebKitStatistics;
293 }
294
295 - (void)_attachScriptDebugger
296 {
297     ScriptController* scriptController = _private->coreFrame->script();
298
299     // Calling ScriptController::globalObject() would create a window shell, and dispatch corresponding callbacks, which may be premature
300     // if the script debugger is attached before a document is created.  These calls use the debuggerWorld(), we will need to pass a world
301     // to be able to debug isolated worlds.
302     if (!scriptController->existingWindowShell(debuggerWorld()))
303         return;
304
305     JSGlobalObject* globalObject = scriptController->globalObject(debuggerWorld());
306     if (!globalObject)
307         return;
308
309     if (_private->scriptDebugger) {
310         ASSERT(_private->scriptDebugger == globalObject->debugger());
311         return;
312     }
313
314     _private->scriptDebugger = new WebScriptDebugger(globalObject);
315 }
316
317 - (void)_detachScriptDebugger
318 {
319     if (!_private->scriptDebugger)
320         return;
321
322     delete _private->scriptDebugger;
323     _private->scriptDebugger = 0;
324 }
325
326 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v
327 {
328     self = [super init];
329     if (!self)
330         return nil;
331
332     _private = [[WebFramePrivate alloc] init];
333
334     // Set includedInWebKitStatistics before calling WebFrameView _setWebFrame, since
335     // it calls WebFrame _isIncludedInWebKitStatistics.
336     if ((_private->includedInWebKitStatistics = [[v class] shouldIncludeInWebKitStatistics]))
337         ++WebFrameCount;
338
339     if (fv) {
340         [_private setWebFrameView:fv];
341         [fv _setWebFrame:self];
342     }
343
344     _private->shouldCreateRenderers = YES;
345
346     return self;
347 }
348
349 - (void)_clearCoreFrame
350 {
351     _private->coreFrame = 0;
352 }
353
354 - (void)_updateBackgroundAndUpdatesWhileOffscreen
355 {
356     WebView *webView = getWebView(self);
357     BOOL drawsBackground = [webView drawsBackground];
358     NSColor *backgroundColor = [webView backgroundColor];
359
360     Frame* coreFrame = _private->coreFrame;
361     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
362         if ([webView _usesDocumentViews]) {
363             // Don't call setDrawsBackground:YES here because it may be NO because of a load
364             // in progress; WebFrameLoaderClient keeps it set to NO during the load process.
365             WebFrame *webFrame = kit(frame);
366             if (!drawsBackground)
367                 [[[webFrame frameView] _scrollView] setDrawsBackground:NO];
368             [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor];
369             id documentView = [[webFrame frameView] documentView];
370             if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
371                 [documentView setDrawsBackground:drawsBackground];
372             if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
373                 [documentView setBackgroundColor:backgroundColor];
374         }
375
376         if (FrameView* view = frame->view()) {
377             view->setTransparent(!drawsBackground);
378             view->setBaseBackgroundColor(colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
379             view->setShouldUpdateWhileOffscreen([webView shouldUpdateWhileOffscreen]);
380         }
381     }
382 }
383
384 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
385 {
386     _private->internalLoadDelegate = internalLoadDelegate;
387 }
388
389 - (id)_internalLoadDelegate
390 {
391     return _private->internalLoadDelegate;
392 }
393
394 #ifndef BUILDING_ON_TIGER
395 - (void)_unmarkAllBadGrammar
396 {
397     Frame* coreFrame = _private->coreFrame;
398     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
399         if (Document* document = frame->document())
400             document->markers()->removeMarkers(DocumentMarker::Grammar);
401     }
402 }
403 #endif
404
405 - (void)_unmarkAllMisspellings
406 {
407     Frame* coreFrame = _private->coreFrame;
408     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
409         if (Document* document = frame->document())
410             document->markers()->removeMarkers(DocumentMarker::Spelling);
411     }
412 }
413
414 - (BOOL)_hasSelection
415 {
416     if ([getWebView(self) _usesDocumentViews]) {
417         id documentView = [_private->webFrameView documentView];    
418
419         // optimization for common case to avoid creating potentially large selection string
420         if ([documentView isKindOfClass:[WebHTMLView class]])
421             if (Frame* coreFrame = _private->coreFrame)
422                 return coreFrame->selection()->isRange();
423
424         if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
425             return [[documentView selectedString] length] > 0;
426         
427         return NO;
428     }
429
430     Frame* coreFrame = _private->coreFrame;
431     return coreFrame && coreFrame->selection()->isRange();
432 }
433
434 - (void)_clearSelection
435 {
436     ASSERT([getWebView(self) _usesDocumentViews]);
437     id documentView = [_private->webFrameView documentView];    
438     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
439         [documentView deselectAll];
440 }
441
442 #if !ASSERT_DISABLED
443 - (BOOL)_atMostOneFrameHasSelection
444 {
445     // FIXME: 4186050 is one known case that makes this debug check fail.
446     BOOL found = NO;
447     Frame* coreFrame = _private->coreFrame;
448     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
449         if ([kit(frame) _hasSelection]) {
450             if (found)
451                 return NO;
452             found = YES;
453         }
454     return YES;
455 }
456 #endif
457
458 - (WebFrame *)_findFrameWithSelection
459 {
460     Frame* coreFrame = _private->coreFrame;
461     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
462         WebFrame *webFrame = kit(frame);
463         if ([webFrame _hasSelection])
464             return webFrame;
465     }
466     return nil;
467 }
468
469 - (void)_clearSelectionInOtherFrames
470 {
471     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
472     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
473     // notification sent when the first responder changes in general (Radar 2573089).
474     WebFrame *frameWithSelection = [[getWebView(self) mainFrame] _findFrameWithSelection];
475     if (frameWithSelection != self)
476         [frameWithSelection _clearSelection];
477
478     // While we're in the general area of selection and frames, check that there is only one now.
479     ASSERT([[getWebView(self) mainFrame] _atMostOneFrameHasSelection]);
480 }
481
482 static inline WebDataSource *dataSource(DocumentLoader* loader)
483 {
484     return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil;
485 }
486
487 - (WebDataSource *)_dataSource
488 {
489     return dataSource(_private->coreFrame->loader()->documentLoader());
490 }
491
492 - (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString
493 {
494     return _private->coreFrame->documentTypeString() + markupString;
495 }
496
497 - (NSArray *)_nodesFromList:(Vector<Node*> *)nodesVector
498 {
499     size_t size = nodesVector->size();
500     NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size];
501     for (size_t i = 0; i < size; ++i)
502         [nodes addObject:kit((*nodesVector)[i])];
503     return nodes;
504 }
505
506 - (NSString *)_markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
507 {
508     // FIXME: This is always "for interchange". Is that right? See the previous method.
509     Vector<Node*> nodeList;
510     NSString *markupString = createMarkup(core(range), nodes ? &nodeList : 0, AnnotateForInterchange);
511     if (nodes)
512         *nodes = [self _nodesFromList:&nodeList];
513
514     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
515 }
516
517 - (NSString *)_selectedString
518 {
519     return _private->coreFrame->displayStringModifiedByEncoding(_private->coreFrame->editor()->selectedText());
520 }
521
522 - (NSString *)_stringForRange:(DOMRange *)range
523 {
524     // This will give a system malloc'd buffer that can be turned directly into an NSString
525     unsigned length;
526     UChar* buf = plainTextToMallocAllocatedBuffer(core(range), length, true);
527     
528     if (!buf)
529         return [NSString string];
530
531     // Transfer buffer ownership to NSString
532     return [[[NSString alloc] initWithCharactersNoCopy:buf length:length freeWhenDone:YES] autorelease];
533 }
534
535 - (BOOL)_shouldFlattenCompositingLayers:(CGContextRef)context
536 {
537     // -currentContextDrawingToScreen returns YES for bitmap contexts.
538     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
539     if (isPrinting)
540         return YES;
541
542     if (!WKCGContextIsBitmapContext(context))
543         return NO;
544
545     // If we're drawing into a bitmap, we might be snapshotting, or drawing into a layer-backed view.
546     if ([getWebView(self) _usesDocumentViews]) {
547         id documentView = [_private->webFrameView documentView];
548         if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _web_isDrawingIntoLayer])
549             return NO;
550     }
551
552     return [getWebView(self) _includesFlattenedCompositingLayersWhenDrawingToBitmap];
553 }
554
555 - (void)_drawRect:(NSRect)rect contentsOnly:(BOOL)contentsOnly
556 {
557     ASSERT([[NSGraphicsContext currentContext] isFlipped]);
558
559     CGContextRef ctx = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
560     GraphicsContext context(ctx);
561
562     FrameView* view = _private->coreFrame->view();
563     
564     bool shouldFlatten = false;
565     if (Frame* parentFrame = _private->coreFrame->tree()->parent()) {
566         // For subframes, we need to inherit the paint behavior from our parent
567         FrameView* parentView = parentFrame ? parentFrame->view() : 0;
568         if (parentView)
569             shouldFlatten = parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
570     } else
571         shouldFlatten = [self _shouldFlattenCompositingLayers:ctx];
572
573     PaintBehavior oldBehavior = PaintBehaviorNormal;
574     if (shouldFlatten) {
575         oldBehavior = view->paintBehavior();
576         view->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
577     }
578     
579     if (contentsOnly)
580         _private->coreFrame->view()->paintContents(&context, enclosingIntRect(rect));
581     else
582         _private->coreFrame->view()->paint(&context, enclosingIntRect(rect));
583
584     if (shouldFlatten)
585         view->setPaintBehavior(oldBehavior);
586 }
587
588 // Used by pagination code called from AppKit when a standalone web page is printed.
589 - (NSArray*)_computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight
590 {
591     NSMutableArray* pages = [NSMutableArray arrayWithCapacity:5];
592     if (printWidthScaleFactor <= 0) {
593         LOG_ERROR("printWidthScaleFactor has bad value %.2f", printWidthScaleFactor);
594         return pages;
595     }
596     
597     if (printHeight <= 0) {
598         LOG_ERROR("printHeight has bad value %.2f", printHeight);
599         return pages;
600     }
601
602     if (!_private->coreFrame || !_private->coreFrame->document() || !_private->coreFrame->view()) return pages;
603     RenderView* root = toRenderView(_private->coreFrame->document()->renderer());
604     if (!root) return pages;
605     
606     FrameView* view = _private->coreFrame->view();
607     if (!view)
608         return pages;
609
610     NSView* documentView = view->documentView();
611     if (!documentView)
612         return pages;
613
614     float docWidth = root->layer()->width();
615     float printWidth = docWidth / printWidthScaleFactor;
616
617     PrintContext printContext(_private->coreFrame);
618     printContext.computePageRectsWithPageSize(FloatSize(printWidth, printHeight), true);
619
620     const Vector<IntRect>& pageRects = printContext.pageRects();
621     const size_t pageCount = pageRects.size();
622     for (size_t pageNumber = 0; pageNumber < pageCount; ++pageNumber)
623         [pages addObject: [NSValue valueWithRect: NSRect(pageRects[pageNumber])]];
624     return pages;
625 }
626
627 - (BOOL)_getVisibleRect:(NSRect*)rect
628 {
629     ASSERT_ARG(rect, rect);
630     if (RenderPart* ownerRenderer = _private->coreFrame->ownerRenderer()) {
631         if (ownerRenderer->needsLayout())
632             return NO;
633         *rect = ownerRenderer->absoluteClippedOverflowRect();
634         return YES;
635     }
636
637     return NO;
638 }
639
640 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string
641 {
642     return [self _stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
643 }
644
645 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
646 {
647     ASSERT(_private->coreFrame->document());
648     
649     JSValue result = _private->coreFrame->script()->executeScript(string, forceUserGesture).jsValue();
650
651     if (!_private->coreFrame) // In case the script removed our frame from the page.
652         return @"";
653
654     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
655     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
656     // JSEvaluateScript instead, since they have less surprising semantics.
657     if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
658         return @"";
659
660     JSLock lock(SilenceAssertionsOnly);
661     return ustringToString(result.toString(_private->coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()));
662 }
663
664 - (NSRect)_caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
665 {
666     VisiblePosition visiblePosition(core(node), offset, static_cast<EAffinity>(affinity));
667     return visiblePosition.absoluteCaretBounds();
668 }
669
670 - (NSRect)_firstRectForDOMRange:(DOMRange *)range
671 {
672    return _private->coreFrame->editor()->firstRectForRange(core(range));
673 }
674
675 - (void)_scrollDOMRangeToVisible:(DOMRange *)range
676 {
677     NSRect rangeRect = [self _firstRectForDOMRange:range];    
678     Node *startNode = core([range startContainer]);
679         
680     if (startNode && startNode->renderer()) {
681         RenderLayer *layer = startNode->renderer()->enclosingLayer();
682         if (layer)
683             layer->scrollRectToVisible(enclosingIntRect(rangeRect), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
684     }
685 }
686
687 - (BOOL)_needsLayout
688 {
689     return _private->coreFrame->view() ? _private->coreFrame->view()->needsLayout() : false;
690 }
691
692 - (id)_accessibilityTree
693 {
694 #if HAVE(ACCESSIBILITY)
695     if (!AXObjectCache::accessibilityEnabled()) {
696         AXObjectCache::enableAccessibility();
697         if ([[NSApp accessibilityAttributeValue:NSAccessibilityEnhancedUserInterfaceAttribute] boolValue])
698             AXObjectCache::enableEnhancedUserInterfaceAccessibility();
699     }
700
701     if (!_private->coreFrame || !_private->coreFrame->document())
702         return nil;
703     RenderView* root = toRenderView(_private->coreFrame->document()->renderer());
704     if (!root)
705         return nil;
706     return _private->coreFrame->document()->axObjectCache()->getOrCreate(root)->wrapper();
707 #else
708     return nil;
709 #endif
710 }
711
712 - (DOMRange *)_rangeByAlteringCurrentSelection:(SelectionController::EAlteration)alteration direction:(SelectionDirection)direction granularity:(TextGranularity)granularity
713 {
714     if (_private->coreFrame->selection()->isNone())
715         return nil;
716
717     SelectionController selection;
718     selection.setSelection(_private->coreFrame->selection()->selection());
719     selection.modify(alteration, direction, granularity);
720     return kit(selection.toNormalizedRange().get());
721 }
722
723 - (TextGranularity)_selectionGranularity
724 {
725     return _private->coreFrame->selection()->granularity();
726 }
727
728 - (NSRange)_convertToNSRange:(Range *)range
729 {
730     if (!range || !range->startContainer())
731         return NSMakeRange(NSNotFound, 0);
732
733     Element* selectionRoot = _private->coreFrame->selection()->rootEditableElement();
734     Element* scope = selectionRoot ? selectionRoot : _private->coreFrame->document()->documentElement();
735     
736     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
737     // that is not inside the current editable region.  These checks ensure we don't produce
738     // potentially invalid data when responding to such requests.
739     if (range->startContainer() != scope && !range->startContainer()->isDescendantOf(scope))
740         return NSMakeRange(NSNotFound, 0);
741     if (range->endContainer() != scope && !range->endContainer()->isDescendantOf(scope))
742         return NSMakeRange(NSNotFound, 0);
743     
744     RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
745     ASSERT(testRange->startContainer() == scope);
746     int startPosition = TextIterator::rangeLength(testRange.get());
747
748     ExceptionCode ec;
749     testRange->setEnd(range->endContainer(), range->endOffset(), ec);
750     ASSERT(testRange->startContainer() == scope);
751     int endPosition = TextIterator::rangeLength(testRange.get());
752
753     return NSMakeRange(startPosition, endPosition - startPosition);
754 }
755
756 - (PassRefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
757 {
758     if (nsrange.location > INT_MAX)
759         return 0;
760     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
761         nsrange.length = INT_MAX - nsrange.location;
762
763     // our critical assumption is that we are only called by input methods that
764     // concentrate on a given area containing the selection
765     // We have to do this because of text fields and textareas. The DOM for those is not
766     // directly in the document DOM, so serialization is problematic. Our solution is
767     // to use the root editable element of the selection start as the positional base.
768     // That fits with AppKit's idea of an input context.
769     Element* selectionRoot = _private->coreFrame->selection()->rootEditableElement();
770     Element* scope = selectionRoot ? selectionRoot : _private->coreFrame->document()->documentElement();
771     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
772 }
773
774 - (DOMRange *)convertNSRangeToDOMRange:(NSRange)nsrange
775 {
776     // This method exists to maintain compatibility with Leopard's Dictionary.app. <rdar://problem/6002160>
777     return [self _convertNSRangeToDOMRange:nsrange];
778 }
779
780 - (DOMRange *)_convertNSRangeToDOMRange:(NSRange)nsrange
781 {
782     return kit([self _convertToDOMRange:nsrange].get());
783 }
784
785 - (NSRange)convertDOMRangeToNSRange:(DOMRange *)range
786 {
787     // This method exists to maintain compatibility with Leopard's Dictionary.app. <rdar://problem/6002160>
788     return [self _convertDOMRangeToNSRange:range];
789 }
790
791 - (NSRange)_convertDOMRangeToNSRange:(DOMRange *)range
792 {
793     return [self _convertToNSRange:core(range)];
794 }
795
796 - (DOMRange *)_markDOMRange
797 {
798     return kit(_private->coreFrame->editor()->mark().toNormalizedRange().get());
799 }
800
801 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
802 // be deleted along with the proposed range in order to preserve proper spacing and punctuation of
803 // the text surrounding the deletion.
804 - (DOMRange *)_smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
805 {
806     Node* startContainer = core([proposedRange startContainer]);
807     Node* endContainer = core([proposedRange endContainer]);
808     if (startContainer == nil || endContainer == nil)
809         return nil;
810
811     ASSERT(startContainer->document() == endContainer->document());
812     
813     _private->coreFrame->document()->updateLayoutIgnorePendingStylesheets();
814
815     Position start(startContainer, [proposedRange startOffset]);
816     Position end(endContainer, [proposedRange endOffset]);
817     Position newStart = start.upstream().leadingWhitespacePosition(DOWNSTREAM, true);
818     if (newStart.isNull())
819         newStart = start;
820     Position newEnd = end.downstream().trailingWhitespacePosition(DOWNSTREAM, true);
821     if (newEnd.isNull())
822         newEnd = end;
823
824     newStart = rangeCompliantEquivalent(newStart);
825     newEnd = rangeCompliantEquivalent(newEnd);
826
827     RefPtr<Range> range = _private->coreFrame->document()->createRange();
828     int exception = 0;
829     range->setStart(newStart.node(), newStart.deprecatedEditingOffset(), exception);
830     range->setEnd(newStart.node(), newStart.deprecatedEditingOffset(), exception);
831     return kit(range.get());
832 }
833
834 - (DOMDocumentFragment *)_documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString 
835 {
836     if (!_private->coreFrame || !_private->coreFrame->document())
837         return nil;
838
839     return kit(createFragmentFromMarkup(_private->coreFrame->document(), markupString, baseURLString, FragmentScriptingNotAllowed).get());
840 }
841
842 - (DOMDocumentFragment *)_documentFragmentWithNodesAsParagraphs:(NSArray *)nodes
843 {
844     if (!_private->coreFrame || !_private->coreFrame->document())
845         return nil;
846     
847     NSEnumerator *nodeEnum = [nodes objectEnumerator];
848     Vector<Node*> nodesVector;
849     DOMNode *node;
850     while ((node = [nodeEnum nextObject]))
851         nodesVector.append(core(node));
852     
853     return kit(createFragmentFromNodes(_private->coreFrame->document(), nodesVector).get());
854 }
855
856 - (void)_replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
857 {
858     DOMDocumentFragment *fragment = kit(_private->coreFrame->document()->createDocumentFragment().get());
859     [fragment appendChild:node];
860     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle];
861 }
862
863 - (void)_insertParagraphSeparatorInQuotedContent
864 {
865     if (_private->coreFrame->selection()->isNone())
866         return;
867     
868     TypingCommand::insertParagraphSeparatorInQuotedContent(_private->coreFrame->document());
869     _private->coreFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
870 }
871
872 - (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
873 {
874     // FIXME: Someone with access to Apple's sources could remove this needless wrapper call.
875     return _private->coreFrame->visiblePositionForPoint(IntPoint(point));
876 }
877
878 - (DOMRange *)_characterRangeAtPoint:(NSPoint)point
879 {
880     VisiblePosition position = [self _visiblePositionForPoint:point];
881     if (position.isNull())
882         return nil;
883     
884     VisiblePosition previous = position.previous();
885     if (previous.isNotNull()) {
886         DOMRange *previousCharacterRange = kit(makeRange(previous, position).get());
887         NSRect rect = [self _firstRectForDOMRange:previousCharacterRange];
888         if (NSPointInRect(point, rect))
889             return previousCharacterRange;
890     }
891
892     VisiblePosition next = position.next();
893     if (next.isNotNull()) {
894         DOMRange *nextCharacterRange = kit(makeRange(position, next).get());
895         NSRect rect = [self _firstRectForDOMRange:nextCharacterRange];
896         if (NSPointInRect(point, rect))
897             return nextCharacterRange;
898     }
899     
900     return nil;
901 }
902
903 - (DOMCSSStyleDeclaration *)_typingStyle
904 {
905     if (!_private->coreFrame)
906         return nil;
907     RefPtr<CSSMutableStyleDeclaration> typingStyle = _private->coreFrame->selection()->copyTypingStyle();
908     if (!typingStyle)
909         return nil;
910     return kit(typingStyle.get());
911 }
912
913 - (void)_setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
914 {
915     if (!_private->coreFrame)
916         return;
917     _private->coreFrame->editor()->computeAndSetTypingStyle(core(style), undoAction);
918 }
919
920 - (void)_dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
921 {
922     if (!_private->coreFrame)
923         return;
924     FrameView* view = _private->coreFrame->view();
925     if (!view)
926         return;
927     ASSERT([getWebView(self) _usesDocumentViews]);
928     // FIXME: These are fake modifier keys here, but they should be real ones instead.
929     PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [view->platformWidget() window]),
930         LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());
931     _private->coreFrame->eventHandler()->dragSourceEndedAt(event, (DragOperation)operation);
932 }
933
934 - (BOOL)_canProvideDocumentSource
935 {
936     Frame* frame = _private->coreFrame;
937     String mimeType = frame->loader()->writer()->mimeType();
938     PluginData* pluginData = frame->page() ? frame->page()->pluginData() : 0;
939
940     if (WebCore::DOMImplementation::isTextMIMEType(mimeType) ||
941         Image::supportsType(mimeType) ||
942         (pluginData && pluginData->supportsMimeType(mimeType)))
943         return NO;
944
945     return YES;
946 }
947
948 - (BOOL)_canSaveAsWebArchive
949 {
950     // Currently, all documents that we can view source for
951     // (HTML and XML documents) can also be saved as web archives
952     return [self _canProvideDocumentSource];
953 }
954
955 - (void)_commitData:(NSData *)data
956 {
957     // FIXME: This really should be a setting.
958     Document* document = _private->coreFrame->document();
959     document->setShouldCreateRenderers(_private->shouldCreateRenderers);
960
961     _private->coreFrame->loader()->documentLoader()->commitData((const char *)[data bytes], [data length]);
962 }
963
964 @end
965
966 @implementation WebFrame (WebPrivate)
967
968 // FIXME: This exists only as a convenience for Safari, consider moving there.
969 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
970 {
971     Frame* coreFrame = _private->coreFrame;
972     return coreFrame && coreFrame->tree()->isDescendantOf(core(ancestor));
973 }
974
975 - (void)_setShouldCreateRenderers:(BOOL)shouldCreateRenderers
976 {
977     _private->shouldCreateRenderers = shouldCreateRenderers;
978 }
979
980 - (NSColor *)_bodyBackgroundColor
981 {
982     Document* document = _private->coreFrame->document();
983     if (!document)
984         return nil;
985     HTMLElement* body = document->body();
986     if (!body)
987         return nil;
988     RenderObject* bodyRenderer = body->renderer();
989     if (!bodyRenderer)
990         return nil;
991     Color color = bodyRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
992     if (!color.isValid())
993         return nil;
994     return nsColor(color);
995 }
996
997 - (BOOL)_isFrameSet
998 {
999     Document* document = _private->coreFrame->document();
1000     return document && document->isFrameSet();
1001 }
1002
1003 - (BOOL)_firstLayoutDone
1004 {
1005     return _private->coreFrame->loader()->stateMachine()->firstLayoutDone();
1006 }
1007
1008 - (WebFrameLoadType)_loadType
1009 {
1010     return (WebFrameLoadType)_private->coreFrame->loader()->loadType();
1011 }
1012
1013 - (NSRange)_selectedNSRange
1014 {
1015     return [self _convertToNSRange:_private->coreFrame->selection()->toNormalizedRange().get()];
1016 }
1017
1018 - (void)_selectNSRange:(NSRange)range
1019 {
1020     RefPtr<Range> domRange = [self _convertToDOMRange:range];
1021     if (domRange)
1022         _private->coreFrame->selection()->setSelection(VisibleSelection(domRange.get(), SEL_DEFAULT_AFFINITY));
1023 }
1024
1025 - (BOOL)_isDisplayingStandaloneImage
1026 {
1027     Document* document = _private->coreFrame->document();
1028     return document && document->isImageDocument();
1029 }
1030
1031 - (unsigned)_pendingFrameUnloadEventCount
1032 {
1033     return _private->coreFrame->domWindow()->pendingUnloadEventListeners();
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     frame->animation()->suspendAnimations();
1145 }
1146
1147 - (void) _resumeAnimations
1148 {
1149     Frame* frame = core(self);
1150     if (!frame)
1151         return;
1152
1153     frame->animation()->resumeAnimations();
1154 }
1155
1156 - (void)_replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1157 {
1158     if (_private->coreFrame->selection()->isNone() || !fragment)
1159         return;
1160     
1161     applyCommand(ReplaceSelectionCommand::create(_private->coreFrame->document(), core(fragment), selectReplacement, smartReplace, matchStyle));
1162     _private->coreFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
1163 }
1164
1165 - (void)_replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1166 {   
1167     DOMDocumentFragment* fragment = kit(createFragmentFromText(_private->coreFrame->selection()->toNormalizedRange().get(), text).get());
1168     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
1169 }
1170
1171 - (void)_replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1172 {
1173     DOMDocumentFragment *fragment = [self _documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
1174     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1175 }
1176
1177 // Determines whether whitespace needs to be added around aString to preserve proper spacing and
1178 // punctuation when it's inserted into the receiver's text over charRange. Returns by reference
1179 // in beforeString and afterString any whitespace that should be added, unless either or both are
1180 // nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
1181 - (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1182 {
1183     // give back nil pointers in case of early returns
1184     if (beforeString)
1185         *beforeString = nil;
1186     if (afterString)
1187         *afterString = nil;
1188         
1189     // inspect destination
1190     Node *startContainer = core([rangeToReplace startContainer]);
1191     Node *endContainer = core([rangeToReplace endContainer]);
1192
1193     Position startPos(startContainer, [rangeToReplace startOffset]);
1194     Position endPos(endContainer, [rangeToReplace endOffset]);
1195
1196     VisiblePosition startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
1197     VisiblePosition endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY);
1198     
1199     // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
1200     if (startVisiblePos.isNull() || endVisiblePos.isNull())
1201         return;
1202
1203     bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
1204     if (addLeadingSpace)
1205         if (UChar previousChar = startVisiblePos.previous().characterAfter())
1206             addLeadingSpace = !isCharacterSmartReplaceExempt(previousChar, true);
1207     
1208     bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
1209     if (addTrailingSpace)
1210         if (UChar thisChar = endVisiblePos.characterAfter())
1211             addTrailingSpace = !isCharacterSmartReplaceExempt(thisChar, false);
1212     
1213     // inspect source
1214     bool hasWhitespaceAtStart = false;
1215     bool hasWhitespaceAtEnd = false;
1216     unsigned pasteLength = [pasteString length];
1217     if (pasteLength > 0) {
1218         NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
1219         
1220         if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
1221             hasWhitespaceAtStart = YES;
1222         }
1223         if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
1224             hasWhitespaceAtEnd = YES;
1225         }
1226     }
1227     
1228     // issue the verdict
1229     if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
1230         *beforeString = @" ";
1231     if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
1232         *afterString = @" ";
1233 }
1234
1235 - (NSMutableDictionary *)_cacheabilityDictionary
1236 {
1237     NSMutableDictionary *result = [NSMutableDictionary dictionary];
1238     
1239     FrameLoader* frameLoader = _private->coreFrame->loader();
1240     DocumentLoader* documentLoader = frameLoader->documentLoader();
1241     if (documentLoader && !documentLoader->mainDocumentError().isNull())
1242         [result setObject:(NSError *)documentLoader->mainDocumentError() forKey:WebFrameMainDocumentError];
1243         
1244     if (frameLoader->subframeLoader()->containsPlugins())
1245         [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasPlugins];
1246     
1247     if (DOMWindow* domWindow = _private->coreFrame->domWindow()) {
1248         if (domWindow->hasEventListeners(eventNames().unloadEvent))
1249             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasUnloadListener];
1250             
1251 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1252         if (domWindow->optionalApplicationCache())
1253             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesApplicationCache];
1254 #endif
1255     }
1256     
1257     if (Document* document = _private->coreFrame->document()) {
1258 #if ENABLE(DATABASE)
1259         if (document->hasOpenDatabases())
1260             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesDatabases];
1261 #endif
1262             
1263         if (document->usingGeolocation())
1264             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesGeolocation];
1265             
1266         if (!document->canSuspendActiveDOMObjects())
1267             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameCanSuspendActiveDOMObjects];
1268     }
1269     
1270     return result;
1271 }
1272
1273 - (BOOL)_allowsFollowingLink:(NSURL *)URL
1274 {
1275     if (!_private->coreFrame)
1276         return YES;
1277     return _private->coreFrame->document()->securityOrigin()->canDisplay(URL);
1278 }
1279
1280 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string withGlobalObject:(JSObjectRef)globalObjectRef inScriptWorld:(WebScriptWorld *)world
1281 {
1282     // Start off with some guess at a frame and a global object, we'll try to do better...!
1283     JSDOMWindow* anyWorldGlobalObject = _private->coreFrame->script()->globalObject(mainThreadNormalWorld());
1284
1285     // The global object is probably a shell object? - if so, we know how to use this!
1286     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
1287     if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
1288         anyWorldGlobalObject = static_cast<JSDOMWindowShell*>(globalObjectObj)->window();
1289
1290     // Get the frame frome the global object we've settled on.
1291     Frame* frame = anyWorldGlobalObject->impl()->frame();
1292     ASSERT(frame->document());
1293     JSValue result = frame->script()->executeScriptInWorld(core(world), string, true).jsValue();
1294
1295     if (!frame) // In case the script removed our frame from the page.
1296         return @"";
1297
1298     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
1299     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
1300     // JSEvaluateScript instead, since they have less surprising semantics.
1301     if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
1302         return @"";
1303
1304     JSLock lock(SilenceAssertionsOnly);
1305     return ustringToString(result.toString(anyWorldGlobalObject->globalExec()));
1306 }
1307
1308 - (JSGlobalContextRef)_globalContextForScriptWorld:(WebScriptWorld *)world
1309 {
1310     Frame* coreFrame = _private->coreFrame;
1311     if (!coreFrame)
1312         return 0;
1313     DOMWrapperWorld* coreWorld = core(world);
1314     if (!coreWorld)
1315         return 0;
1316     return toGlobalRef(coreFrame->script()->globalObject(coreWorld)->globalExec());
1317 }
1318
1319 - (void)setAllowsScrollersToOverlapContent:(BOOL)flag
1320 {
1321     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1322     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAllowsScrollersToOverlapContent:flag];
1323 }
1324
1325 - (void)setAlwaysHideHorizontalScroller:(BOOL)flag
1326 {
1327     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1328     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideHorizontalScroller:flag];
1329 }
1330 - (void)setAlwaysHideVerticalScroller:(BOOL)flag
1331 {
1332     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1333     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideVerticalScroller:flag];
1334 }
1335
1336 - (void)setAccessibleName:(NSString *)name
1337 {
1338 #if HAVE(ACCESSIBILITY)
1339     if (!AXObjectCache::accessibilityEnabled())
1340         return;
1341     
1342     RenderView* root = toRenderView(_private->coreFrame->document()->renderer());
1343     if (!root)
1344         return;
1345     
1346     AccessibilityObject* rootObject = _private->coreFrame->document()->axObjectCache()->getOrCreate(root);
1347     String strName(name);
1348     rootObject->setAccessibleName(strName);
1349 #endif
1350 }
1351
1352 - (NSString*)_layerTreeAsText
1353 {
1354     Frame* coreFrame = _private->coreFrame;
1355     if (!coreFrame)
1356         return @"";
1357
1358     return coreFrame->layerTreeAsText();
1359 }
1360
1361 - (BOOL)hasSpellingMarker:(int)from length:(int)length
1362 {
1363     Frame* coreFrame = _private->coreFrame;
1364     if (!coreFrame)
1365         return NO;
1366     return coreFrame->editor()->selectionStartHasSpellingMarkerFor(from, length);
1367 }
1368
1369 @end
1370
1371 @implementation WebFrame
1372
1373 - (id)init
1374 {
1375     return nil;
1376 }
1377
1378 // Should be deprecated.
1379 - (id)initWithName:(NSString *)name webFrameView:(WebFrameView *)view webView:(WebView *)webView
1380 {
1381     return nil;
1382 }
1383
1384 - (void)dealloc
1385 {
1386     if (_private && _private->includedInWebKitStatistics)
1387         --WebFrameCount;
1388
1389     [_private release];
1390
1391     [super dealloc];
1392 }
1393
1394 - (void)finalize
1395 {
1396     if (_private && _private->includedInWebKitStatistics)
1397         --WebFrameCount;
1398
1399     [super finalize];
1400 }
1401
1402 - (NSString *)name
1403 {
1404     Frame* coreFrame = _private->coreFrame;
1405     if (!coreFrame)
1406         return nil;
1407     return coreFrame->tree()->uniqueName();
1408 }
1409
1410 - (WebFrameView *)frameView
1411 {
1412     ASSERT(!getWebView(self) || [getWebView(self) _usesDocumentViews]);
1413     return _private->webFrameView;
1414 }
1415
1416 - (WebView *)webView
1417 {
1418     return getWebView(self);
1419 }
1420
1421 static bool needsMicrosoftMessengerDOMDocumentWorkaround()
1422 {
1423     static bool needsWorkaround = applicationIsMicrosoftMessenger() && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] compare:@"7.1" options:NSNumericSearch] == NSOrderedAscending;
1424     return needsWorkaround;
1425 }
1426
1427 - (DOMDocument *)DOMDocument
1428 {
1429     if (needsMicrosoftMessengerDOMDocumentWorkaround() && !pthread_main_np())
1430         return nil;
1431
1432     Frame* coreFrame = _private->coreFrame;
1433     if (!coreFrame)
1434         return nil;
1435     
1436     // FIXME: <rdar://problem/5145841> When loading a custom view/representation 
1437     // into a web frame, the old document can still be around. This makes sure that
1438     // we'll return nil in those cases.
1439     if (![[self _dataSource] _isDocumentHTML]) 
1440         return nil; 
1441
1442     Document* document = coreFrame->document();
1443     
1444     // According to the documentation, we should return nil if the frame doesn't have a document.
1445     // While full-frame images and plugins do have an underlying HTML document, we return nil here to be
1446     // backwards compatible.
1447     if (document && (document->isPluginDocument() || document->isImageDocument()))
1448         return nil;
1449     
1450     return kit(coreFrame->document());
1451 }
1452
1453 - (DOMHTMLElement *)frameElement
1454 {
1455     Frame* coreFrame = _private->coreFrame;
1456     if (!coreFrame)
1457         return nil;
1458     return kit(coreFrame->ownerElement());
1459 }
1460
1461 - (WebDataSource *)provisionalDataSource
1462 {
1463     Frame* coreFrame = _private->coreFrame;
1464     return coreFrame ? dataSource(coreFrame->loader()->provisionalDocumentLoader()) : nil;
1465 }
1466
1467 - (WebDataSource *)dataSource
1468 {
1469     Frame* coreFrame = _private->coreFrame;
1470     return coreFrame && coreFrame->loader()->frameHasLoaded() ? [self _dataSource] : nil;
1471 }
1472
1473 - (void)loadRequest:(NSURLRequest *)request
1474 {
1475     Frame* coreFrame = _private->coreFrame;
1476     if (!coreFrame)
1477         return;
1478     coreFrame->loader()->load(request, false);
1479 }
1480
1481 static NSURL *createUniqueWebDataURL()
1482 {
1483     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
1484     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
1485     CFRelease(UUIDRef);
1486     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"applewebdata://%@", UUIDString]];
1487     CFRelease(UUIDString);
1488     return URL;
1489 }
1490
1491 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
1492 {
1493     if (!pthread_main_np())
1494         return [[self _webkit_invokeOnMainThread] _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:unreachableURL];
1495     
1496     KURL responseURL;
1497     if (!baseURL) {
1498         baseURL = blankURL();
1499         responseURL = createUniqueWebDataURL();
1500     }
1501     
1502     ResourceRequest request([baseURL absoluteURL]);
1503
1504     // hack because Mail checks for this property to detect data / archive loads
1505     [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest()];
1506
1507     SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData(data), MIMEType, encodingName, [unreachableURL absoluteURL], responseURL);
1508
1509     _private->coreFrame->loader()->load(request, substituteData, false);
1510 }
1511
1512
1513 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
1514 {
1515     WebCoreThreadViolationCheckRoundTwo();
1516     
1517     if (!MIMEType)
1518         MIMEType = @"text/html";
1519     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:nil];
1520 }
1521
1522 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
1523 {
1524     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
1525     [self _loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL unreachableURL:unreachableURL];
1526 }
1527
1528 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
1529 {
1530     WebCoreThreadViolationCheckRoundTwo();
1531
1532     [self _loadHTMLString:string baseURL:baseURL unreachableURL:nil];
1533 }
1534
1535 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
1536 {
1537     WebCoreThreadViolationCheckRoundTwo();
1538
1539     [self _loadHTMLString:string baseURL:baseURL unreachableURL:unreachableURL];
1540 }
1541
1542 - (void)loadArchive:(WebArchive *)archive
1543 {
1544     if (LegacyWebArchive* coreArchive = [archive _coreLegacyWebArchive])
1545         _private->coreFrame->loader()->loadArchive(coreArchive);
1546 }
1547
1548 - (void)stopLoading
1549 {
1550     if (!_private->coreFrame)
1551         return;
1552     _private->coreFrame->loader()->stopForUserCancel();
1553 }
1554
1555 - (void)reload
1556 {
1557     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_RELOAD_FROM_ORIGIN) && applicationIsSafari())
1558         _private->coreFrame->loader()->reload(GetCurrentKeyModifiers() & shiftKey);
1559     else
1560         _private->coreFrame->loader()->reload(false);
1561 }
1562
1563 - (void)reloadFromOrigin
1564 {
1565     _private->coreFrame->loader()->reload(true);
1566 }
1567
1568 - (WebFrame *)findFrameNamed:(NSString *)name
1569 {
1570     Frame* coreFrame = _private->coreFrame;
1571     if (!coreFrame)
1572         return nil;
1573     return kit(coreFrame->tree()->find(name));
1574 }
1575
1576 - (WebFrame *)parentFrame
1577 {
1578     Frame* coreFrame = _private->coreFrame;
1579     if (!coreFrame)
1580         return nil;
1581     return [[kit(coreFrame->tree()->parent()) retain] autorelease];
1582 }
1583
1584 - (NSArray *)childFrames
1585 {
1586     Frame* coreFrame = _private->coreFrame;
1587     if (!coreFrame)
1588         return [NSArray array];
1589     NSMutableArray *children = [NSMutableArray arrayWithCapacity:coreFrame->tree()->childCount()];
1590     for (Frame* child = coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1591         [children addObject:kit(child)];
1592     return children;
1593 }
1594
1595 - (WebScriptObject *)windowObject
1596 {
1597     Frame* coreFrame = _private->coreFrame;
1598     if (!coreFrame)
1599         return 0;
1600     return coreFrame->script()->windowScriptObject();
1601 }
1602
1603 - (JSGlobalContextRef)globalContext
1604 {
1605     Frame* coreFrame = _private->coreFrame;
1606     if (!coreFrame)
1607         return 0;
1608     return toGlobalRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
1609 }
1610
1611 @end