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