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