|
1 /* |
|
2 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. |
|
3 * Copyright (C) 2006 David Smith (catfish.man@gmail.com) |
|
4 * Copyright (C) 2010 Igalia S.L |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions |
|
8 * are met: |
|
9 * |
|
10 * 1. Redistributions of source code must retain the above copyright |
|
11 * notice, this list of conditions and the following disclaimer. |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
|
16 * its contributors may be used to endorse or promote products derived |
|
17 * from this software without specific prior written permission. |
|
18 * |
|
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
|
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
|
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
29 */ |
|
30 |
|
31 #import "WebViewInternal.h" |
|
32 #import "WebViewData.h" |
|
33 |
|
34 #import "DOMCSSStyleDeclarationInternal.h" |
|
35 #import "DOMNodeInternal.h" |
|
36 #import "DOMRangeInternal.h" |
|
37 #import "WebBackForwardListInternal.h" |
|
38 #import "WebBaseNetscapePluginView.h" |
|
39 #import "WebCache.h" |
|
40 #import "WebChromeClient.h" |
|
41 #import "WebContextMenuClient.h" |
|
42 #import "WebDOMOperationsPrivate.h" |
|
43 #import "WebDataSourceInternal.h" |
|
44 #import "WebDatabaseManagerInternal.h" |
|
45 #import "WebDefaultEditingDelegate.h" |
|
46 #import "WebDefaultPolicyDelegate.h" |
|
47 #import "WebDefaultUIDelegate.h" |
|
48 #import "WebDelegateImplementationCaching.h" |
|
49 #import "WebDocument.h" |
|
50 #import "WebDocumentInternal.h" |
|
51 #import "WebDownload.h" |
|
52 #import "WebDownloadInternal.h" |
|
53 #import "WebDragClient.h" |
|
54 #import "WebDynamicScrollBarsViewInternal.h" |
|
55 #import "WebEditingDelegate.h" |
|
56 #import "WebEditorClient.h" |
|
57 #import "WebFormDelegatePrivate.h" |
|
58 #import "WebFrameInternal.h" |
|
59 #import "WebFrameViewInternal.h" |
|
60 #import "WebGeolocationControllerClient.h" |
|
61 #import "WebGeolocationPositionInternal.h" |
|
62 #import "WebHTMLRepresentation.h" |
|
63 #import "WebHTMLViewInternal.h" |
|
64 #import "WebHistoryItemInternal.h" |
|
65 #import "WebIconDatabaseInternal.h" |
|
66 #import "WebInspector.h" |
|
67 #import "WebInspectorClient.h" |
|
68 #import "WebKitErrors.h" |
|
69 #import "WebKitLogging.h" |
|
70 #import "WebKitNSStringExtras.h" |
|
71 #import "WebKitStatisticsPrivate.h" |
|
72 #import "WebKitSystemBits.h" |
|
73 #import "WebKitVersionChecks.h" |
|
74 #import "WebLocalizableStrings.h" |
|
75 #import "WebNSDataExtras.h" |
|
76 #import "WebNSDataExtrasPrivate.h" |
|
77 #import "WebNSDictionaryExtras.h" |
|
78 #import "WebNSEventExtras.h" |
|
79 #import "WebNSObjectExtras.h" |
|
80 #import "WebNSPasteboardExtras.h" |
|
81 #import "WebNSPrintOperationExtras.h" |
|
82 #import "WebNSURLExtras.h" |
|
83 #import "WebNSURLRequestExtras.h" |
|
84 #import "WebNSUserDefaultsExtras.h" |
|
85 #import "WebNSViewExtras.h" |
|
86 #import "WebNodeHighlight.h" |
|
87 #import "WebPDFView.h" |
|
88 #import "WebPanelAuthenticationHandler.h" |
|
89 #import "WebPasteboardHelper.h" |
|
90 #import "WebPlatformStrategies.h" |
|
91 #import "WebPluginDatabase.h" |
|
92 #import "WebPluginHalterClient.h" |
|
93 #import "WebPolicyDelegate.h" |
|
94 #import "WebPreferenceKeysPrivate.h" |
|
95 #import "WebPreferencesPrivate.h" |
|
96 #import "WebScriptDebugDelegate.h" |
|
97 #import "WebScriptWorldInternal.h" |
|
98 #import "WebSystemInterface.h" |
|
99 #import "WebTextCompletionController.h" |
|
100 #import "WebTextIterator.h" |
|
101 #import "WebUIDelegate.h" |
|
102 #import "WebUIDelegatePrivate.h" |
|
103 #import "WebVideoFullscreenController.h" |
|
104 #import <CoreFoundation/CFSet.h> |
|
105 #import <Foundation/NSURLConnection.h> |
|
106 #import <JavaScriptCore/APICast.h> |
|
107 #import <JavaScriptCore/JSValueRef.h> |
|
108 #import <WebCore/AbstractDatabase.h> |
|
109 #import <WebCore/ApplicationCacheStorage.h> |
|
110 #import <WebCore/BackForwardList.h> |
|
111 #import <WebCore/Cache.h> |
|
112 #import <WebCore/ColorMac.h> |
|
113 #import <WebCore/CSSComputedStyleDeclaration.h> |
|
114 #import <WebCore/Cursor.h> |
|
115 #import <WebCore/Document.h> |
|
116 #import <WebCore/DocumentLoader.h> |
|
117 #import <WebCore/DragController.h> |
|
118 #import <WebCore/DragData.h> |
|
119 #import <WebCore/Editor.h> |
|
120 #import <WebCore/EventHandler.h> |
|
121 #import <WebCore/ExceptionHandlers.h> |
|
122 #import <WebCore/FocusController.h> |
|
123 #import <WebCore/Frame.h> |
|
124 #import <WebCore/FrameLoader.h> |
|
125 #import <WebCore/FrameTree.h> |
|
126 #import <WebCore/FrameView.h> |
|
127 #import <WebCore/GCController.h> |
|
128 #import <WebCore/HTMLMediaElement.h> |
|
129 #import <WebCore/HTMLNames.h> |
|
130 #import <WebCore/HistoryItem.h> |
|
131 #import <WebCore/IconDatabase.h> |
|
132 #import <WebCore/JSCSSStyleDeclaration.h> |
|
133 #import <WebCore/JSElement.h> |
|
134 #import <WebCore/Logging.h> |
|
135 #import <WebCore/MIMETypeRegistry.h> |
|
136 #import <WebCore/Page.h> |
|
137 #import <WebCore/PageCache.h> |
|
138 #import <WebCore/PageGroup.h> |
|
139 #import <WebCore/PlatformMouseEvent.h> |
|
140 #import <WebCore/ProgressTracker.h> |
|
141 #import <WebCore/RenderWidget.h> |
|
142 #import <WebCore/ResourceHandle.h> |
|
143 #import <WebCore/RuntimeApplicationChecks.h> |
|
144 #import <WebCore/SchemeRegistry.h> |
|
145 #import <WebCore/ScriptController.h> |
|
146 #import <WebCore/ScriptValue.h> |
|
147 #import <WebCore/SecurityOrigin.h> |
|
148 #import <WebCore/SelectionController.h> |
|
149 #import <WebCore/Settings.h> |
|
150 #import <WebCore/TextResourceDecoder.h> |
|
151 #import <WebCore/ThreadCheck.h> |
|
152 #import <WebCore/WebCoreObjCExtras.h> |
|
153 #import <WebCore/WebCoreView.h> |
|
154 #import <WebCore/Widget.h> |
|
155 #import <WebKit/DOM.h> |
|
156 #import <WebKit/DOMExtensions.h> |
|
157 #import <WebKit/DOMPrivate.h> |
|
158 #import <WebKitSystemInterface.h> |
|
159 #import <mach-o/dyld.h> |
|
160 #import <objc/objc-auto.h> |
|
161 #import <objc/objc-runtime.h> |
|
162 #import <runtime/ArrayPrototype.h> |
|
163 #import <runtime/DateInstance.h> |
|
164 #import <runtime/InitializeThreading.h> |
|
165 #import <runtime/JSLock.h> |
|
166 #import <runtime/JSValue.h> |
|
167 #import <wtf/Assertions.h> |
|
168 #import <wtf/HashTraits.h> |
|
169 #import <wtf/RefCountedLeakCounter.h> |
|
170 #import <wtf/RefPtr.h> |
|
171 #import <wtf/StdLibExtras.h> |
|
172 #import <wtf/Threading.h> |
|
173 |
|
174 #if ENABLE(DASHBOARD_SUPPORT) |
|
175 #import <WebKit/WebDashboardRegion.h> |
|
176 #endif |
|
177 |
|
178 #if ENABLE(CLIENT_BASED_GEOLOCATION) |
|
179 #import <WebCore/GeolocationController.h> |
|
180 #import <WebCore/GeolocationError.h> |
|
181 #endif |
|
182 |
|
183 #if ENABLE(VIDEO) && USE(GSTREAMER) |
|
184 #import <glib.h> |
|
185 #endif |
|
186 |
|
187 @interface NSSpellChecker (WebNSSpellCheckerDetails) |
|
188 - (void)_preflightChosenSpellServer; |
|
189 @end |
|
190 |
|
191 @interface NSView (WebNSViewDetails) |
|
192 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types; |
|
193 - (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta; |
|
194 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo; |
|
195 @end |
|
196 |
|
197 @interface NSWindow (WebNSWindowDetails) |
|
198 - (id)_oldFirstResponderBeforeBecoming; |
|
199 - (void)_enableScreenUpdatesIfNeeded; |
|
200 - (BOOL)_wrapsCarbonWindow; |
|
201 @end |
|
202 |
|
203 using namespace WebCore; |
|
204 using namespace JSC; |
|
205 |
|
206 #if defined(__ppc__) || defined(__ppc64__) |
|
207 #define PROCESSOR "PPC" |
|
208 #elif defined(__i386__) || defined(__x86_64__) |
|
209 #define PROCESSOR "Intel" |
|
210 #else |
|
211 #error Unknown architecture |
|
212 #endif |
|
213 |
|
214 #define FOR_EACH_RESPONDER_SELECTOR(macro) \ |
|
215 macro(alignCenter) \ |
|
216 macro(alignJustified) \ |
|
217 macro(alignLeft) \ |
|
218 macro(alignRight) \ |
|
219 macro(capitalizeWord) \ |
|
220 macro(centerSelectionInVisibleArea) \ |
|
221 macro(changeAttributes) \ |
|
222 macro(changeBaseWritingDirection) \ |
|
223 macro(changeBaseWritingDirectionToLTR) \ |
|
224 macro(changeBaseWritingDirectionToRTL) \ |
|
225 macro(changeColor) \ |
|
226 macro(changeDocumentBackgroundColor) \ |
|
227 macro(changeFont) \ |
|
228 macro(changeSpelling) \ |
|
229 macro(checkSpelling) \ |
|
230 macro(complete) \ |
|
231 macro(copy) \ |
|
232 macro(copyFont) \ |
|
233 macro(cut) \ |
|
234 macro(delete) \ |
|
235 macro(deleteBackward) \ |
|
236 macro(deleteBackwardByDecomposingPreviousCharacter) \ |
|
237 macro(deleteForward) \ |
|
238 macro(deleteToBeginningOfLine) \ |
|
239 macro(deleteToBeginningOfParagraph) \ |
|
240 macro(deleteToEndOfLine) \ |
|
241 macro(deleteToEndOfParagraph) \ |
|
242 macro(deleteToMark) \ |
|
243 macro(deleteWordBackward) \ |
|
244 macro(deleteWordForward) \ |
|
245 macro(ignoreSpelling) \ |
|
246 macro(indent) \ |
|
247 macro(insertBacktab) \ |
|
248 macro(insertLineBreak) \ |
|
249 macro(insertNewline) \ |
|
250 macro(insertNewlineIgnoringFieldEditor) \ |
|
251 macro(insertParagraphSeparator) \ |
|
252 macro(insertTab) \ |
|
253 macro(insertTabIgnoringFieldEditor) \ |
|
254 macro(lowercaseWord) \ |
|
255 macro(makeBaseWritingDirectionLeftToRight) \ |
|
256 macro(makeBaseWritingDirectionRightToLeft) \ |
|
257 macro(makeTextWritingDirectionLeftToRight) \ |
|
258 macro(makeTextWritingDirectionNatural) \ |
|
259 macro(makeTextWritingDirectionRightToLeft) \ |
|
260 macro(moveBackward) \ |
|
261 macro(moveBackwardAndModifySelection) \ |
|
262 macro(moveDown) \ |
|
263 macro(moveDownAndModifySelection) \ |
|
264 macro(moveForward) \ |
|
265 macro(moveForwardAndModifySelection) \ |
|
266 macro(moveLeft) \ |
|
267 macro(moveLeftAndModifySelection) \ |
|
268 macro(moveParagraphBackwardAndModifySelection) \ |
|
269 macro(moveParagraphForwardAndModifySelection) \ |
|
270 macro(moveRight) \ |
|
271 macro(moveRightAndModifySelection) \ |
|
272 macro(moveToBeginningOfDocument) \ |
|
273 macro(moveToBeginningOfDocumentAndModifySelection) \ |
|
274 macro(moveToBeginningOfLine) \ |
|
275 macro(moveToBeginningOfLineAndModifySelection) \ |
|
276 macro(moveToBeginningOfParagraph) \ |
|
277 macro(moveToBeginningOfParagraphAndModifySelection) \ |
|
278 macro(moveToBeginningOfSentence) \ |
|
279 macro(moveToBeginningOfSentenceAndModifySelection) \ |
|
280 macro(moveToEndOfDocument) \ |
|
281 macro(moveToEndOfDocumentAndModifySelection) \ |
|
282 macro(moveToEndOfLine) \ |
|
283 macro(moveToEndOfLineAndModifySelection) \ |
|
284 macro(moveToEndOfParagraph) \ |
|
285 macro(moveToEndOfParagraphAndModifySelection) \ |
|
286 macro(moveToEndOfSentence) \ |
|
287 macro(moveToEndOfSentenceAndModifySelection) \ |
|
288 macro(moveToLeftEndOfLine) \ |
|
289 macro(moveToLeftEndOfLineAndModifySelection) \ |
|
290 macro(moveToRightEndOfLine) \ |
|
291 macro(moveToRightEndOfLineAndModifySelection) \ |
|
292 macro(moveUp) \ |
|
293 macro(moveUpAndModifySelection) \ |
|
294 macro(moveWordBackward) \ |
|
295 macro(moveWordBackwardAndModifySelection) \ |
|
296 macro(moveWordForward) \ |
|
297 macro(moveWordForwardAndModifySelection) \ |
|
298 macro(moveWordLeft) \ |
|
299 macro(moveWordLeftAndModifySelection) \ |
|
300 macro(moveWordRight) \ |
|
301 macro(moveWordRightAndModifySelection) \ |
|
302 macro(outdent) \ |
|
303 macro(orderFrontSubstitutionsPanel) \ |
|
304 macro(pageDown) \ |
|
305 macro(pageDownAndModifySelection) \ |
|
306 macro(pageUp) \ |
|
307 macro(pageUpAndModifySelection) \ |
|
308 macro(paste) \ |
|
309 macro(pasteAsPlainText) \ |
|
310 macro(pasteAsRichText) \ |
|
311 macro(pasteFont) \ |
|
312 macro(performFindPanelAction) \ |
|
313 macro(scrollLineDown) \ |
|
314 macro(scrollLineUp) \ |
|
315 macro(scrollPageDown) \ |
|
316 macro(scrollPageUp) \ |
|
317 macro(scrollToBeginningOfDocument) \ |
|
318 macro(scrollToEndOfDocument) \ |
|
319 macro(selectAll) \ |
|
320 macro(selectLine) \ |
|
321 macro(selectParagraph) \ |
|
322 macro(selectSentence) \ |
|
323 macro(selectToMark) \ |
|
324 macro(selectWord) \ |
|
325 macro(setMark) \ |
|
326 macro(showGuessPanel) \ |
|
327 macro(startSpeaking) \ |
|
328 macro(stopSpeaking) \ |
|
329 macro(subscript) \ |
|
330 macro(superscript) \ |
|
331 macro(swapWithMark) \ |
|
332 macro(takeFindStringFromSelection) \ |
|
333 macro(toggleBaseWritingDirection) \ |
|
334 macro(transpose) \ |
|
335 macro(underline) \ |
|
336 macro(unscript) \ |
|
337 macro(uppercaseWord) \ |
|
338 macro(yank) \ |
|
339 macro(yankAndSelect) \ |
|
340 |
|
341 #define WebKitOriginalTopPrintingMarginKey @"WebKitOriginalTopMargin" |
|
342 #define WebKitOriginalBottomPrintingMarginKey @"WebKitOriginalBottomMargin" |
|
343 |
|
344 #define KeyboardUIModeDidChangeNotification @"com.apple.KeyboardUIModeDidChange" |
|
345 #define AppleKeyboardUIMode CFSTR("AppleKeyboardUIMode") |
|
346 #define UniversalAccessDomain CFSTR("com.apple.universalaccess") |
|
347 |
|
348 static BOOL s_didSetCacheModel; |
|
349 static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer; |
|
350 |
|
351 #ifndef NDEBUG |
|
352 static const char webViewIsOpen[] = "At least one WebView is still open."; |
|
353 #endif |
|
354 |
|
355 @interface NSObject (WebValidateWithoutDelegate) |
|
356 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item; |
|
357 @end |
|
358 |
|
359 @interface _WebSafeForwarder : NSObject |
|
360 { |
|
361 id target; // Non-retained. Don't retain delegates. |
|
362 id defaultTarget; |
|
363 BOOL catchExceptions; |
|
364 } |
|
365 - (id)initWithTarget:(id)target defaultTarget:(id)defaultTarget catchExceptions:(BOOL)catchExceptions; |
|
366 @end |
|
367 |
|
368 @interface WebView (WebFileInternal) |
|
369 - (BOOL)_isLoading; |
|
370 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point; |
|
371 - (WebFrame *)_focusedFrame; |
|
372 + (void)_preflightSpellChecker; |
|
373 - (BOOL)_continuousCheckingAllowed; |
|
374 - (NSResponder *)_responderForResponderOperations; |
|
375 #if USE(ACCELERATED_COMPOSITING) |
|
376 - (void)_clearLayerSyncLoopObserver; |
|
377 #endif |
|
378 #if ENABLE(VIDEO) && USE(GSTREAMER) |
|
379 - (void)_clearGlibLoopObserver; |
|
380 #endif |
|
381 @end |
|
382 |
|
383 static void patchMailRemoveAttributesMethod(); |
|
384 |
|
385 NSString *WebElementDOMNodeKey = @"WebElementDOMNode"; |
|
386 NSString *WebElementFrameKey = @"WebElementFrame"; |
|
387 NSString *WebElementImageKey = @"WebElementImage"; |
|
388 NSString *WebElementImageAltStringKey = @"WebElementImageAltString"; |
|
389 NSString *WebElementImageRectKey = @"WebElementImageRect"; |
|
390 NSString *WebElementImageURLKey = @"WebElementImageURL"; |
|
391 NSString *WebElementIsSelectedKey = @"WebElementIsSelected"; |
|
392 NSString *WebElementLinkLabelKey = @"WebElementLinkLabel"; |
|
393 NSString *WebElementLinkTargetFrameKey = @"WebElementTargetFrame"; |
|
394 NSString *WebElementLinkTitleKey = @"WebElementLinkTitle"; |
|
395 NSString *WebElementLinkURLKey = @"WebElementLinkURL"; |
|
396 NSString *WebElementSpellingToolTipKey = @"WebElementSpellingToolTip"; |
|
397 NSString *WebElementTitleKey = @"WebElementTitle"; |
|
398 NSString *WebElementLinkIsLiveKey = @"WebElementLinkIsLive"; |
|
399 NSString *WebElementIsInScrollBarKey = @"WebElementIsInScrollBar"; |
|
400 NSString *WebElementIsContentEditableKey = @"WebElementIsContentEditableKey"; |
|
401 |
|
402 NSString *WebViewProgressStartedNotification = @"WebProgressStartedNotification"; |
|
403 NSString *WebViewProgressEstimateChangedNotification = @"WebProgressEstimateChangedNotification"; |
|
404 NSString *WebViewProgressFinishedNotification = @"WebProgressFinishedNotification"; |
|
405 |
|
406 NSString * const WebViewDidBeginEditingNotification = @"WebViewDidBeginEditingNotification"; |
|
407 NSString * const WebViewDidChangeNotification = @"WebViewDidChangeNotification"; |
|
408 NSString * const WebViewDidEndEditingNotification = @"WebViewDidEndEditingNotification"; |
|
409 NSString * const WebViewDidChangeTypingStyleNotification = @"WebViewDidChangeTypingStyleNotification"; |
|
410 NSString * const WebViewDidChangeSelectionNotification = @"WebViewDidChangeSelectionNotification"; |
|
411 |
|
412 enum { WebViewVersion = 4 }; |
|
413 |
|
414 #define timedLayoutSize 4096 |
|
415 |
|
416 static NSMutableSet *schemesWithRepresentationsSet; |
|
417 |
|
418 NSString *_WebCanGoBackKey = @"canGoBack"; |
|
419 NSString *_WebCanGoForwardKey = @"canGoForward"; |
|
420 NSString *_WebEstimatedProgressKey = @"estimatedProgress"; |
|
421 NSString *_WebIsLoadingKey = @"isLoading"; |
|
422 NSString *_WebMainFrameIconKey = @"mainFrameIcon"; |
|
423 NSString *_WebMainFrameTitleKey = @"mainFrameTitle"; |
|
424 NSString *_WebMainFrameURLKey = @"mainFrameURL"; |
|
425 NSString *_WebMainFrameDocumentKey = @"mainFrameDocument"; |
|
426 |
|
427 NSString *_WebViewDidStartAcceleratedCompositingNotification = @"_WebViewDidStartAcceleratedCompositing"; |
|
428 |
|
429 @interface WebProgressItem : NSObject |
|
430 { |
|
431 @public |
|
432 long long bytesReceived; |
|
433 long long estimatedLength; |
|
434 } |
|
435 @end |
|
436 |
|
437 @implementation WebProgressItem |
|
438 @end |
|
439 |
|
440 static BOOL continuousSpellCheckingEnabled; |
|
441 #ifndef BUILDING_ON_TIGER |
|
442 static BOOL grammarCheckingEnabled; |
|
443 #endif |
|
444 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) |
|
445 static BOOL automaticQuoteSubstitutionEnabled; |
|
446 static BOOL automaticLinkDetectionEnabled; |
|
447 static BOOL automaticDashSubstitutionEnabled; |
|
448 static BOOL automaticTextReplacementEnabled; |
|
449 static BOOL automaticSpellingCorrectionEnabled; |
|
450 #endif |
|
451 |
|
452 @implementation WebView (AllWebViews) |
|
453 |
|
454 static CFSetCallBacks NonRetainingSetCallbacks = { |
|
455 0, |
|
456 NULL, |
|
457 NULL, |
|
458 CFCopyDescription, |
|
459 CFEqual, |
|
460 CFHash |
|
461 }; |
|
462 |
|
463 static CFMutableSetRef allWebViewsSet; |
|
464 |
|
465 + (void)_makeAllWebViewsPerformSelector:(SEL)selector |
|
466 { |
|
467 if (!allWebViewsSet) |
|
468 return; |
|
469 |
|
470 [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector]; |
|
471 } |
|
472 |
|
473 - (void)_removeFromAllWebViewsSet |
|
474 { |
|
475 if (allWebViewsSet) |
|
476 CFSetRemoveValue(allWebViewsSet, self); |
|
477 } |
|
478 |
|
479 - (void)_addToAllWebViewsSet |
|
480 { |
|
481 if (!allWebViewsSet) |
|
482 allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks); |
|
483 |
|
484 CFSetSetValue(allWebViewsSet, self); |
|
485 } |
|
486 |
|
487 @end |
|
488 |
|
489 @implementation WebView (WebPrivate) |
|
490 |
|
491 static inline int callGestalt(OSType selector) |
|
492 { |
|
493 SInt32 value = 0; |
|
494 Gestalt(selector, &value); |
|
495 return value; |
|
496 } |
|
497 |
|
498 // Uses underscores instead of dots because if "4." ever appears in a user agent string, old DHTML libraries treat it as Netscape 4. |
|
499 static NSString *createMacOSXVersionString() |
|
500 { |
|
501 // Can't use -[NSProcessInfo operatingSystemVersionString] because it has too much stuff we don't want. |
|
502 int major = callGestalt(gestaltSystemVersionMajor); |
|
503 ASSERT(major); |
|
504 |
|
505 int minor = callGestalt(gestaltSystemVersionMinor); |
|
506 int bugFix = callGestalt(gestaltSystemVersionBugFix); |
|
507 if (bugFix) |
|
508 return [[NSString alloc] initWithFormat:@"%d_%d_%d", major, minor, bugFix]; |
|
509 if (minor) |
|
510 return [[NSString alloc] initWithFormat:@"%d_%d", major, minor]; |
|
511 return [[NSString alloc] initWithFormat:@"%d", major]; |
|
512 } |
|
513 |
|
514 static NSString *createUserVisibleWebKitVersionString() |
|
515 { |
|
516 // If the version is 4 digits long or longer, then the first digit represents |
|
517 // the version of the OS. Our user agent string should not include this first digit, |
|
518 // so strip it off and report the rest as the version. <rdar://problem/4997547> |
|
519 NSString *fullVersion = [[NSBundle bundleForClass:[WebView class]] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; |
|
520 NSRange nonDigitRange = [fullVersion rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; |
|
521 if (nonDigitRange.location == NSNotFound && [fullVersion length] >= 4) |
|
522 return [[fullVersion substringFromIndex:1] copy]; |
|
523 if (nonDigitRange.location != NSNotFound && nonDigitRange.location >= 4) |
|
524 return [[fullVersion substringFromIndex:1] copy]; |
|
525 return [fullVersion copy]; |
|
526 } |
|
527 |
|
528 + (NSString *)_standardUserAgentWithApplicationName:(NSString *)applicationName |
|
529 { |
|
530 // Note: Do *not* move the initialization of osVersion nor webKitVersion into the declaration. |
|
531 // Garbage collection won't correctly mark the global variable in that case <rdar://problem/5733674>. |
|
532 static NSString *osVersion; |
|
533 static NSString *webKitVersion; |
|
534 if (!osVersion) |
|
535 osVersion = createMacOSXVersionString(); |
|
536 if (!webKitVersion) |
|
537 webKitVersion = createUserVisibleWebKitVersionString(); |
|
538 NSString *language = [NSUserDefaults _webkit_preferredLanguageCode]; |
|
539 if ([applicationName length]) |
|
540 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko) %@", osVersion, language, webKitVersion, applicationName]; |
|
541 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko)", osVersion, language, webKitVersion]; |
|
542 } |
|
543 |
|
544 + (void)_reportException:(JSValueRef)exception inContext:(JSContextRef)context |
|
545 { |
|
546 if (!exception || !context) |
|
547 return; |
|
548 |
|
549 JSLock lock(SilenceAssertionsOnly); |
|
550 JSC::ExecState* execState = toJS(context); |
|
551 |
|
552 // Make sure the context has a DOMWindow global object, otherwise this context didn't originate from a WebView. |
|
553 if (!toJSDOMWindow(execState->lexicalGlobalObject())) |
|
554 return; |
|
555 |
|
556 reportException(execState, toJS(execState, exception)); |
|
557 } |
|
558 |
|
559 static void WebKitInitializeApplicationCachePathIfNecessary() |
|
560 { |
|
561 #if ENABLE(OFFLINE_WEB_APPLICATIONS) |
|
562 static BOOL initialized = NO; |
|
563 if (initialized) |
|
564 return; |
|
565 |
|
566 NSString *appName = [[NSBundle mainBundle] bundleIdentifier]; |
|
567 if (!appName) |
|
568 appName = [[NSProcessInfo processInfo] processName]; |
|
569 |
|
570 ASSERT(appName); |
|
571 |
|
572 NSString* cacheDir = [NSString _webkit_localCacheDirectoryWithBundleIdentifier:appName]; |
|
573 |
|
574 cacheStorage().setCacheDirectory(cacheDir); |
|
575 initialized = YES; |
|
576 #endif |
|
577 } |
|
578 |
|
579 static bool runningLeopardMail() |
|
580 { |
|
581 #ifdef BUILDING_ON_LEOPARD |
|
582 return applicationIsAppleMail(); |
|
583 #endif |
|
584 return NO; |
|
585 } |
|
586 |
|
587 static bool runningTigerMail() |
|
588 { |
|
589 #ifdef BUILDING_ON_TIGER |
|
590 return applicationIsAppleMail(); |
|
591 #endif |
|
592 return NO; |
|
593 } |
|
594 |
|
595 static bool coreVideoHas7228836Fix() |
|
596 { |
|
597 #ifdef BUILDING_ON_LEOPARD |
|
598 NSBundle* coreVideoFrameworkBundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/CoreVideo.framework"]; |
|
599 double version = [[coreVideoFrameworkBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] doubleValue]; |
|
600 return (version >= 48); |
|
601 #endif |
|
602 return true; |
|
603 } |
|
604 |
|
605 static bool shouldEnableLoadDeferring() |
|
606 { |
|
607 return !applicationIsAdobeInstaller(); |
|
608 } |
|
609 |
|
610 - (void)_dispatchPendingLoadRequests |
|
611 { |
|
612 cache()->loader()->servePendingRequests(); |
|
613 } |
|
614 |
|
615 - (void)_registerDraggedTypes |
|
616 { |
|
617 NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes]; |
|
618 NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL]; |
|
619 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes]; |
|
620 [types addObjectsFromArray:URLTypes]; |
|
621 [self registerForDraggedTypes:[types allObjects]]; |
|
622 [types release]; |
|
623 } |
|
624 |
|
625 - (BOOL)_usesDocumentViews |
|
626 { |
|
627 return _private->usesDocumentViews; |
|
628 } |
|
629 |
|
630 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews |
|
631 { |
|
632 WebCoreThreadViolationCheckRoundTwo(); |
|
633 |
|
634 #ifndef NDEBUG |
|
635 WTF::RefCountedLeakCounter::suppressMessages(webViewIsOpen); |
|
636 #endif |
|
637 |
|
638 WebPreferences *standardPreferences = [WebPreferences standardPreferences]; |
|
639 [standardPreferences willAddToWebView]; |
|
640 |
|
641 _private->preferences = [standardPreferences retain]; |
|
642 _private->catchesDelegateExceptions = YES; |
|
643 _private->mainFrameDocumentReady = NO; |
|
644 _private->drawsBackground = YES; |
|
645 _private->backgroundColor = [[NSColor colorWithDeviceWhite:1 alpha:1] retain]; |
|
646 _private->usesDocumentViews = usesDocumentViews; |
|
647 _private->includesFlattenedCompositingLayersWhenDrawingToBitmap = YES; |
|
648 |
|
649 WebFrameView *frameView = nil; |
|
650 if (_private->usesDocumentViews) { |
|
651 NSRect f = [self frame]; |
|
652 frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)]; |
|
653 [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; |
|
654 [self addSubview:frameView]; |
|
655 [frameView release]; |
|
656 } |
|
657 |
|
658 static bool didOneTimeInitialization = false; |
|
659 if (!didOneTimeInitialization) { |
|
660 WebKitInitializeLoggingChannelsIfNecessary(); |
|
661 WebCore::InitializeLoggingChannelsIfNecessary(); |
|
662 [WebHistoryItem initWindowWatcherIfNecessary]; |
|
663 #if ENABLE(DATABASE) |
|
664 WebKitInitializeDatabasesIfNecessary(); |
|
665 #endif |
|
666 WebKitInitializeApplicationCachePathIfNecessary(); |
|
667 patchMailRemoveAttributesMethod(); |
|
668 |
|
669 // Initialize our platform strategies. |
|
670 WebPlatformStrategies::initialize(); |
|
671 |
|
672 didOneTimeInitialization = true; |
|
673 } |
|
674 |
|
675 #if ENABLE(CLIENT_BASED_GEOLOCATION) |
|
676 WebGeolocationControllerClient* geolocationControllerClient = new WebGeolocationControllerClient(self); |
|
677 #else |
|
678 WebGeolocationControllerClient* geolocationControllerClient = 0; |
|
679 #endif |
|
680 _private->page = new Page(new WebChromeClient(self), new WebContextMenuClient(self), new WebEditorClient(self), new WebDragClient(self), new WebInspectorClient(self), new WebPluginHalterClient(self), geolocationControllerClient, 0, 0); |
|
681 |
|
682 _private->page->setCanStartMedia([self window]); |
|
683 _private->page->settings()->setLocalStorageDatabasePath([[self preferences] _localStorageDatabasePath]); |
|
684 |
|
685 [WebFrame _createMainFrameWithPage:_private->page frameName:frameName frameView:frameView]; |
|
686 |
|
687 #ifndef BUILDING_ON_TIGER |
|
688 NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; |
|
689 #else |
|
690 NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; |
|
691 #endif |
|
692 |
|
693 if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOADING_DURING_COMMON_RUNLOOP_MODES)) |
|
694 [self scheduleInRunLoop:runLoop forMode:(NSString *)kCFRunLoopCommonModes]; |
|
695 else |
|
696 [self scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode]; |
|
697 |
|
698 [self _addToAllWebViewsSet]; |
|
699 [self setGroupName:groupName]; |
|
700 |
|
701 // If there's already a next key view (e.g., from a nib), wire it up to our |
|
702 // contained frame view. In any case, wire our next key view up to the our |
|
703 // contained frame view. This works together with our becomeFirstResponder |
|
704 // and setNextKeyView overrides. |
|
705 NSView *nextKeyView = [self nextKeyView]; |
|
706 if (nextKeyView && nextKeyView != frameView) |
|
707 [frameView setNextKeyView:nextKeyView]; |
|
708 [super setNextKeyView:frameView]; |
|
709 |
|
710 if ([[self class] shouldIncludeInWebKitStatistics]) |
|
711 ++WebViewCount; |
|
712 |
|
713 [self _registerDraggedTypes]; |
|
714 |
|
715 WebPreferences *prefs = [self preferences]; |
|
716 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) |
|
717 name:WebPreferencesChangedNotification object:prefs]; |
|
718 |
|
719 // Post a notification so the WebCore settings update. |
|
720 [[self preferences] _postPreferencesChangesNotification]; |
|
721 |
|
722 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION)) { |
|
723 // Originally, we allowed all local loads. |
|
724 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll); |
|
725 } else if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MORE_STRICT_LOCAL_RESOURCE_SECURITY_RESTRICTION)) { |
|
726 // Later, we allowed local loads for local URLs and documents loaded |
|
727 // with substitute data. |
|
728 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); |
|
729 } |
|
730 |
|
731 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_CONTENT_SNIFFING_FOR_FILE_URLS)) |
|
732 ResourceHandle::forceContentSniffing(); |
|
733 |
|
734 #if ENABLE(VIDEO) && USE(GSTREAMER) |
|
735 [self _scheduleGlibContextIterations]; |
|
736 #endif |
|
737 |
|
738 } |
|
739 |
|
740 - (id)_initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews |
|
741 { |
|
742 self = [super initWithFrame:f]; |
|
743 if (!self) |
|
744 return nil; |
|
745 |
|
746 #ifdef ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH |
|
747 // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which |
|
748 // may not work with other WebKit applications. Unsetting DYLD_FRAMEWORK_PATH removes the |
|
749 // need for Safari to unset it to prevent it from being passed to applications it launches. |
|
750 // Unsetting it when a WebView is first created is as good a place as any. |
|
751 // See <http://bugs.webkit.org/show_bug.cgi?id=4286> for more details. |
|
752 if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) { |
|
753 unsetenv("DYLD_FRAMEWORK_PATH"); |
|
754 unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH"); |
|
755 } |
|
756 #endif |
|
757 |
|
758 _private = [[WebViewPrivate alloc] init]; |
|
759 [self _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:usesDocumentViews]; |
|
760 [self setMaintainsBackForwardList: YES]; |
|
761 return self; |
|
762 } |
|
763 |
|
764 - (BOOL)_mustDrawUnionedRect:(NSRect)rect singleRects:(const NSRect *)rects count:(NSInteger)count |
|
765 { |
|
766 // If count == 0 here, use the rect passed in for drawing. This is a workaround for: |
|
767 // <rdar://problem/3908282> REGRESSION (Mail): No drag image dragging selected text in Blot and Mail |
|
768 // The reason for the workaround is that this method is called explicitly from the code |
|
769 // to generate a drag image, and at that time, getRectsBeingDrawn:count: will return a zero count. |
|
770 const int cRectThreshold = 10; |
|
771 const float cWastedSpaceThreshold = 0.75f; |
|
772 BOOL useUnionedRect = (count <= 1) || (count > cRectThreshold); |
|
773 if (!useUnionedRect) { |
|
774 // Attempt to guess whether or not we should use the unioned rect or the individual rects. |
|
775 // We do this by computing the percentage of "wasted space" in the union. If that wasted space |
|
776 // is too large, then we will do individual rect painting instead. |
|
777 float unionPixels = (rect.size.width * rect.size.height); |
|
778 float singlePixels = 0; |
|
779 for (int i = 0; i < count; ++i) |
|
780 singlePixels += rects[i].size.width * rects[i].size.height; |
|
781 float wastedSpace = 1 - (singlePixels / unionPixels); |
|
782 if (wastedSpace <= cWastedSpaceThreshold) |
|
783 useUnionedRect = YES; |
|
784 } |
|
785 return useUnionedRect; |
|
786 } |
|
787 |
|
788 - (void)drawSingleRect:(NSRect)rect |
|
789 { |
|
790 ASSERT(!_private->usesDocumentViews); |
|
791 |
|
792 [NSGraphicsContext saveGraphicsState]; |
|
793 NSRectClip(rect); |
|
794 |
|
795 @try { |
|
796 [[self mainFrame] _drawRect:rect contentsOnly:NO]; |
|
797 |
|
798 [[self _UIDelegateForwarder] webView:self didDrawRect:rect]; |
|
799 |
|
800 if (WebNodeHighlight *currentHighlight = [self currentNodeHighlight]) |
|
801 [currentHighlight setNeedsUpdateInTargetViewRect:rect]; |
|
802 |
|
803 [NSGraphicsContext restoreGraphicsState]; |
|
804 } @catch (NSException *localException) { |
|
805 [NSGraphicsContext restoreGraphicsState]; |
|
806 LOG_ERROR("Exception caught while drawing: %@", localException); |
|
807 [localException raise]; |
|
808 } |
|
809 } |
|
810 |
|
811 - (BOOL)isFlipped |
|
812 { |
|
813 return _private && !_private->usesDocumentViews; |
|
814 } |
|
815 |
|
816 - (void)setFrameSize:(NSSize)size |
|
817 { |
|
818 if (!_private->usesDocumentViews && !NSEqualSizes(_private->lastLayoutSize, size)) { |
|
819 Frame* frame = [self _mainCoreFrame]; |
|
820 // FIXME: Viewless WebKit is broken with Safari banners (e.g., the Find banner). We'll have to figure out a way for |
|
821 // Safari to communicate that this space is being consumed. For WebKit with document views, there's no |
|
822 // need to do an explicit resize, since WebFrameViews have auto resizing turned on and will handle changing |
|
823 // their bounds automatically. See <rdar://problem/6835573> for details. |
|
824 frame->view()->resize(IntSize(size)); |
|
825 frame->view()->setNeedsLayout(); |
|
826 [self setNeedsDisplay:YES]; |
|
827 _private->lastLayoutSize = size; |
|
828 } |
|
829 |
|
830 [super setFrameSize:size]; |
|
831 } |
|
832 |
|
833 #if USE(ACCELERATED_COMPOSITING) || !defined(BUILDING_ON_TIGER) |
|
834 |
|
835 - (void)_viewWillDrawInternal |
|
836 { |
|
837 Frame* frame = [self _mainCoreFrame]; |
|
838 if (frame && frame->view()) |
|
839 frame->view()->layoutIfNeededRecursive(); |
|
840 } |
|
841 |
|
842 #endif |
|
843 |
|
844 #ifndef BUILDING_ON_TIGER |
|
845 |
|
846 - (void)viewWillDraw |
|
847 { |
|
848 if (!_private->usesDocumentViews) |
|
849 [self _viewWillDrawInternal]; |
|
850 [super viewWillDraw]; |
|
851 } |
|
852 |
|
853 #endif |
|
854 |
|
855 |
|
856 - (void)drawRect:(NSRect)rect |
|
857 { |
|
858 if (_private->usesDocumentViews) |
|
859 return [super drawRect:rect]; |
|
860 |
|
861 ASSERT_MAIN_THREAD(); |
|
862 |
|
863 const NSRect *rects; |
|
864 NSInteger count; |
|
865 [self getRectsBeingDrawn:&rects count:&count]; |
|
866 |
|
867 |
|
868 if ([self _mustDrawUnionedRect:rect singleRects:rects count:count]) |
|
869 [self drawSingleRect:rect]; |
|
870 else |
|
871 for (int i = 0; i < count; ++i) |
|
872 [self drawSingleRect:rects[i]]; |
|
873 } |
|
874 |
|
875 + (NSArray *)_supportedMIMETypes |
|
876 { |
|
877 // Load the plug-in DB allowing plug-ins to install types. |
|
878 [WebPluginDatabase sharedDatabase]; |
|
879 return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys]; |
|
880 } |
|
881 |
|
882 + (NSArray *)_supportedFileExtensions |
|
883 { |
|
884 NSMutableSet *extensions = [[NSMutableSet alloc] init]; |
|
885 NSArray *MIMETypes = [self _supportedMIMETypes]; |
|
886 NSEnumerator *enumerator = [MIMETypes objectEnumerator]; |
|
887 NSString *MIMEType; |
|
888 while ((MIMEType = [enumerator nextObject]) != nil) { |
|
889 NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType); |
|
890 if (extensionsForType) { |
|
891 [extensions addObjectsFromArray:extensionsForType]; |
|
892 } |
|
893 } |
|
894 NSArray *uniqueExtensions = [extensions allObjects]; |
|
895 [extensions release]; |
|
896 return uniqueExtensions; |
|
897 } |
|
898 |
|
899 static NSMutableSet *knownPluginMIMETypes() |
|
900 { |
|
901 static NSMutableSet *mimeTypes = [[NSMutableSet alloc] init]; |
|
902 |
|
903 return mimeTypes; |
|
904 } |
|
905 |
|
906 + (void)_registerPluginMIMEType:(NSString *)MIMEType |
|
907 { |
|
908 [WebView registerViewClass:[WebHTMLView class] representationClass:[WebHTMLRepresentation class] forMIMEType:MIMEType]; |
|
909 [knownPluginMIMETypes() addObject:MIMEType]; |
|
910 } |
|
911 |
|
912 + (void)_unregisterPluginMIMEType:(NSString *)MIMEType |
|
913 { |
|
914 [self _unregisterViewClassAndRepresentationClassForMIMEType:MIMEType]; |
|
915 [knownPluginMIMETypes() removeObject:MIMEType]; |
|
916 } |
|
917 |
|
918 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins |
|
919 { |
|
920 MIMEType = [MIMEType lowercaseString]; |
|
921 Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType]; |
|
922 Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType]; |
|
923 |
|
924 if (!viewClass || !repClass || [[WebPDFView supportedMIMETypes] containsObject:MIMEType]) { |
|
925 // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed. |
|
926 |
|
927 if (allowPlugins) { |
|
928 // Load the plug-in DB allowing plug-ins to install types. |
|
929 [WebPluginDatabase sharedDatabase]; |
|
930 } |
|
931 |
|
932 // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types. |
|
933 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType]; |
|
934 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType]; |
|
935 } |
|
936 |
|
937 if (viewClass && repClass) { |
|
938 if (viewClass == [WebHTMLView class] && repClass == [WebHTMLRepresentation class]) { |
|
939 // Special-case WebHTMLView for text types that shouldn't be shown. |
|
940 if ([[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType]) |
|
941 return NO; |
|
942 |
|
943 // If the MIME type is a known plug-in we might not want to load it. |
|
944 if (!allowPlugins && [knownPluginMIMETypes() containsObject:MIMEType]) { |
|
945 BOOL isSupportedByWebKit = [[WebHTMLView supportedNonImageMIMETypes] containsObject:MIMEType] || |
|
946 [[WebHTMLView supportedMIMETypes] containsObject:MIMEType]; |
|
947 |
|
948 // If this is a known plug-in MIME type and WebKit can't show it natively, we don't want to show it. |
|
949 if (!isSupportedByWebKit) |
|
950 return NO; |
|
951 } |
|
952 } |
|
953 if (vClass) |
|
954 *vClass = viewClass; |
|
955 if (rClass) |
|
956 *rClass = repClass; |
|
957 return YES; |
|
958 } |
|
959 |
|
960 return NO; |
|
961 } |
|
962 |
|
963 - (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType |
|
964 { |
|
965 if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType allowingPlugins:[_private->preferences arePlugInsEnabled]]) |
|
966 return YES; |
|
967 |
|
968 if (_private->pluginDatabase) { |
|
969 WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType]; |
|
970 if (pluginPackage) { |
|
971 if (vClass) |
|
972 *vClass = [WebHTMLView class]; |
|
973 if (rClass) |
|
974 *rClass = [WebHTMLRepresentation class]; |
|
975 return YES; |
|
976 } |
|
977 } |
|
978 |
|
979 return NO; |
|
980 } |
|
981 |
|
982 + (void)_setAlwaysUseATSU:(BOOL)f |
|
983 { |
|
984 [self _setAlwaysUsesComplexTextCodePath:f]; |
|
985 } |
|
986 |
|
987 + (void)_setAlwaysUsesComplexTextCodePath:(BOOL)f |
|
988 { |
|
989 Font::setCodePath(f ? Font::Complex : Font::Auto); |
|
990 } |
|
991 |
|
992 + (BOOL)canCloseAllWebViews |
|
993 { |
|
994 return DOMWindow::dispatchAllPendingBeforeUnloadEvents(); |
|
995 } |
|
996 |
|
997 + (void)closeAllWebViews |
|
998 { |
|
999 DOMWindow::dispatchAllPendingUnloadEvents(); |
|
1000 |
|
1001 // This will close the WebViews in a random order. Change this if close order is important. |
|
1002 // Make a new set to avoid mutating the set we are enumerating. |
|
1003 NSSet *webViewsToClose = [NSSet setWithSet:(NSSet *)allWebViewsSet]; |
|
1004 NSEnumerator *enumerator = [webViewsToClose objectEnumerator]; |
|
1005 while (WebView *webView = [enumerator nextObject]) |
|
1006 [webView close]; |
|
1007 } |
|
1008 |
|
1009 + (BOOL)canShowFile:(NSString *)path |
|
1010 { |
|
1011 return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]]; |
|
1012 } |
|
1013 |
|
1014 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type |
|
1015 { |
|
1016 return WKGetPreferredExtensionForMIMEType(type); |
|
1017 } |
|
1018 |
|
1019 - (BOOL)_isClosed |
|
1020 { |
|
1021 return !_private || _private->closed; |
|
1022 } |
|
1023 |
|
1024 - (void)_closePluginDatabases |
|
1025 { |
|
1026 pluginDatabaseClientCount--; |
|
1027 |
|
1028 // Close both sets of plug-in databases because plug-ins need an opportunity to clean up files, etc. |
|
1029 |
|
1030 // Unload the WebView local plug-in database. |
|
1031 if (_private->pluginDatabase) { |
|
1032 [_private->pluginDatabase destroyAllPluginInstanceViews]; |
|
1033 [_private->pluginDatabase close]; |
|
1034 [_private->pluginDatabase release]; |
|
1035 _private->pluginDatabase = nil; |
|
1036 } |
|
1037 |
|
1038 // Keep the global plug-in database active until the app terminates to avoid having to reload plug-in bundles. |
|
1039 if (!pluginDatabaseClientCount && applicationIsTerminating) |
|
1040 [WebPluginDatabase closeSharedDatabase]; |
|
1041 } |
|
1042 |
|
1043 - (void)_closeWithFastTeardown |
|
1044 { |
|
1045 #ifndef NDEBUG |
|
1046 WTF::RefCountedLeakCounter::suppressMessages("At least one WebView was closed with fast teardown."); |
|
1047 #endif |
|
1048 |
|
1049 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; |
|
1050 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
|
1051 |
|
1052 [self _closePluginDatabases]; |
|
1053 } |
|
1054 |
|
1055 static bool fastDocumentTeardownEnabled() |
|
1056 { |
|
1057 #ifdef NDEBUG |
|
1058 static bool enabled = ![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; |
|
1059 #else |
|
1060 static bool initialized = false; |
|
1061 static bool enabled = false; |
|
1062 if (!initialized) { |
|
1063 // This allows debug builds to default to not have fast teardown, so leak checking still works. |
|
1064 // But still allow the WebKitEnableFullDocumentTeardown default to override it if present. |
|
1065 NSNumber *setting = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; |
|
1066 if (setting) |
|
1067 enabled = ![setting boolValue]; |
|
1068 initialized = true; |
|
1069 } |
|
1070 #endif |
|
1071 return enabled; |
|
1072 } |
|
1073 |
|
1074 // _close is here only for backward compatibility; clients and subclasses should use |
|
1075 // public method -close instead. |
|
1076 - (void)_close |
|
1077 { |
|
1078 if (!_private || _private->closed) |
|
1079 return; |
|
1080 |
|
1081 _private->closed = YES; |
|
1082 [self _removeFromAllWebViewsSet]; |
|
1083 |
|
1084 [self _closingEventHandling]; |
|
1085 |
|
1086 #ifndef NDEBUG |
|
1087 WTF::RefCountedLeakCounter::cancelMessageSuppression(webViewIsOpen); |
|
1088 #endif |
|
1089 |
|
1090 // To quit the apps fast we skip document teardown, except plugins |
|
1091 // need to be destroyed and unloaded. |
|
1092 if (applicationIsTerminating && fastDocumentTeardownEnabled()) { |
|
1093 [self _closeWithFastTeardown]; |
|
1094 return; |
|
1095 } |
|
1096 |
|
1097 #if ENABLE(VIDEO) |
|
1098 [self _exitFullscreen]; |
|
1099 #endif |
|
1100 |
|
1101 if (Frame* mainFrame = [self _mainCoreFrame]) |
|
1102 mainFrame->loader()->detachFromParent(); |
|
1103 |
|
1104 [self setHostWindow:nil]; |
|
1105 |
|
1106 [self setDownloadDelegate:nil]; |
|
1107 [self setEditingDelegate:nil]; |
|
1108 [self setFrameLoadDelegate:nil]; |
|
1109 [self setPolicyDelegate:nil]; |
|
1110 [self setResourceLoadDelegate:nil]; |
|
1111 [self setScriptDebugDelegate:nil]; |
|
1112 [self setUIDelegate:nil]; |
|
1113 |
|
1114 [_private->inspector webViewClosed]; |
|
1115 |
|
1116 // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint. |
|
1117 [self removeDragCaret]; |
|
1118 |
|
1119 // Deleteing the WebCore::Page will clear the page cache so we call destroy on |
|
1120 // all the plug-ins in the page cache to break any retain cycles. |
|
1121 // See comment in HistoryItem::releaseAllPendingPageCaches() for more information. |
|
1122 Page* page = _private->page; |
|
1123 _private->page = 0; |
|
1124 delete page; |
|
1125 |
|
1126 if (_private->hasSpellCheckerDocumentTag) { |
|
1127 [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag]; |
|
1128 _private->hasSpellCheckerDocumentTag = NO; |
|
1129 } |
|
1130 |
|
1131 #if USE(ACCELERATED_COMPOSITING) |
|
1132 [self _clearLayerSyncLoopObserver]; |
|
1133 #endif |
|
1134 |
|
1135 #if ENABLE(VIDEO) && USE(GSTREAMER) |
|
1136 [self _clearGlibLoopObserver]; |
|
1137 #endif |
|
1138 |
|
1139 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; |
|
1140 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
|
1141 |
|
1142 [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]]; |
|
1143 |
|
1144 WebPreferences *preferences = _private->preferences; |
|
1145 _private->preferences = nil; |
|
1146 [preferences didRemoveFromWebView]; |
|
1147 [preferences release]; |
|
1148 |
|
1149 [self _closePluginDatabases]; |
|
1150 |
|
1151 #ifndef NDEBUG |
|
1152 // Need this to make leak messages accurate. |
|
1153 if (applicationIsTerminating) { |
|
1154 gcController().garbageCollectNow(); |
|
1155 [WebCache setDisabled:YES]; |
|
1156 } |
|
1157 #endif |
|
1158 } |
|
1159 |
|
1160 // Indicates if the WebView is in the midst of a user gesture. |
|
1161 - (BOOL)_isProcessingUserGesture |
|
1162 { |
|
1163 WebFrame *frame = [self mainFrame]; |
|
1164 return core(frame)->loader()->isProcessingUserGesture(); |
|
1165 } |
|
1166 |
|
1167 + (NSString *)_MIMETypeForFile:(NSString *)path |
|
1168 { |
|
1169 NSString *extension = [path pathExtension]; |
|
1170 NSString *MIMEType = nil; |
|
1171 |
|
1172 // Get the MIME type from the extension. |
|
1173 if ([extension length] != 0) { |
|
1174 MIMEType = WKGetMIMETypeForExtension(extension); |
|
1175 } |
|
1176 |
|
1177 // If we can't get a known MIME type from the extension, sniff. |
|
1178 if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) { |
|
1179 NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; |
|
1180 NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH]; |
|
1181 [handle closeFile]; |
|
1182 if ([data length] != 0) { |
|
1183 MIMEType = [data _webkit_guessedMIMEType]; |
|
1184 } |
|
1185 if ([MIMEType length] == 0) { |
|
1186 MIMEType = @"application/octet-stream"; |
|
1187 } |
|
1188 } |
|
1189 |
|
1190 return MIMEType; |
|
1191 } |
|
1192 |
|
1193 - (WebDownload *)_downloadURL:(NSURL *)URL |
|
1194 { |
|
1195 ASSERT(URL); |
|
1196 |
|
1197 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL]; |
|
1198 WebDownload *download = [WebDownload _downloadWithRequest:request |
|
1199 delegate:_private->downloadDelegate |
|
1200 directory:nil]; |
|
1201 [request release]; |
|
1202 |
|
1203 return download; |
|
1204 } |
|
1205 |
|
1206 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request |
|
1207 { |
|
1208 NSDictionary *features = [[NSDictionary alloc] init]; |
|
1209 WebView *newWindowWebView = [[self _UIDelegateForwarder] webView:self |
|
1210 createWebViewWithRequest:nil |
|
1211 windowFeatures:features]; |
|
1212 [features release]; |
|
1213 if (!newWindowWebView) |
|
1214 return nil; |
|
1215 |
|
1216 CallUIDelegate(newWindowWebView, @selector(webViewShow:)); |
|
1217 return newWindowWebView; |
|
1218 } |
|
1219 |
|
1220 - (WebInspector *)inspector |
|
1221 { |
|
1222 if (!_private->inspector) |
|
1223 _private->inspector = [[WebInspector alloc] initWithWebView:self]; |
|
1224 return _private->inspector; |
|
1225 } |
|
1226 |
|
1227 - (WebCore::Page*)page |
|
1228 { |
|
1229 return _private->page; |
|
1230 } |
|
1231 |
|
1232 - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items |
|
1233 { |
|
1234 NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate] webView:self contextMenuItemsForElement:element defaultMenuItems:items]; |
|
1235 |
|
1236 NSArray *menuItems = CallUIDelegate(self, @selector(webView:contextMenuItemsForElement:defaultMenuItems:), element, defaultMenuItems); |
|
1237 if (!menuItems) |
|
1238 return nil; |
|
1239 |
|
1240 unsigned count = [menuItems count]; |
|
1241 if (!count) |
|
1242 return nil; |
|
1243 |
|
1244 NSMenu *menu = [[NSMenu alloc] init]; |
|
1245 for (unsigned i = 0; i < count; i++) |
|
1246 [menu addItem:[menuItems objectAtIndex:i]]; |
|
1247 |
|
1248 return [menu autorelease]; |
|
1249 } |
|
1250 |
|
1251 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(NSUInteger)modifierFlags |
|
1252 { |
|
1253 // We originally intended to call this delegate method sometimes with a nil dictionary, but due to |
|
1254 // a bug dating back to WebKit 1.0 this delegate was never called with nil! Unfortunately we can't |
|
1255 // start calling this with nil since it will break Adobe Help Viewer, and possibly other clients. |
|
1256 if (!dictionary) |
|
1257 return; |
|
1258 CallUIDelegate(self, @selector(webView:mouseDidMoveOverElement:modifierFlags:), dictionary, modifierFlags); |
|
1259 } |
|
1260 |
|
1261 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView |
|
1262 { |
|
1263 if (!_private->page) |
|
1264 return; |
|
1265 |
|
1266 if (!otherView->_private->page) |
|
1267 return; |
|
1268 |
|
1269 // It turns out the right combination of behavior is done with the back/forward load |
|
1270 // type. (See behavior matrix at the top of WebFramePrivate.) So we copy all the items |
|
1271 // in the back forward list, and go to the current one. |
|
1272 |
|
1273 BackForwardList* backForwardList = _private->page->backForwardList(); |
|
1274 ASSERT(!backForwardList->currentItem()); // destination list should be empty |
|
1275 |
|
1276 BackForwardList* otherBackForwardList = otherView->_private->page->backForwardList(); |
|
1277 if (!otherBackForwardList->currentItem()) |
|
1278 return; // empty back forward list, bail |
|
1279 |
|
1280 HistoryItem* newItemToGoTo = 0; |
|
1281 |
|
1282 int lastItemIndex = otherBackForwardList->forwardListCount(); |
|
1283 for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) { |
|
1284 if (i == 0) { |
|
1285 // If this item is showing , save away its current scroll and form state, |
|
1286 // since that might have changed since loading and it is normally not saved |
|
1287 // until we leave that page. |
|
1288 otherView->_private->page->mainFrame()->loader()->history()->saveDocumentAndScrollState(); |
|
1289 } |
|
1290 RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy(); |
|
1291 if (i == 0) |
|
1292 newItemToGoTo = newItem.get(); |
|
1293 backForwardList->addItem(newItem.release()); |
|
1294 } |
|
1295 |
|
1296 ASSERT(newItemToGoTo); |
|
1297 _private->page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward); |
|
1298 } |
|
1299 |
|
1300 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate |
|
1301 { |
|
1302 _private->formDelegate = delegate; |
|
1303 } |
|
1304 |
|
1305 - (id<WebFormDelegate>)_formDelegate |
|
1306 { |
|
1307 return _private->formDelegate; |
|
1308 } |
|
1309 |
|
1310 - (BOOL)_needsAdobeFrameReloadingQuirk |
|
1311 { |
|
1312 static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0) |
|
1313 || WKAppVersionCheckLessThan(@"com.adobe.Acrobat.Pro", -1, 9.0) |
|
1314 || WKAppVersionCheckLessThan(@"com.adobe.Reader", -1, 9.0) |
|
1315 || WKAppVersionCheckLessThan(@"com.adobe.distiller", -1, 9.0) |
|
1316 || WKAppVersionCheckLessThan(@"com.adobe.Contribute", -1, 4.2) |
|
1317 || WKAppVersionCheckLessThan(@"com.adobe.dreamweaver-9.0", -1, 9.1) |
|
1318 || WKAppVersionCheckLessThan(@"com.macromedia.fireworks", -1, 9.1) |
|
1319 || WKAppVersionCheckLessThan(@"com.adobe.InCopy", -1, 5.1) |
|
1320 || WKAppVersionCheckLessThan(@"com.adobe.InDesign", -1, 5.1) |
|
1321 || WKAppVersionCheckLessThan(@"com.adobe.Soundbooth", -1, 2); |
|
1322 |
|
1323 return needsQuirk; |
|
1324 } |
|
1325 |
|
1326 - (BOOL)_needsLinkElementTextCSSQuirk |
|
1327 { |
|
1328 static BOOL needsQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LINK_ELEMENT_TEXT_CSS_QUIRK) |
|
1329 && WKAppVersionCheckLessThan(@"com.e-frontier.shade10", -1, 10.6); |
|
1330 return needsQuirk; |
|
1331 } |
|
1332 |
|
1333 - (BOOL)_needsKeyboardEventDisambiguationQuirks |
|
1334 { |
|
1335 static BOOL needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH) && !applicationIsSafari(); |
|
1336 return needsQuirks; |
|
1337 } |
|
1338 |
|
1339 - (BOOL)_needsFrameLoadDelegateRetainQuirk |
|
1340 { |
|
1341 static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.equinux.iSale5", -1, 5.6); |
|
1342 return needsQuirk; |
|
1343 } |
|
1344 |
|
1345 - (void)_preferencesChangedNotification:(NSNotification *)notification |
|
1346 { |
|
1347 WebPreferences *preferences = (WebPreferences *)[notification object]; |
|
1348 ASSERT(preferences == [self preferences]); |
|
1349 |
|
1350 if (!_private->userAgentOverridden) |
|
1351 _private->userAgent = String(); |
|
1352 |
|
1353 // Cache this value so we don't have to read NSUserDefaults on each page load |
|
1354 _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing]; |
|
1355 |
|
1356 // Update corresponding WebCore Settings object. |
|
1357 if (!_private->page) |
|
1358 return; |
|
1359 |
|
1360 Settings* settings = _private->page->settings(); |
|
1361 |
|
1362 settings->setCursiveFontFamily([preferences cursiveFontFamily]); |
|
1363 settings->setDefaultFixedFontSize([preferences defaultFixedFontSize]); |
|
1364 settings->setDefaultFontSize([preferences defaultFontSize]); |
|
1365 settings->setDefaultTextEncodingName([preferences defaultTextEncodingName]); |
|
1366 settings->setUsesEncodingDetector([preferences usesEncodingDetector]); |
|
1367 settings->setFantasyFontFamily([preferences fantasyFontFamily]); |
|
1368 settings->setFixedFontFamily([preferences fixedFontFamily]); |
|
1369 settings->setForceFTPDirectoryListings([preferences _forceFTPDirectoryListings]); |
|
1370 settings->setFTPDirectoryTemplatePath([preferences _ftpDirectoryTemplatePath]); |
|
1371 settings->setLocalStorageDatabasePath([preferences _localStorageDatabasePath]); |
|
1372 settings->setJavaEnabled([preferences isJavaEnabled]); |
|
1373 settings->setJavaScriptEnabled([preferences isJavaScriptEnabled]); |
|
1374 settings->setWebSecurityEnabled([preferences isWebSecurityEnabled]); |
|
1375 settings->setAllowUniversalAccessFromFileURLs([preferences allowUniversalAccessFromFileURLs]); |
|
1376 settings->setAllowFileAccessFromFileURLs([preferences allowFileAccessFromFileURLs]); |
|
1377 settings->setJavaScriptCanOpenWindowsAutomatically([preferences javaScriptCanOpenWindowsAutomatically]); |
|
1378 settings->setMinimumFontSize([preferences minimumFontSize]); |
|
1379 settings->setMinimumLogicalFontSize([preferences minimumLogicalFontSize]); |
|
1380 settings->setPluginsEnabled([preferences arePlugInsEnabled]); |
|
1381 #if ENABLE(DATABASE) |
|
1382 AbstractDatabase::setIsAvailable([preferences databasesEnabled]); |
|
1383 #endif |
|
1384 settings->setLocalStorageEnabled([preferences localStorageEnabled]); |
|
1385 settings->setExperimentalNotificationsEnabled([preferences experimentalNotificationsEnabled]); |
|
1386 settings->setPrivateBrowsingEnabled([preferences privateBrowsingEnabled]); |
|
1387 settings->setSansSerifFontFamily([preferences sansSerifFontFamily]); |
|
1388 settings->setSerifFontFamily([preferences serifFontFamily]); |
|
1389 settings->setStandardFontFamily([preferences standardFontFamily]); |
|
1390 settings->setLoadsImagesAutomatically([preferences loadsImagesAutomatically]); |
|
1391 settings->setShouldPrintBackgrounds([preferences shouldPrintBackgrounds]); |
|
1392 settings->setTextAreasAreResizable([preferences textAreasAreResizable]); |
|
1393 settings->setShrinksStandaloneImagesToFit([preferences shrinksStandaloneImagesToFit]); |
|
1394 settings->setEditableLinkBehavior(core([preferences editableLinkBehavior])); |
|
1395 settings->setEditingBehaviorType(core([preferences editingBehavior])); |
|
1396 settings->setTextDirectionSubmenuInclusionBehavior(core([preferences textDirectionSubmenuInclusionBehavior])); |
|
1397 settings->setDOMPasteAllowed([preferences isDOMPasteAllowed]); |
|
1398 settings->setUsesPageCache([self usesPageCache]); |
|
1399 settings->setShowsURLsInToolTips([preferences showsURLsInToolTips]); |
|
1400 settings->setDeveloperExtrasEnabled([preferences developerExtrasEnabled]); |
|
1401 settings->setAuthorAndUserStylesEnabled([preferences authorAndUserStylesEnabled]); |
|
1402 settings->setApplicationChromeMode([preferences applicationChromeModeEnabled]); |
|
1403 if ([preferences userStyleSheetEnabled]) { |
|
1404 NSString* location = [[preferences userStyleSheetLocation] _web_originalDataAsString]; |
|
1405 if ([location isEqualToString:@"apple-dashboard://stylesheet"]) |
|
1406 location = @"file:///System/Library/PrivateFrameworks/DashboardClient.framework/Resources/widget.css"; |
|
1407 settings->setUserStyleSheetLocation([NSURL URLWithString:(location ? location : @"")]); |
|
1408 } else |
|
1409 settings->setUserStyleSheetLocation([NSURL URLWithString:@""]); |
|
1410 settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]); |
|
1411 settings->setTreatsAnyTextCSSLinkAsStylesheet([self _needsLinkElementTextCSSQuirk]); |
|
1412 settings->setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]); |
|
1413 settings->setNeedsLeopardMailQuirks(runningLeopardMail()); |
|
1414 settings->setNeedsTigerMailQuirks(runningTigerMail()); |
|
1415 settings->setNeedsSiteSpecificQuirks(_private->useSiteSpecificSpoofing); |
|
1416 settings->setWebArchiveDebugModeEnabled([preferences webArchiveDebugModeEnabled]); |
|
1417 settings->setLocalFileContentSniffingEnabled([preferences localFileContentSniffingEnabled]); |
|
1418 settings->setOfflineWebApplicationCacheEnabled([preferences offlineWebApplicationCacheEnabled]); |
|
1419 settings->setZoomMode([preferences zoomsTextOnly] ? ZoomTextOnly : ZoomPage); |
|
1420 settings->setJavaScriptCanAccessClipboard([preferences javaScriptCanAccessClipboard]); |
|
1421 settings->setXSSAuditorEnabled([preferences isXSSAuditorEnabled]); |
|
1422 settings->setEnforceCSSMIMETypeInStrictMode(!WKAppVersionCheckLessThan(@"com.apple.iWeb", -1, 2.1)); |
|
1423 settings->setDNSPrefetchingEnabled([preferences isDNSPrefetchingEnabled]); |
|
1424 |
|
1425 // FIXME: Enabling accelerated compositing when WebGL is enabled causes tests to fail on Leopard which expect HW compositing to be disabled. |
|
1426 // Until we fix that, I will comment out the test (CFM) |
|
1427 settings->setAcceleratedCompositingEnabled((coreVideoHas7228836Fix() || [preferences webGLEnabled]) && [preferences acceleratedCompositingEnabled]); |
|
1428 settings->setShowDebugBorders([preferences showDebugBorders]); |
|
1429 settings->setShowRepaintCounter([preferences showRepaintCounter]); |
|
1430 settings->setPluginAllowedRunTime([preferences pluginAllowedRunTime]); |
|
1431 settings->setWebGLEnabled([preferences webGLEnabled]); |
|
1432 settings->setLoadDeferringEnabled(shouldEnableLoadDeferring()); |
|
1433 settings->setFrameFlatteningEnabled([preferences isFrameFlatteningEnabled]); |
|
1434 settings->setHTML5ParserEnabled([preferences html5ParserEnabled]); |
|
1435 settings->setHTML5TreeBuilderEnabled_DO_NOT_USE([preferences html5TreeBuilderEnabled]); |
|
1436 settings->setPaginateDuringLayoutEnabled([preferences paginateDuringLayoutEnabled]); |
|
1437 settings->setMemoryInfoEnabled([preferences memoryInfoEnabled]); |
|
1438 } |
|
1439 |
|
1440 static inline IMP getMethod(id o, SEL s) |
|
1441 { |
|
1442 return [o respondsToSelector:s] ? [o methodForSelector:s] : 0; |
|
1443 } |
|
1444 |
|
1445 - (void)_cacheResourceLoadDelegateImplementations |
|
1446 { |
|
1447 WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations; |
|
1448 id delegate = _private->resourceProgressDelegate; |
|
1449 |
|
1450 if (!delegate) { |
|
1451 bzero(cache, sizeof(WebResourceDelegateImplementationCache)); |
|
1452 return; |
|
1453 } |
|
1454 |
|
1455 cache->didCancelAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)); |
|
1456 cache->didFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFailLoadingWithError:fromDataSource:)); |
|
1457 cache->didFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFinishLoadingFromDataSource:)); |
|
1458 cache->didLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:)); |
|
1459 cache->didReceiveAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)); |
|
1460 #if USE(PROTECTION_SPACE_AUTH_CALLBACK) |
|
1461 cache->canAuthenticateAgainstProtectionSpaceFunc = getMethod(delegate, @selector(webView:resource:canAuthenticateAgainstProtectionSpace:forDataSource:)); |
|
1462 #endif |
|
1463 cache->didReceiveContentLengthFunc = getMethod(delegate, @selector(webView:resource:didReceiveContentLength:fromDataSource:)); |
|
1464 cache->didReceiveResponseFunc = getMethod(delegate, @selector(webView:resource:didReceiveResponse:fromDataSource:)); |
|
1465 cache->identifierForRequestFunc = getMethod(delegate, @selector(webView:identifierForInitialRequest:fromDataSource:)); |
|
1466 cache->plugInFailedWithErrorFunc = getMethod(delegate, @selector(webView:plugInFailedWithError:dataSource:)); |
|
1467 cache->willCacheResponseFunc = getMethod(delegate, @selector(webView:resource:willCacheResponse:fromDataSource:)); |
|
1468 cache->willSendRequestFunc = getMethod(delegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)); |
|
1469 cache->shouldUseCredentialStorageFunc = getMethod(delegate, @selector(webView:resource:shouldUseCredentialStorageForDataSource:)); |
|
1470 } |
|
1471 |
|
1472 - (void)_cacheFrameLoadDelegateImplementations |
|
1473 { |
|
1474 WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations; |
|
1475 id delegate = _private->frameLoadDelegate; |
|
1476 |
|
1477 if (!delegate) { |
|
1478 bzero(cache, sizeof(WebFrameLoadDelegateImplementationCache)); |
|
1479 return; |
|
1480 } |
|
1481 |
|
1482 cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:)); |
|
1483 cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:)); |
|
1484 cache->didPushStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPushStateWithinPageForFrame:)); |
|
1485 cache->didReplaceStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didReplaceStateWithinPageForFrame:)); |
|
1486 cache->didPopStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPopStateWithinPageForFrame:)); |
|
1487 cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:)); |
|
1488 cache->didClearWindowObjectForFrameInScriptWorldFunc = getMethod(delegate, @selector(webView:didClearWindowObjectForFrame:inScriptWorld:)); |
|
1489 cache->didClearInspectorWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearInspectorWindowObject:forFrame:)); |
|
1490 cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:)); |
|
1491 cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:)); |
|
1492 cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:)); |
|
1493 cache->didFinishDocumentLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishDocumentLoadForFrame:)); |
|
1494 cache->didFinishLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishLoadForFrame:)); |
|
1495 cache->didFirstLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstLayoutInFrame:)); |
|
1496 cache->didFirstVisuallyNonEmptyLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstVisuallyNonEmptyLayoutInFrame:)); |
|
1497 cache->didHandleOnloadEventsForFrameFunc = getMethod(delegate, @selector(webView:didHandleOnloadEventsForFrame:)); |
|
1498 cache->didReceiveIconForFrameFunc = getMethod(delegate, @selector(webView:didReceiveIcon:forFrame:)); |
|
1499 cache->didReceiveServerRedirectForProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:)); |
|
1500 cache->didReceiveTitleForFrameFunc = getMethod(delegate, @selector(webView:didReceiveTitle:forFrame:)); |
|
1501 cache->didStartProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didStartProvisionalLoadForFrame:)); |
|
1502 cache->willCloseFrameFunc = getMethod(delegate, @selector(webView:willCloseFrame:)); |
|
1503 cache->willPerformClientRedirectToURLDelayFireDateForFrameFunc = getMethod(delegate, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:)); |
|
1504 cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:)); |
|
1505 cache->didDisplayInsecureContentFunc = getMethod(delegate, @selector(webViewDidDisplayInsecureContent:)); |
|
1506 cache->didRunInsecureContentFunc = getMethod(delegate, @selector(webView:didRunInsecureContent:)); |
|
1507 } |
|
1508 |
|
1509 - (void)_cacheScriptDebugDelegateImplementations |
|
1510 { |
|
1511 WebScriptDebugDelegateImplementationCache *cache = &_private->scriptDebugDelegateImplementations; |
|
1512 id delegate = _private->scriptDebugDelegate; |
|
1513 |
|
1514 if (!delegate) { |
|
1515 bzero(cache, sizeof(WebScriptDebugDelegateImplementationCache)); |
|
1516 return; |
|
1517 } |
|
1518 |
|
1519 cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:)); |
|
1520 if (cache->didParseSourceFunc) |
|
1521 cache->didParseSourceExpectsBaseLineNumber = YES; |
|
1522 else |
|
1523 cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:)); |
|
1524 |
|
1525 cache->failedToParseSourceFunc = getMethod(delegate, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:)); |
|
1526 cache->didEnterCallFrameFunc = getMethod(delegate, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:)); |
|
1527 cache->willExecuteStatementFunc = getMethod(delegate, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:)); |
|
1528 cache->willLeaveCallFrameFunc = getMethod(delegate, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:)); |
|
1529 cache->exceptionWasRaisedFunc = getMethod(delegate, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:)); |
|
1530 } |
|
1531 |
|
1532 - (void)_cacheHistoryDelegateImplementations |
|
1533 { |
|
1534 WebHistoryDelegateImplementationCache *cache = &_private->historyDelegateImplementations; |
|
1535 id delegate = _private->historyDelegate; |
|
1536 |
|
1537 if (!delegate) { |
|
1538 bzero(cache, sizeof(WebHistoryDelegateImplementationCache)); |
|
1539 return; |
|
1540 } |
|
1541 |
|
1542 cache->navigatedFunc = getMethod(delegate, @selector(webView:didNavigateWithNavigationData:inFrame:)); |
|
1543 cache->clientRedirectFunc = getMethod(delegate, @selector(webView:didPerformClientRedirectFromURL:toURL:inFrame:)); |
|
1544 cache->serverRedirectFunc = getMethod(delegate, @selector(webView:didPerformServerRedirectFromURL:toURL:inFrame:)); |
|
1545 cache->setTitleFunc = getMethod(delegate, @selector(webView:updateHistoryTitle:forURL:)); |
|
1546 cache->populateVisitedLinksFunc = getMethod(delegate, @selector(populateVisitedLinksForWebView:)); |
|
1547 } |
|
1548 |
|
1549 - (id)_policyDelegateForwarder |
|
1550 { |
|
1551 if (!_private->policyDelegateForwarder) |
|
1552 _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->policyDelegate defaultTarget:[WebDefaultPolicyDelegate sharedPolicyDelegate] catchExceptions:_private->catchesDelegateExceptions]; |
|
1553 return _private->policyDelegateForwarder; |
|
1554 } |
|
1555 |
|
1556 - (id)_UIDelegateForwarder |
|
1557 { |
|
1558 if (!_private->UIDelegateForwarder) |
|
1559 _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIDelegate defaultTarget:[WebDefaultUIDelegate sharedUIDelegate] catchExceptions:_private->catchesDelegateExceptions]; |
|
1560 return _private->UIDelegateForwarder; |
|
1561 } |
|
1562 |
|
1563 - (id)_editingDelegateForwarder |
|
1564 { |
|
1565 // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in. |
|
1566 // Not sure if that is a bug or not. |
|
1567 if (!_private) |
|
1568 return nil; |
|
1569 |
|
1570 if (!_private->editingDelegateForwarder) |
|
1571 _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->editingDelegate defaultTarget:[WebDefaultEditingDelegate sharedEditingDelegate] catchExceptions:_private->catchesDelegateExceptions]; |
|
1572 return _private->editingDelegateForwarder; |
|
1573 } |
|
1574 |
|
1575 - (void)_closeWindow |
|
1576 { |
|
1577 [[self _UIDelegateForwarder] webViewClose:self]; |
|
1578 } |
|
1579 |
|
1580 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType |
|
1581 { |
|
1582 [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType]; |
|
1583 [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType]; |
|
1584 |
|
1585 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) |
|
1586 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner |
|
1587 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness |
|
1588 MIMETypeRegistry::getSupportedNonImageMIMETypes().remove(MIMEType); |
|
1589 } |
|
1590 |
|
1591 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme |
|
1592 { |
|
1593 NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme]; |
|
1594 [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType]; |
|
1595 |
|
1596 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) |
|
1597 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner |
|
1598 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness |
|
1599 if ([viewClass class] == [WebHTMLView class]) |
|
1600 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType); |
|
1601 |
|
1602 // This is used to make _representationExistsForURLScheme faster. |
|
1603 // Without this set, we'd have to create the MIME type each time. |
|
1604 if (schemesWithRepresentationsSet == nil) { |
|
1605 schemesWithRepresentationsSet = [[NSMutableSet alloc] init]; |
|
1606 } |
|
1607 [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]]; |
|
1608 } |
|
1609 |
|
1610 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme |
|
1611 { |
|
1612 return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]]; |
|
1613 } |
|
1614 |
|
1615 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme |
|
1616 { |
|
1617 return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]]; |
|
1618 } |
|
1619 |
|
1620 + (BOOL)_canHandleRequest:(NSURLRequest *)request forMainFrame:(BOOL)forMainFrame |
|
1621 { |
|
1622 // FIXME: If <rdar://problem/5217309> gets fixed, this check can be removed. |
|
1623 if (!request) |
|
1624 return NO; |
|
1625 |
|
1626 if ([NSURLConnection canHandleRequest:request]) |
|
1627 return YES; |
|
1628 |
|
1629 NSString *scheme = [[request URL] scheme]; |
|
1630 |
|
1631 // Representations for URL schemes work at the top level. |
|
1632 if (forMainFrame && [self _representationExistsForURLScheme:scheme]) |
|
1633 return YES; |
|
1634 |
|
1635 return [scheme _webkit_isCaseInsensitiveEqualToString:@"applewebdata"]; |
|
1636 } |
|
1637 |
|
1638 + (BOOL)_canHandleRequest:(NSURLRequest *)request |
|
1639 { |
|
1640 return [self _canHandleRequest:request forMainFrame:YES]; |
|
1641 } |
|
1642 |
|
1643 + (NSString *)_decodeData:(NSData *)data |
|
1644 { |
|
1645 HTMLNames::init(); // this method is used for importing bookmarks at startup, so HTMLNames are likely to be uninitialized yet |
|
1646 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/html"); // bookmark files are HTML |
|
1647 String result = decoder->decode(static_cast<const char*>([data bytes]), [data length]); |
|
1648 result += decoder->flush(); |
|
1649 return result; |
|
1650 } |
|
1651 |
|
1652 - (void)_pushPerformingProgrammaticFocus |
|
1653 { |
|
1654 _private->programmaticFocusCount++; |
|
1655 } |
|
1656 |
|
1657 - (void)_popPerformingProgrammaticFocus |
|
1658 { |
|
1659 _private->programmaticFocusCount--; |
|
1660 } |
|
1661 |
|
1662 - (BOOL)_isPerformingProgrammaticFocus |
|
1663 { |
|
1664 return _private->programmaticFocusCount != 0; |
|
1665 } |
|
1666 |
|
1667 - (void)_didChangeValueForKey: (NSString *)key |
|
1668 { |
|
1669 LOG (Bindings, "calling didChangeValueForKey: %@", key); |
|
1670 [self didChangeValueForKey: key]; |
|
1671 } |
|
1672 |
|
1673 - (void)_willChangeValueForKey: (NSString *)key |
|
1674 { |
|
1675 LOG (Bindings, "calling willChangeValueForKey: %@", key); |
|
1676 [self willChangeValueForKey: key]; |
|
1677 } |
|
1678 |
|
1679 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { |
|
1680 static NSSet *manualNotifyKeys = nil; |
|
1681 if (!manualNotifyKeys) |
|
1682 manualNotifyKeys = [[NSSet alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, |
|
1683 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, |
|
1684 nil]; |
|
1685 if ([manualNotifyKeys containsObject:key]) |
|
1686 return NO; |
|
1687 return YES; |
|
1688 } |
|
1689 |
|
1690 - (NSArray *)_declaredKeys { |
|
1691 static NSArray *declaredKeys = nil; |
|
1692 if (!declaredKeys) |
|
1693 declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, |
|
1694 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil]; |
|
1695 return declaredKeys; |
|
1696 } |
|
1697 |
|
1698 - (void)setObservationInfo:(void *)info |
|
1699 { |
|
1700 _private->observationInfo = info; |
|
1701 } |
|
1702 |
|
1703 - (void *)observationInfo |
|
1704 { |
|
1705 return _private->observationInfo; |
|
1706 } |
|
1707 |
|
1708 - (void)_willChangeBackForwardKeys |
|
1709 { |
|
1710 [self _willChangeValueForKey: _WebCanGoBackKey]; |
|
1711 [self _willChangeValueForKey: _WebCanGoForwardKey]; |
|
1712 } |
|
1713 |
|
1714 - (void)_didChangeBackForwardKeys |
|
1715 { |
|
1716 [self _didChangeValueForKey: _WebCanGoBackKey]; |
|
1717 [self _didChangeValueForKey: _WebCanGoForwardKey]; |
|
1718 } |
|
1719 |
|
1720 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame |
|
1721 { |
|
1722 [self _willChangeBackForwardKeys]; |
|
1723 if (frame == [self mainFrame]){ |
|
1724 // Force an observer update by sending a will/did. |
|
1725 [self _willChangeValueForKey: _WebIsLoadingKey]; |
|
1726 [self _didChangeValueForKey: _WebIsLoadingKey]; |
|
1727 |
|
1728 [self _willChangeValueForKey: _WebMainFrameURLKey]; |
|
1729 } |
|
1730 |
|
1731 [NSApp setWindowsNeedUpdate:YES]; |
|
1732 } |
|
1733 |
|
1734 - (void)_didCommitLoadForFrame:(WebFrame *)frame |
|
1735 { |
|
1736 if (frame == [self mainFrame]) |
|
1737 [self _didChangeValueForKey: _WebMainFrameURLKey]; |
|
1738 [NSApp setWindowsNeedUpdate:YES]; |
|
1739 } |
|
1740 |
|
1741 - (void)_didFinishLoadForFrame:(WebFrame *)frame |
|
1742 { |
|
1743 [self _didChangeBackForwardKeys]; |
|
1744 if (frame == [self mainFrame]){ |
|
1745 // Force an observer update by sending a will/did. |
|
1746 [self _willChangeValueForKey: _WebIsLoadingKey]; |
|
1747 [self _didChangeValueForKey: _WebIsLoadingKey]; |
|
1748 } |
|
1749 [NSApp setWindowsNeedUpdate:YES]; |
|
1750 } |
|
1751 |
|
1752 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame |
|
1753 { |
|
1754 [self _didChangeBackForwardKeys]; |
|
1755 if (frame == [self mainFrame]){ |
|
1756 // Force an observer update by sending a will/did. |
|
1757 [self _willChangeValueForKey: _WebIsLoadingKey]; |
|
1758 [self _didChangeValueForKey: _WebIsLoadingKey]; |
|
1759 } |
|
1760 [NSApp setWindowsNeedUpdate:YES]; |
|
1761 } |
|
1762 |
|
1763 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame |
|
1764 { |
|
1765 [self _didChangeBackForwardKeys]; |
|
1766 if (frame == [self mainFrame]){ |
|
1767 // Force an observer update by sending a will/did. |
|
1768 [self _willChangeValueForKey: _WebIsLoadingKey]; |
|
1769 [self _didChangeValueForKey: _WebIsLoadingKey]; |
|
1770 |
|
1771 [self _didChangeValueForKey: _WebMainFrameURLKey]; |
|
1772 } |
|
1773 [NSApp setWindowsNeedUpdate:YES]; |
|
1774 } |
|
1775 |
|
1776 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL |
|
1777 { |
|
1778 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL]; |
|
1779 [request _web_setHTTPUserAgent:[self userAgentForURL:URL]]; |
|
1780 NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; |
|
1781 [request release]; |
|
1782 return cachedResponse; |
|
1783 } |
|
1784 |
|
1785 - (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard |
|
1786 { |
|
1787 NSURL *linkURL = [element objectForKey:WebElementLinkURLKey]; |
|
1788 DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey]; |
|
1789 [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey]) |
|
1790 element:domElement |
|
1791 URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey] |
|
1792 title:[element objectForKey:WebElementImageAltStringKey] |
|
1793 archive:[[element objectForKey:WebElementDOMNodeKey] webArchive] |
|
1794 types:types |
|
1795 source:nil]; |
|
1796 } |
|
1797 |
|
1798 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard |
|
1799 { |
|
1800 [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey] |
|
1801 andTitle:[element objectForKey:WebElementLinkLabelKey] |
|
1802 types:types]; |
|
1803 } |
|
1804 |
|
1805 - (void)_setInitiatedDrag:(BOOL)initiatedDrag |
|
1806 { |
|
1807 if (!_private->page) |
|
1808 return; |
|
1809 _private->page->dragController()->setDidInitiateDrag(initiatedDrag); |
|
1810 } |
|
1811 |
|
1812 #if ENABLE(DASHBOARD_SUPPORT) |
|
1813 |
|
1814 #define DASHBOARD_CONTROL_LABEL @"control" |
|
1815 |
|
1816 - (void)_addControlRect:(NSRect)bounds clip:(NSRect)clip fromView:(NSView *)view toDashboardRegions:(NSMutableDictionary *)regions |
|
1817 { |
|
1818 NSRect adjustedBounds = bounds; |
|
1819 adjustedBounds.origin = [self convertPoint:bounds.origin fromView:view]; |
|
1820 adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y; |
|
1821 adjustedBounds.size = bounds.size; |
|
1822 |
|
1823 NSRect adjustedClip; |
|
1824 adjustedClip.origin = [self convertPoint:clip.origin fromView:view]; |
|
1825 adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y; |
|
1826 adjustedClip.size = clip.size; |
|
1827 |
|
1828 WebDashboardRegion *region = [[WebDashboardRegion alloc] initWithRect:adjustedBounds |
|
1829 clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle]; |
|
1830 NSMutableArray *scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL]; |
|
1831 if (!scrollerRegions) { |
|
1832 scrollerRegions = [[NSMutableArray alloc] init]; |
|
1833 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL]; |
|
1834 [scrollerRegions release]; |
|
1835 } |
|
1836 [scrollerRegions addObject:region]; |
|
1837 [region release]; |
|
1838 } |
|
1839 |
|
1840 - (void)_addScrollerDashboardRegionsForFrameView:(FrameView*)frameView dashboardRegions:(NSMutableDictionary *)regions |
|
1841 { |
|
1842 NSView *documentView = [[kit(frameView->frame()) frameView] documentView]; |
|
1843 |
|
1844 const HashSet<RefPtr<Widget> >* children = frameView->children(); |
|
1845 HashSet<RefPtr<Widget> >::const_iterator end = children->end(); |
|
1846 for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { |
|
1847 Widget* widget = (*it).get(); |
|
1848 if (widget->isFrameView()) { |
|
1849 [self _addScrollerDashboardRegionsForFrameView:static_cast<FrameView*>(widget) dashboardRegions:regions]; |
|
1850 continue; |
|
1851 } |
|
1852 |
|
1853 if (!widget->isScrollbar()) |
|
1854 continue; |
|
1855 |
|
1856 // FIXME: This should really pass an appropriate clip, but our first try got it wrong, and |
|
1857 // it's not common to need this to be correct in Dashboard widgets. |
|
1858 NSRect bounds = widget->frameRect(); |
|
1859 [self _addControlRect:bounds clip:bounds fromView:documentView toDashboardRegions:regions]; |
|
1860 } |
|
1861 } |
|
1862 |
|
1863 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views |
|
1864 { |
|
1865 // Add scroller regions for NSScroller and WebCore scrollbars |
|
1866 NSUInteger count = [views count]; |
|
1867 for (NSUInteger i = 0; i < count; i++) { |
|
1868 NSView *view = [views objectAtIndex:i]; |
|
1869 |
|
1870 if ([view isKindOfClass:[WebHTMLView class]]) { |
|
1871 if (Frame* coreFrame = core([(WebHTMLView*)view _frame])) { |
|
1872 if (FrameView* coreView = coreFrame->view()) |
|
1873 [self _addScrollerDashboardRegionsForFrameView:coreView dashboardRegions:regions]; |
|
1874 } |
|
1875 } else if ([view isKindOfClass:[NSScroller class]]) { |
|
1876 // AppKit places absent scrollers at -100,-100 |
|
1877 if ([view frame].origin.y < 0) |
|
1878 continue; |
|
1879 [self _addControlRect:[view bounds] clip:[view visibleRect] fromView:view toDashboardRegions:regions]; |
|
1880 } |
|
1881 [self _addScrollerDashboardRegions:regions from:[view subviews]]; |
|
1882 } |
|
1883 } |
|
1884 |
|
1885 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions |
|
1886 { |
|
1887 [self _addScrollerDashboardRegions:regions from:[self subviews]]; |
|
1888 } |
|
1889 |
|
1890 - (NSDictionary *)_dashboardRegions |
|
1891 { |
|
1892 // Only return regions from main frame. |
|
1893 Frame* mainFrame = [self _mainCoreFrame]; |
|
1894 if (!mainFrame) |
|
1895 return nil; |
|
1896 NSMutableDictionary *regions = mainFrame->dashboardRegionsDictionary(); |
|
1897 [self _addScrollerDashboardRegions:regions]; |
|
1898 return regions; |
|
1899 } |
|
1900 |
|
1901 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag |
|
1902 { |
|
1903 // FIXME: Remove this blanket assignment once Dashboard and Dashcode implement |
|
1904 // specific support for the backward compatibility mode flag. |
|
1905 if (behavior == WebDashboardBehaviorAllowWheelScrolling && flag == NO && _private->page) |
|
1906 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(true); |
|
1907 |
|
1908 switch (behavior) { |
|
1909 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: { |
|
1910 _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag; |
|
1911 break; |
|
1912 } |
|
1913 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: { |
|
1914 _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag; |
|
1915 break; |
|
1916 } |
|
1917 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: { |
|
1918 _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag; |
|
1919 break; |
|
1920 } |
|
1921 case WebDashboardBehaviorAllowWheelScrolling: { |
|
1922 _private->dashboardBehaviorAllowWheelScrolling = flag; |
|
1923 break; |
|
1924 } |
|
1925 case WebDashboardBehaviorUseBackwardCompatibilityMode: { |
|
1926 if (_private->page) |
|
1927 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(flag); |
|
1928 break; |
|
1929 } |
|
1930 } |
|
1931 } |
|
1932 |
|
1933 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior |
|
1934 { |
|
1935 switch (behavior) { |
|
1936 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: { |
|
1937 return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows; |
|
1938 } |
|
1939 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: { |
|
1940 return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns; |
|
1941 } |
|
1942 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: { |
|
1943 return _private->dashboardBehaviorAlwaysAcceptsFirstMouse; |
|
1944 } |
|
1945 case WebDashboardBehaviorAllowWheelScrolling: { |
|
1946 return _private->dashboardBehaviorAllowWheelScrolling; |
|
1947 } |
|
1948 case WebDashboardBehaviorUseBackwardCompatibilityMode: { |
|
1949 return _private->page && _private->page->settings()->usesDashboardBackwardCompatibilityMode(); |
|
1950 } |
|
1951 } |
|
1952 return NO; |
|
1953 } |
|
1954 |
|
1955 #endif /* ENABLE(DASHBOARD_SUPPORT) */ |
|
1956 |
|
1957 + (void)_setShouldUseFontSmoothing:(BOOL)f |
|
1958 { |
|
1959 Font::setShouldUseSmoothing(f); |
|
1960 } |
|
1961 |
|
1962 + (BOOL)_shouldUseFontSmoothing |
|
1963 { |
|
1964 return Font::shouldUseSmoothing(); |
|
1965 } |
|
1966 |
|
1967 + (void)_setUsesTestModeFocusRingColor:(BOOL)f |
|
1968 { |
|
1969 setUsesTestModeFocusRingColor(f); |
|
1970 } |
|
1971 |
|
1972 + (BOOL)_usesTestModeFocusRingColor |
|
1973 { |
|
1974 return usesTestModeFocusRingColor(); |
|
1975 } |
|
1976 |
|
1977 - (void)setAlwaysShowVerticalScroller:(BOOL)flag |
|
1978 { |
|
1979 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; |
|
1980 if (flag) { |
|
1981 [scrollview setVerticalScrollingMode:ScrollbarAlwaysOn andLock:YES]; |
|
1982 } else { |
|
1983 [scrollview setVerticalScrollingModeLocked:NO]; |
|
1984 [scrollview setVerticalScrollingMode:ScrollbarAuto andLock:NO]; |
|
1985 } |
|
1986 } |
|
1987 |
|
1988 - (BOOL)alwaysShowVerticalScroller |
|
1989 { |
|
1990 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; |
|
1991 return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == ScrollbarAlwaysOn; |
|
1992 } |
|
1993 |
|
1994 - (void)setAlwaysShowHorizontalScroller:(BOOL)flag |
|
1995 { |
|
1996 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; |
|
1997 if (flag) { |
|
1998 [scrollview setHorizontalScrollingMode:ScrollbarAlwaysOn andLock:YES]; |
|
1999 } else { |
|
2000 [scrollview setHorizontalScrollingModeLocked:NO]; |
|
2001 [scrollview setHorizontalScrollingMode:ScrollbarAuto andLock:NO]; |
|
2002 } |
|
2003 } |
|
2004 |
|
2005 - (void)setProhibitsMainFrameScrolling:(BOOL)prohibits |
|
2006 { |
|
2007 if (Frame* mainFrame = [self _mainCoreFrame]) |
|
2008 mainFrame->view()->setProhibitsScrolling(prohibits); |
|
2009 } |
|
2010 |
|
2011 - (BOOL)alwaysShowHorizontalScroller |
|
2012 { |
|
2013 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; |
|
2014 return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == ScrollbarAlwaysOn; |
|
2015 } |
|
2016 |
|
2017 - (void)_setInViewSourceMode:(BOOL)flag |
|
2018 { |
|
2019 if (Frame* mainFrame = [self _mainCoreFrame]) |
|
2020 mainFrame->setInViewSourceMode(flag); |
|
2021 } |
|
2022 |
|
2023 - (BOOL)_inViewSourceMode |
|
2024 { |
|
2025 Frame* mainFrame = [self _mainCoreFrame]; |
|
2026 return mainFrame && mainFrame->inViewSourceMode(); |
|
2027 } |
|
2028 |
|
2029 - (void)_setUseFastImageScalingMode:(BOOL)flag |
|
2030 { |
|
2031 if (_private->page && _private->page->inLowQualityImageInterpolationMode() != flag) { |
|
2032 _private->page->setInLowQualityImageInterpolationMode(flag); |
|
2033 [self setNeedsDisplay:YES]; |
|
2034 } |
|
2035 } |
|
2036 |
|
2037 - (BOOL)_inFastImageScalingMode |
|
2038 { |
|
2039 if (_private->page) |
|
2040 return _private->page->inLowQualityImageInterpolationMode(); |
|
2041 return NO; |
|
2042 } |
|
2043 |
|
2044 - (BOOL)_cookieEnabled |
|
2045 { |
|
2046 if (_private->page) |
|
2047 return _private->page->cookieEnabled(); |
|
2048 return YES; |
|
2049 } |
|
2050 |
|
2051 - (void)_setCookieEnabled:(BOOL)enable |
|
2052 { |
|
2053 if (_private->page) |
|
2054 _private->page->setCookieEnabled(enable); |
|
2055 } |
|
2056 |
|
2057 - (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths |
|
2058 { |
|
2059 if (!_private->pluginDatabase) |
|
2060 _private->pluginDatabase = [[WebPluginDatabase alloc] init]; |
|
2061 |
|
2062 [_private->pluginDatabase setPlugInPaths:newPaths]; |
|
2063 [_private->pluginDatabase refresh]; |
|
2064 } |
|
2065 |
|
2066 - (void)_attachScriptDebuggerToAllFrames |
|
2067 { |
|
2068 for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) |
|
2069 [kit(frame) _attachScriptDebugger]; |
|
2070 } |
|
2071 |
|
2072 - (void)_detachScriptDebuggerFromAllFrames |
|
2073 { |
|
2074 for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) |
|
2075 [kit(frame) _detachScriptDebugger]; |
|
2076 } |
|
2077 |
|
2078 - (void)setBackgroundColor:(NSColor *)backgroundColor |
|
2079 { |
|
2080 if ([_private->backgroundColor isEqual:backgroundColor]) |
|
2081 return; |
|
2082 |
|
2083 id old = _private->backgroundColor; |
|
2084 _private->backgroundColor = [backgroundColor retain]; |
|
2085 [old release]; |
|
2086 |
|
2087 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; |
|
2088 } |
|
2089 |
|
2090 - (NSColor *)backgroundColor |
|
2091 { |
|
2092 return _private->backgroundColor; |
|
2093 } |
|
2094 |
|
2095 - (BOOL)defersCallbacks |
|
2096 { |
|
2097 if (!_private->page) |
|
2098 return NO; |
|
2099 return _private->page->defersLoading(); |
|
2100 } |
|
2101 |
|
2102 - (void)setDefersCallbacks:(BOOL)defer |
|
2103 { |
|
2104 if (!_private->page) |
|
2105 return; |
|
2106 return _private->page->setDefersLoading(defer); |
|
2107 } |
|
2108 |
|
2109 // For backwards compatibility with the WebBackForwardList API, we honor both |
|
2110 // a per-WebView and a per-preferences setting for whether to use the page cache. |
|
2111 |
|
2112 - (BOOL)usesPageCache |
|
2113 { |
|
2114 return _private->usesPageCache && [[self preferences] usesPageCache]; |
|
2115 } |
|
2116 |
|
2117 - (void)setUsesPageCache:(BOOL)usesPageCache |
|
2118 { |
|
2119 _private->usesPageCache = usesPageCache; |
|
2120 |
|
2121 // Post a notification so the WebCore settings update. |
|
2122 [[self preferences] _postPreferencesChangesNotification]; |
|
2123 } |
|
2124 |
|
2125 - (WebHistoryItem *)_globalHistoryItem |
|
2126 { |
|
2127 if (!_private->page) |
|
2128 return nil; |
|
2129 return kit(_private->page->globalHistoryItem()); |
|
2130 } |
|
2131 |
|
2132 - (WebTextIterator *)textIteratorForRect:(NSRect)rect |
|
2133 { |
|
2134 IntPoint rectStart(rect.origin.x, rect.origin.y); |
|
2135 IntPoint rectEnd(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); |
|
2136 |
|
2137 Frame* coreFrame = [self _mainCoreFrame]; |
|
2138 if (!coreFrame) |
|
2139 return nil; |
|
2140 |
|
2141 VisibleSelection selectionInsideRect(coreFrame->visiblePositionForPoint(rectStart), coreFrame->visiblePositionForPoint(rectEnd)); |
|
2142 |
|
2143 return [[[WebTextIterator alloc] initWithRange:kit(selectionInsideRect.toNormalizedRange().get())] autorelease]; |
|
2144 } |
|
2145 |
|
2146 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource |
|
2147 { |
|
2148 NSWindow *window = [self hostWindow] ? [self hostWindow] : [self window]; |
|
2149 [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window]; |
|
2150 } |
|
2151 |
|
2152 - (void)_clearUndoRedoOperations |
|
2153 { |
|
2154 if (!_private->page) |
|
2155 return; |
|
2156 _private->page->clearUndoRedoOperations(); |
|
2157 } |
|
2158 |
|
2159 - (void)_setCatchesDelegateExceptions:(BOOL)f |
|
2160 { |
|
2161 _private->catchesDelegateExceptions = f; |
|
2162 } |
|
2163 |
|
2164 - (BOOL)_catchesDelegateExceptions |
|
2165 { |
|
2166 return _private->catchesDelegateExceptions; |
|
2167 } |
|
2168 |
|
2169 - (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value |
|
2170 { |
|
2171 Frame* coreFrame = [self _mainCoreFrame]; |
|
2172 if (!coreFrame) |
|
2173 return; |
|
2174 coreFrame->editor()->command(name).execute(value); |
|
2175 } |
|
2176 |
|
2177 - (void)_setCustomHTMLTokenizerTimeDelay:(double)timeDelay |
|
2178 { |
|
2179 if (!_private->page) |
|
2180 return; |
|
2181 return _private->page->setCustomHTMLTokenizerTimeDelay(timeDelay); |
|
2182 } |
|
2183 |
|
2184 - (void)_setCustomHTMLTokenizerChunkSize:(int)chunkSize |
|
2185 { |
|
2186 if (!_private->page) |
|
2187 return; |
|
2188 return _private->page->setCustomHTMLTokenizerChunkSize(chunkSize); |
|
2189 } |
|
2190 |
|
2191 - (void)_clearMainFrameName |
|
2192 { |
|
2193 _private->page->mainFrame()->tree()->clearName(); |
|
2194 } |
|
2195 |
|
2196 - (void)setSelectTrailingWhitespaceEnabled:(BOOL)flag |
|
2197 { |
|
2198 _private->selectTrailingWhitespaceEnabled = flag; |
|
2199 if (flag) |
|
2200 [self setSmartInsertDeleteEnabled:false]; |
|
2201 } |
|
2202 |
|
2203 - (BOOL)isSelectTrailingWhitespaceEnabled |
|
2204 { |
|
2205 return _private->selectTrailingWhitespaceEnabled; |
|
2206 } |
|
2207 |
|
2208 - (void)setMemoryCacheDelegateCallsEnabled:(BOOL)enabled |
|
2209 { |
|
2210 _private->page->setMemoryCacheClientCallsEnabled(enabled); |
|
2211 } |
|
2212 |
|
2213 - (BOOL)areMemoryCacheDelegateCallsEnabled |
|
2214 { |
|
2215 return _private->page->areMemoryCacheClientCallsEnabled(); |
|
2216 } |
|
2217 |
|
2218 - (void)_setJavaScriptURLsAreAllowed:(BOOL)areAllowed |
|
2219 { |
|
2220 _private->page->setJavaScriptURLsAreAllowed(areAllowed); |
|
2221 } |
|
2222 |
|
2223 + (NSCursor *)_pointingHandCursor |
|
2224 { |
|
2225 return handCursor().platformCursor(); |
|
2226 } |
|
2227 |
|
2228 - (BOOL)_postsAcceleratedCompositingNotifications |
|
2229 { |
|
2230 #if USE(ACCELERATED_COMPOSITING) |
|
2231 return _private->postsAcceleratedCompositingNotifications; |
|
2232 #else |
|
2233 return NO; |
|
2234 #endif |
|
2235 |
|
2236 } |
|
2237 - (void)_setPostsAcceleratedCompositingNotifications:(BOOL)flag |
|
2238 { |
|
2239 #if USE(ACCELERATED_COMPOSITING) |
|
2240 _private->postsAcceleratedCompositingNotifications = flag; |
|
2241 #endif |
|
2242 } |
|
2243 |
|
2244 - (BOOL)_isUsingAcceleratedCompositing |
|
2245 { |
|
2246 #if USE(ACCELERATED_COMPOSITING) |
|
2247 if (_private->usesDocumentViews) { |
|
2248 Frame* coreFrame = [self _mainCoreFrame]; |
|
2249 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) { |
|
2250 NSView *documentView = [[kit(frame) frameView] documentView]; |
|
2251 if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _isUsingAcceleratedCompositing]) |
|
2252 return YES; |
|
2253 } |
|
2254 } |
|
2255 #endif |
|
2256 return NO; |
|
2257 } |
|
2258 |
|
2259 - (BOOL)_isSoftwareRenderable |
|
2260 { |
|
2261 #if USE(ACCELERATED_COMPOSITING) |
|
2262 if (_private->usesDocumentViews) { |
|
2263 Frame* coreFrame = [self _mainCoreFrame]; |
|
2264 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) { |
|
2265 if (FrameView* view = frame->view()) { |
|
2266 if (!view->isSoftwareRenderable()) |
|
2267 return NO; |
|
2268 } |
|
2269 } |
|
2270 } |
|
2271 #endif |
|
2272 return YES; |
|
2273 } |
|
2274 |
|
2275 - (void)_setIncludesFlattenedCompositingLayersWhenDrawingToBitmap:(BOOL)flag |
|
2276 { |
|
2277 _private->includesFlattenedCompositingLayersWhenDrawingToBitmap = flag; |
|
2278 } |
|
2279 |
|
2280 - (BOOL)_includesFlattenedCompositingLayersWhenDrawingToBitmap |
|
2281 { |
|
2282 return _private->includesFlattenedCompositingLayersWhenDrawingToBitmap; |
|
2283 } |
|
2284 |
|
2285 static WebBaseNetscapePluginView *_pluginViewForNode(DOMNode *node) |
|
2286 { |
|
2287 if (!node) |
|
2288 return nil; |
|
2289 |
|
2290 Node* coreNode = core(node); |
|
2291 if (!coreNode) |
|
2292 return nil; |
|
2293 |
|
2294 RenderObject* renderer = coreNode->renderer(); |
|
2295 if (!renderer || !renderer->isWidget()) |
|
2296 return nil; |
|
2297 |
|
2298 Widget* widget = toRenderWidget(renderer)->widget(); |
|
2299 if (!widget || !widget->platformWidget()) |
|
2300 return nil; |
|
2301 |
|
2302 NSView *view = widget->platformWidget(); |
|
2303 if (![view isKindOfClass:[WebBaseNetscapePluginView class]]) |
|
2304 return nil; |
|
2305 |
|
2306 return (WebBaseNetscapePluginView *)view; |
|
2307 } |
|
2308 |
|
2309 + (BOOL)_isNodeHaltedPlugin:(DOMNode *)node |
|
2310 { |
|
2311 return [_pluginViewForNode(node) isHalted]; |
|
2312 } |
|
2313 |
|
2314 + (BOOL)_hasPluginForNodeBeenHalted:(DOMNode *)node |
|
2315 { |
|
2316 return [_pluginViewForNode(node) hasBeenHalted]; |
|
2317 } |
|
2318 + (void)_restartHaltedPluginForNode:(DOMNode *)node |
|
2319 { |
|
2320 if (!node) |
|
2321 return; |
|
2322 |
|
2323 [_pluginViewForNode(node) resumeFromHalt]; |
|
2324 } |
|
2325 |
|
2326 - (NSPasteboard *)_insertionPasteboard |
|
2327 { |
|
2328 return _private ? _private->insertionPasteboard : nil; |
|
2329 } |
|
2330 |
|
2331 + (void)_addOriginAccessWhitelistEntryWithSourceOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains |
|
2332 { |
|
2333 SecurityOrigin::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains); |
|
2334 } |
|
2335 |
|
2336 + (void)_removeOriginAccessWhitelistEntryWithSourceOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains |
|
2337 { |
|
2338 SecurityOrigin::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains); |
|
2339 } |
|
2340 |
|
2341 +(void)_resetOriginAccessWhitelists |
|
2342 { |
|
2343 SecurityOrigin::resetOriginAccessWhitelists(); |
|
2344 } |
|
2345 |
|
2346 - (void)_updateActiveState |
|
2347 { |
|
2348 if (_private && _private->page) |
|
2349 _private->page->focusController()->setActive([[self window] isKeyWindow]); |
|
2350 } |
|
2351 |
|
2352 static PassOwnPtr<Vector<String> > toStringVector(NSArray* patterns) |
|
2353 { |
|
2354 // Convert the patterns into Vectors. |
|
2355 NSUInteger count = [patterns count]; |
|
2356 if (count == 0) |
|
2357 return 0; |
|
2358 Vector<String>* patternsVector = new Vector<String>; |
|
2359 for (NSUInteger i = 0; i < count; ++i) { |
|
2360 id entry = [patterns objectAtIndex:i]; |
|
2361 if ([entry isKindOfClass:[NSString class]]) |
|
2362 patternsVector->append(String((NSString*)entry)); |
|
2363 } |
|
2364 return patternsVector; |
|
2365 } |
|
2366 |
|
2367 + (void)_addUserScriptToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url |
|
2368 whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist |
|
2369 injectionTime:(WebUserScriptInjectionTime)injectionTime |
|
2370 { |
|
2371 [WebView _addUserScriptToGroup:groupName world:world source:source url:url whitelist:whitelist blacklist:blacklist injectionTime:injectionTime injectedFrames:WebInjectInAllFrames]; |
|
2372 } |
|
2373 |
|
2374 + (void)_addUserScriptToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url |
|
2375 whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist |
|
2376 injectionTime:(WebUserScriptInjectionTime)injectionTime |
|
2377 injectedFrames:(WebUserContentInjectedFrames)injectedFrames |
|
2378 { |
|
2379 String group(groupName); |
|
2380 if (group.isEmpty()) |
|
2381 return; |
|
2382 |
|
2383 PageGroup* pageGroup = PageGroup::pageGroup(group); |
|
2384 if (!pageGroup) |
|
2385 return; |
|
2386 |
|
2387 pageGroup->addUserScriptToWorld(core(world), source, url, toStringVector(whitelist), toStringVector(blacklist), |
|
2388 injectionTime == WebInjectAtDocumentStart ? InjectAtDocumentStart : InjectAtDocumentEnd, |
|
2389 injectedFrames == WebInjectInAllFrames ? InjectInAllFrames : InjectInTopFrameOnly); |
|
2390 } |
|
2391 |
|
2392 + (void)_addUserStyleSheetToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url |
|
2393 whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist |
|
2394 { |
|
2395 [WebView _addUserStyleSheetToGroup:groupName world:world source:source url:url whitelist:whitelist blacklist:blacklist injectedFrames:WebInjectInAllFrames]; |
|
2396 } |
|
2397 |
|
2398 + (void)_addUserStyleSheetToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url |
|
2399 whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist |
|
2400 injectedFrames:(WebUserContentInjectedFrames)injectedFrames |
|
2401 { |
|
2402 String group(groupName); |
|
2403 if (group.isEmpty()) |
|
2404 return; |
|
2405 |
|
2406 PageGroup* pageGroup = PageGroup::pageGroup(group); |
|
2407 if (!pageGroup) |
|
2408 return; |
|
2409 |
|
2410 pageGroup->addUserStyleSheetToWorld(core(world), source, url, toStringVector(whitelist), toStringVector(blacklist), injectedFrames == WebInjectInAllFrames ? InjectInAllFrames : InjectInTopFrameOnly); |
|
2411 } |
|
2412 |
|
2413 + (void)_removeUserScriptFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url |
|
2414 { |
|
2415 String group(groupName); |
|
2416 if (group.isEmpty()) |
|
2417 return; |
|
2418 |
|
2419 PageGroup* pageGroup = PageGroup::pageGroup(group); |
|
2420 if (!pageGroup) |
|
2421 return; |
|
2422 |
|
2423 pageGroup->removeUserScriptFromWorld(core(world), url); |
|
2424 } |
|
2425 |
|
2426 + (void)_removeUserStyleSheetFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url |
|
2427 { |
|
2428 String group(groupName); |
|
2429 if (group.isEmpty()) |
|
2430 return; |
|
2431 |
|
2432 PageGroup* pageGroup = PageGroup::pageGroup(group); |
|
2433 if (!pageGroup) |
|
2434 return; |
|
2435 |
|
2436 pageGroup->removeUserStyleSheetFromWorld(core(world), url); |
|
2437 } |
|
2438 |
|
2439 + (void)_removeUserScriptsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world |
|
2440 { |
|
2441 String group(groupName); |
|
2442 if (group.isEmpty()) |
|
2443 return; |
|
2444 |
|
2445 PageGroup* pageGroup = PageGroup::pageGroup(group); |
|
2446 if (!pageGroup) |
|
2447 return; |
|
2448 |
|
2449 pageGroup->removeUserScriptsFromWorld(core(world)); |
|
2450 } |
|
2451 |
|
2452 + (void)_removeUserStyleSheetsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world |
|
2453 { |
|
2454 String group(groupName); |
|
2455 if (group.isEmpty()) |
|
2456 return; |
|
2457 |
|
2458 PageGroup* pageGroup = PageGroup::pageGroup(group); |
|
2459 if (!pageGroup) |
|
2460 return; |
|
2461 |
|
2462 pageGroup->removeUserStyleSheetsFromWorld(core(world)); |
|
2463 } |
|
2464 |
|
2465 + (void)_removeAllUserContentFromGroup:(NSString *)groupName |
|
2466 { |
|
2467 String group(groupName); |
|
2468 if (group.isEmpty()) |
|
2469 return; |
|
2470 |
|
2471 PageGroup* pageGroup = PageGroup::pageGroup(group); |
|
2472 if (!pageGroup) |
|
2473 return; |
|
2474 |
|
2475 pageGroup->removeAllUserContent(); |
|
2476 } |
|
2477 |
|
2478 - (BOOL)cssAnimationsSuspended |
|
2479 { |
|
2480 return _private->cssAnimationsSuspended; |
|
2481 } |
|
2482 |
|
2483 - (void)setCSSAnimationsSuspended:(BOOL)suspended |
|
2484 { |
|
2485 if (suspended == _private->cssAnimationsSuspended) |
|
2486 return; |
|
2487 |
|
2488 _private->cssAnimationsSuspended = suspended; |
|
2489 |
|
2490 Frame* frame = core([self mainFrame]); |
|
2491 if (suspended) |
|
2492 frame->animation()->suspendAnimations(frame->document()); |
|
2493 else |
|
2494 frame->animation()->resumeAnimations(frame->document()); |
|
2495 } |
|
2496 |
|
2497 + (void)_setDomainRelaxationForbidden:(BOOL)forbidden forURLScheme:(NSString *)scheme |
|
2498 { |
|
2499 SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme); |
|
2500 } |
|
2501 |
|
2502 + (void)_registerURLSchemeAsSecure:(NSString *)scheme |
|
2503 { |
|
2504 SchemeRegistry::registerURLSchemeAsSecure(scheme); |
|
2505 } |
|
2506 |
|
2507 @end |
|
2508 |
|
2509 @implementation _WebSafeForwarder |
|
2510 |
|
2511 // Used to send messages to delegates that implement informal protocols. |
|
2512 |
|
2513 - (id)initWithTarget:(id)t defaultTarget:(id)dt catchExceptions:(BOOL)c |
|
2514 { |
|
2515 self = [super init]; |
|
2516 if (!self) |
|
2517 return nil; |
|
2518 target = t; // Non retained. |
|
2519 defaultTarget = dt; |
|
2520 catchExceptions = c; |
|
2521 return self; |
|
2522 } |
|
2523 |
|
2524 - (void)forwardInvocation:(NSInvocation *)invocation |
|
2525 { |
|
2526 if ([target respondsToSelector:[invocation selector]]) { |
|
2527 if (catchExceptions) { |
|
2528 @try { |
|
2529 [invocation invokeWithTarget:target]; |
|
2530 } @catch(id exception) { |
|
2531 ReportDiscardedDelegateException([invocation selector], exception); |
|
2532 } |
|
2533 } else |
|
2534 [invocation invokeWithTarget:target]; |
|
2535 return; |
|
2536 } |
|
2537 |
|
2538 if ([defaultTarget respondsToSelector:[invocation selector]]) |
|
2539 [invocation invokeWithTarget:defaultTarget]; |
|
2540 |
|
2541 // Do nothing quietly if method not implemented. |
|
2542 } |
|
2543 |
|
2544 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector |
|
2545 { |
|
2546 return [defaultTarget methodSignatureForSelector:aSelector]; |
|
2547 } |
|
2548 |
|
2549 @end |
|
2550 |
|
2551 @implementation WebView |
|
2552 |
|
2553 + (void)initialize |
|
2554 { |
|
2555 static BOOL initialized = NO; |
|
2556 if (initialized) |
|
2557 return; |
|
2558 initialized = YES; |
|
2559 |
|
2560 InitWebCoreSystemInterface(); |
|
2561 JSC::initializeThreading(); |
|
2562 WTF::initializeMainThreadToProcessMainThread(); |
|
2563 |
|
2564 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp]; |
|
2565 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil]; |
|
2566 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil]; |
|
2567 |
|
2568 continuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled]; |
|
2569 #ifndef BUILDING_ON_TIGER |
|
2570 grammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled]; |
|
2571 #endif |
|
2572 |
|
2573 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) |
|
2574 automaticQuoteSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticQuoteSubstitutionEnabled]; |
|
2575 automaticLinkDetectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticLinkDetectionEnabled]; |
|
2576 automaticDashSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticDashSubstitutionEnabled]; |
|
2577 automaticTextReplacementEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticTextReplacementEnabled]; |
|
2578 automaticSpellingCorrectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticSpellingCorrectionEnabled]; |
|
2579 #endif |
|
2580 } |
|
2581 |
|
2582 + (void)_applicationWillTerminate |
|
2583 { |
|
2584 applicationIsTerminating = YES; |
|
2585 |
|
2586 if (fastDocumentTeardownEnabled()) |
|
2587 [self closeAllWebViews]; |
|
2588 |
|
2589 if (!pluginDatabaseClientCount) |
|
2590 [WebPluginDatabase closeSharedDatabase]; |
|
2591 |
|
2592 PageGroup::closeLocalStorage(); |
|
2593 } |
|
2594 |
|
2595 + (BOOL)_canShowMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins |
|
2596 { |
|
2597 return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType allowingPlugins:allowPlugins]; |
|
2598 } |
|
2599 |
|
2600 + (BOOL)canShowMIMEType:(NSString *)MIMEType |
|
2601 { |
|
2602 return [self _canShowMIMEType:MIMEType allowingPlugins:YES]; |
|
2603 } |
|
2604 |
|
2605 - (BOOL)_canShowMIMEType:(NSString *)MIMEType |
|
2606 { |
|
2607 return [[self class] _canShowMIMEType:MIMEType allowingPlugins:[_private->preferences arePlugInsEnabled]]; |
|
2608 } |
|
2609 |
|
2610 - (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType |
|
2611 { |
|
2612 if (![_private->preferences arePlugInsEnabled]) |
|
2613 return nil; |
|
2614 |
|
2615 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType]; |
|
2616 if (pluginPackage) |
|
2617 return pluginPackage; |
|
2618 |
|
2619 if (_private->pluginDatabase) |
|
2620 return [_private->pluginDatabase pluginForMIMEType:MIMEType]; |
|
2621 |
|
2622 return nil; |
|
2623 } |
|
2624 |
|
2625 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) |
|
2626 - (WebBasePluginPackage *)_videoProxyPluginForMIMEType:(NSString *)MIMEType |
|
2627 { |
|
2628 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType]; |
|
2629 if (pluginPackage) |
|
2630 return pluginPackage; |
|
2631 |
|
2632 if (_private->pluginDatabase) |
|
2633 return [_private->pluginDatabase pluginForMIMEType:MIMEType]; |
|
2634 |
|
2635 return nil; |
|
2636 } |
|
2637 #endif |
|
2638 |
|
2639 - (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension |
|
2640 { |
|
2641 if (![_private->preferences arePlugInsEnabled]) |
|
2642 return nil; |
|
2643 |
|
2644 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForExtension:extension]; |
|
2645 if (pluginPackage) |
|
2646 return pluginPackage; |
|
2647 |
|
2648 if (_private->pluginDatabase) |
|
2649 return [_private->pluginDatabase pluginForExtension:extension]; |
|
2650 |
|
2651 return nil; |
|
2652 } |
|
2653 |
|
2654 - (void)addPluginInstanceView:(NSView *)view |
|
2655 { |
|
2656 if (!_private->pluginDatabase) |
|
2657 _private->pluginDatabase = [[WebPluginDatabase alloc] init]; |
|
2658 [_private->pluginDatabase addPluginInstanceView:view]; |
|
2659 } |
|
2660 |
|
2661 - (void)removePluginInstanceView:(NSView *)view |
|
2662 { |
|
2663 if (_private->pluginDatabase) |
|
2664 [_private->pluginDatabase removePluginInstanceView:view]; |
|
2665 } |
|
2666 |
|
2667 - (void)removePluginInstanceViewsFor:(WebFrame*)webFrame |
|
2668 { |
|
2669 if (_private->pluginDatabase) |
|
2670 [_private->pluginDatabase removePluginInstanceViewsFor:webFrame]; |
|
2671 } |
|
2672 |
|
2673 - (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType |
|
2674 { |
|
2675 if (![_private->preferences arePlugInsEnabled]) |
|
2676 return NO; |
|
2677 |
|
2678 if ([[WebPluginDatabase sharedDatabase] isMIMETypeRegistered:MIMEType]) |
|
2679 return YES; |
|
2680 |
|
2681 if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType]) |
|
2682 return YES; |
|
2683 |
|
2684 return NO; |
|
2685 } |
|
2686 |
|
2687 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType |
|
2688 { |
|
2689 return [WebFrameView _canShowMIMETypeAsHTML:MIMEType]; |
|
2690 } |
|
2691 |
|
2692 + (NSArray *)MIMETypesShownAsHTML |
|
2693 { |
|
2694 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES]; |
|
2695 NSEnumerator *enumerator = [viewTypes keyEnumerator]; |
|
2696 id key; |
|
2697 NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease]; |
|
2698 |
|
2699 while ((key = [enumerator nextObject])) { |
|
2700 if ([viewTypes objectForKey:key] == [WebHTMLView class]) |
|
2701 [array addObject:key]; |
|
2702 } |
|
2703 |
|
2704 return array; |
|
2705 } |
|
2706 |
|
2707 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes |
|
2708 { |
|
2709 NSDictionary *viewTypes = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] copy]; |
|
2710 NSEnumerator *enumerator = [viewTypes keyEnumerator]; |
|
2711 id key; |
|
2712 while ((key = [enumerator nextObject])) { |
|
2713 if ([viewTypes objectForKey:key] == [WebHTMLView class]) |
|
2714 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key]; |
|
2715 } |
|
2716 |
|
2717 int i, count = [MIMETypes count]; |
|
2718 for (i = 0; i < count; i++) { |
|
2719 [WebView registerViewClass:[WebHTMLView class] |
|
2720 representationClass:[WebHTMLRepresentation class] |
|
2721 forMIMEType:[MIMETypes objectAtIndex:i]]; |
|
2722 } |
|
2723 [viewTypes release]; |
|
2724 } |
|
2725 |
|
2726 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard |
|
2727 { |
|
2728 return [pasteboard _web_bestURL]; |
|
2729 } |
|
2730 |
|
2731 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard |
|
2732 { |
|
2733 return [pasteboard stringForType:WebURLNamePboardType]; |
|
2734 } |
|
2735 |
|
2736 + (void)registerURLSchemeAsLocal:(NSString *)protocol |
|
2737 { |
|
2738 SchemeRegistry::registerURLSchemeAsLocal(protocol); |
|
2739 } |
|
2740 |
|
2741 - (id)_initWithArguments:(NSDictionary *) arguments |
|
2742 { |
|
2743 NSCoder *decoder = [arguments objectForKey:@"decoder"]; |
|
2744 if (decoder) { |
|
2745 self = [self initWithCoder:decoder]; |
|
2746 } else { |
|
2747 ASSERT([arguments objectForKey:@"frame"]); |
|
2748 NSValue *frameValue = [arguments objectForKey:@"frame"]; |
|
2749 NSRect frame = (frameValue ? [frameValue rectValue] : NSZeroRect); |
|
2750 NSString *frameName = [arguments objectForKey:@"frameName"]; |
|
2751 NSString *groupName = [arguments objectForKey:@"groupName"]; |
|
2752 self = [self initWithFrame:frame frameName:frameName groupName:groupName]; |
|
2753 } |
|
2754 |
|
2755 return self; |
|
2756 } |
|
2757 |
|
2758 static bool clientNeedsWebViewInitThreadWorkaround() |
|
2759 { |
|
2760 if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_WEBVIEW_INIT_THREAD_WORKAROUND)) |
|
2761 return false; |
|
2762 |
|
2763 NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; |
|
2764 |
|
2765 // Installer. |
|
2766 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.installer"]) |
|
2767 return true; |
|
2768 |
|
2769 // Automator. |
|
2770 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Automator"]) |
|
2771 return true; |
|
2772 |
|
2773 // Automator Runner. |
|
2774 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.AutomatorRunner"]) |
|
2775 return true; |
|
2776 |
|
2777 // Automator workflows. |
|
2778 if ([bundleIdentifier _webkit_hasCaseInsensitivePrefix:@"com.apple.Automator."]) |
|
2779 return true; |
|
2780 |
|
2781 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) |
|
2782 // Mail. |
|
2783 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Mail"]) |
|
2784 return true; |
|
2785 #endif |
|
2786 |
|
2787 return false; |
|
2788 } |
|
2789 |
|
2790 static bool needsWebViewInitThreadWorkaround() |
|
2791 { |
|
2792 static bool isOldClient = clientNeedsWebViewInitThreadWorkaround(); |
|
2793 return isOldClient && !pthread_main_np(); |
|
2794 } |
|
2795 |
|
2796 - (id)initWithFrame:(NSRect)f |
|
2797 { |
|
2798 return [self initWithFrame:f frameName:nil groupName:nil]; |
|
2799 } |
|
2800 |
|
2801 - (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName |
|
2802 { |
|
2803 if (needsWebViewInitThreadWorkaround()) |
|
2804 return [[self _webkit_invokeOnMainThread] initWithFrame:f frameName:frameName groupName:groupName]; |
|
2805 |
|
2806 WebCoreThreadViolationCheckRoundTwo(); |
|
2807 return [self _initWithFrame:f frameName:frameName groupName:groupName usesDocumentViews:YES]; |
|
2808 } |
|
2809 |
|
2810 - (id)initWithCoder:(NSCoder *)decoder |
|
2811 { |
|
2812 if (needsWebViewInitThreadWorkaround()) |
|
2813 return [[self _webkit_invokeOnMainThread] initWithCoder:decoder]; |
|
2814 |
|
2815 WebCoreThreadViolationCheckRoundTwo(); |
|
2816 WebView *result = nil; |
|
2817 |
|
2818 @try { |
|
2819 NSString *frameName; |
|
2820 NSString *groupName; |
|
2821 WebPreferences *preferences; |
|
2822 BOOL useBackForwardList = NO; |
|
2823 BOOL allowsUndo = YES; |
|
2824 |
|
2825 result = [super initWithCoder:decoder]; |
|
2826 result->_private = [[WebViewPrivate alloc] init]; |
|
2827 |
|
2828 // We don't want any of the archived subviews. The subviews will always |
|
2829 // be created in _commonInitializationFrameName:groupName:. |
|
2830 [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; |
|
2831 |
|
2832 if ([decoder allowsKeyedCoding]) { |
|
2833 frameName = [decoder decodeObjectForKey:@"FrameName"]; |
|
2834 groupName = [decoder decodeObjectForKey:@"GroupName"]; |
|
2835 preferences = [decoder decodeObjectForKey:@"Preferences"]; |
|
2836 useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"]; |
|
2837 if ([decoder containsValueForKey:@"AllowsUndo"]) |
|
2838 allowsUndo = [decoder decodeBoolForKey:@"AllowsUndo"]; |
|
2839 } else { |
|
2840 int version; |
|
2841 [decoder decodeValueOfObjCType:@encode(int) at:&version]; |
|
2842 frameName = [decoder decodeObject]; |
|
2843 groupName = [decoder decodeObject]; |
|
2844 preferences = [decoder decodeObject]; |
|
2845 if (version > 1) |
|
2846 [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList]; |
|
2847 // The allowsUndo field is no longer written out in encodeWithCoder, but since there are |
|
2848 // version 3 NIBs that have this field encoded, we still need to read it in. |
|
2849 if (version == 3) |
|
2850 [decoder decodeValuesOfObjCTypes:"c", &allowsUndo]; |
|
2851 } |
|
2852 |
|
2853 if (![frameName isKindOfClass:[NSString class]]) |
|
2854 frameName = nil; |
|
2855 if (![groupName isKindOfClass:[NSString class]]) |
|
2856 groupName = nil; |
|
2857 if (![preferences isKindOfClass:[WebPreferences class]]) |
|
2858 preferences = nil; |
|
2859 |
|
2860 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList); |
|
2861 [result _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:YES]; |
|
2862 [result page]->backForwardList()->setEnabled(useBackForwardList); |
|
2863 result->_private->allowsUndo = allowsUndo; |
|
2864 if (preferences) |
|
2865 [result setPreferences:preferences]; |
|
2866 } @catch (NSException *localException) { |
|
2867 result = nil; |
|
2868 [self release]; |
|
2869 } |
|
2870 |
|
2871 return result; |
|
2872 } |
|
2873 |
|
2874 - (void)encodeWithCoder:(NSCoder *)encoder |
|
2875 { |
|
2876 // Set asside the subviews before we archive. We don't want to archive any subviews. |
|
2877 // The subviews will always be created in _commonInitializationFrameName:groupName:. |
|
2878 id originalSubviews = _subviews; |
|
2879 _subviews = nil; |
|
2880 |
|
2881 [super encodeWithCoder:encoder]; |
|
2882 |
|
2883 // Restore the subviews we set aside. |
|
2884 _subviews = originalSubviews; |
|
2885 |
|
2886 BOOL useBackForwardList = _private->page && _private->page->backForwardList()->enabled(); |
|
2887 if ([encoder allowsKeyedCoding]) { |
|
2888 [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"]; |
|
2889 [encoder encodeObject:[self groupName] forKey:@"GroupName"]; |
|
2890 [encoder encodeObject:[self preferences] forKey:@"Preferences"]; |
|
2891 [encoder encodeBool:useBackForwardList forKey:@"UseBackForwardList"]; |
|
2892 [encoder encodeBool:_private->allowsUndo forKey:@"AllowsUndo"]; |
|
2893 } else { |
|
2894 int version = WebViewVersion; |
|
2895 [encoder encodeValueOfObjCType:@encode(int) at:&version]; |
|
2896 [encoder encodeObject:[[self mainFrame] name]]; |
|
2897 [encoder encodeObject:[self groupName]]; |
|
2898 [encoder encodeObject:[self preferences]]; |
|
2899 [encoder encodeValuesOfObjCTypes:"c", &useBackForwardList]; |
|
2900 // DO NOT encode any new fields here, doing so will break older WebKit releases. |
|
2901 } |
|
2902 |
|
2903 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)useBackForwardList); |
|
2904 } |
|
2905 |
|
2906 - (void)dealloc |
|
2907 { |
|
2908 if (WebCoreObjCScheduleDeallocateOnMainThread([WebView class], self)) |
|
2909 return; |
|
2910 |
|
2911 // call close to ensure we tear-down completely |
|
2912 // this maintains our old behavior for existing applications |
|
2913 [self close]; |
|
2914 |
|
2915 if ([[self class] shouldIncludeInWebKitStatistics]) |
|
2916 --WebViewCount; |
|
2917 |
|
2918 if ([self _needsFrameLoadDelegateRetainQuirk]) |
|
2919 [_private->frameLoadDelegate release]; |
|
2920 |
|
2921 [_private release]; |
|
2922 // [super dealloc] can end up dispatching against _private (3466082) |
|
2923 _private = nil; |
|
2924 |
|
2925 [super dealloc]; |
|
2926 } |
|
2927 |
|
2928 - (void)finalize |
|
2929 { |
|
2930 ASSERT(_private->closed); |
|
2931 |
|
2932 --WebViewCount; |
|
2933 |
|
2934 [super finalize]; |
|
2935 } |
|
2936 |
|
2937 - (void)close |
|
2938 { |
|
2939 // _close existed first, and some clients might be calling or overriding it, so call through. |
|
2940 [self _close]; |
|
2941 } |
|
2942 |
|
2943 - (void)setShouldCloseWithWindow:(BOOL)close |
|
2944 { |
|
2945 _private->shouldCloseWithWindow = close; |
|
2946 } |
|
2947 |
|
2948 - (BOOL)shouldCloseWithWindow |
|
2949 { |
|
2950 return _private->shouldCloseWithWindow; |
|
2951 } |
|
2952 |
|
2953 - (void)addWindowObserversForWindow:(NSWindow *)window |
|
2954 { |
|
2955 if (window) { |
|
2956 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:) |
|
2957 name:NSWindowDidBecomeKeyNotification object:nil]; |
|
2958 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:) |
|
2959 name:NSWindowDidResignKeyNotification object:nil]; |
|
2960 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillOrderOnScreen:) |
|
2961 name:WKWindowWillOrderOnScreenNotification() object:window]; |
|
2962 } |
|
2963 } |
|
2964 |
|
2965 - (void)removeWindowObservers |
|
2966 { |
|
2967 NSWindow *window = [self window]; |
|
2968 if (window) { |
|
2969 [[NSNotificationCenter defaultCenter] removeObserver:self |
|
2970 name:NSWindowDidBecomeKeyNotification object:nil]; |
|
2971 [[NSNotificationCenter defaultCenter] removeObserver:self |
|
2972 name:NSWindowDidResignKeyNotification object:nil]; |
|
2973 [[NSNotificationCenter defaultCenter] removeObserver:self |
|
2974 name:WKWindowWillOrderOnScreenNotification() object:window]; |
|
2975 } |
|
2976 } |
|
2977 |
|
2978 - (void)viewWillMoveToWindow:(NSWindow *)window |
|
2979 { |
|
2980 // Don't do anything if the WebView isn't initialized. |
|
2981 // This happens when decoding a WebView in a nib. |
|
2982 // FIXME: What sets up the observer of NSWindowWillCloseNotification in this case? |
|
2983 if (!_private || _private->closed) |
|
2984 return; |
|
2985 |
|
2986 if ([self window] && [self window] != [self hostWindow]) |
|
2987 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]]; |
|
2988 |
|
2989 if (window) { |
|
2990 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window]; |
|
2991 |
|
2992 // Ensure that we will receive the events that WebHTMLView (at least) needs. |
|
2993 // The following are expensive enough that we don't want to call them over |
|
2994 // and over, so do them when we move into a window. |
|
2995 [window setAcceptsMouseMovedEvents:YES]; |
|
2996 WKSetNSWindowShouldPostEventNotifications(window, YES); |
|
2997 } else { |
|
2998 _private->page->setCanStartMedia(false); |
|
2999 _private->page->willMoveOffscreen(); |
|
3000 } |
|
3001 |
|
3002 if (window != [self window]) { |
|
3003 [self removeWindowObservers]; |
|
3004 [self addWindowObserversForWindow:window]; |
|
3005 } |
|
3006 } |
|
3007 |
|
3008 - (void)viewDidMoveToWindow |
|
3009 { |
|
3010 // Don't do anything if we aren't initialized. This happens |
|
3011 // when decoding a WebView. When WebViews are decoded their subviews |
|
3012 // are created by initWithCoder: and so won't be normally |
|
3013 // initialized. The stub views are discarded by WebView. |
|
3014 if (!_private || _private->closed) |
|
3015 return; |
|
3016 |
|
3017 if ([self window]) { |
|
3018 _private->page->setCanStartMedia(true); |
|
3019 _private->page->didMoveOnscreen(); |
|
3020 } |
|
3021 |
|
3022 [self _updateActiveState]; |
|
3023 } |
|
3024 |
|
3025 - (void)_windowDidBecomeKey:(NSNotification *)notification |
|
3026 { |
|
3027 NSWindow *keyWindow = [notification object]; |
|
3028 if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) |
|
3029 [self _updateActiveState]; |
|
3030 } |
|
3031 |
|
3032 - (void)_windowDidResignKey:(NSNotification *)notification |
|
3033 { |
|
3034 NSWindow *formerKeyWindow = [notification object]; |
|
3035 if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) |
|
3036 [self _updateActiveState]; |
|
3037 } |
|
3038 |
|
3039 - (void)_windowWillOrderOnScreen:(NSNotification *)notification |
|
3040 { |
|
3041 if (![self shouldUpdateWhileOffscreen]) |
|
3042 [self setNeedsDisplay:YES]; |
|
3043 } |
|
3044 |
|
3045 - (void)_windowWillClose:(NSNotification *)notification |
|
3046 { |
|
3047 if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow]))) |
|
3048 [self close]; |
|
3049 } |
|
3050 |
|
3051 - (void)setPreferences:(WebPreferences *)prefs |
|
3052 { |
|
3053 if (!prefs) |
|
3054 prefs = [WebPreferences standardPreferences]; |
|
3055 |
|
3056 if (_private->preferences == prefs) |
|
3057 return; |
|
3058 |
|
3059 [prefs willAddToWebView]; |
|
3060 |
|
3061 WebPreferences *oldPrefs = _private->preferences; |
|
3062 |
|
3063 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]]; |
|
3064 [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]]; |
|
3065 |
|
3066 _private->preferences = [prefs retain]; |
|
3067 |
|
3068 // After registering for the notification, post it so the WebCore settings update. |
|
3069 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) |
|
3070 name:WebPreferencesChangedNotification object:[self preferences]]; |
|
3071 [[self preferences] _postPreferencesChangesNotification]; |
|
3072 |
|
3073 [oldPrefs didRemoveFromWebView]; |
|
3074 [oldPrefs release]; |
|
3075 } |
|
3076 |
|
3077 - (WebPreferences *)preferences |
|
3078 { |
|
3079 return _private->preferences; |
|
3080 } |
|
3081 |
|
3082 - (void)setPreferencesIdentifier:(NSString *)anIdentifier |
|
3083 { |
|
3084 if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) { |
|
3085 WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier]; |
|
3086 [self setPreferences:prefs]; |
|
3087 [prefs release]; |
|
3088 } |
|
3089 } |
|
3090 |
|
3091 - (NSString *)preferencesIdentifier |
|
3092 { |
|
3093 return [[self preferences] identifier]; |
|
3094 } |
|
3095 |
|
3096 |
|
3097 - (void)setUIDelegate:delegate |
|
3098 { |
|
3099 _private->UIDelegate = delegate; |
|
3100 [_private->UIDelegateForwarder release]; |
|
3101 _private->UIDelegateForwarder = nil; |
|
3102 } |
|
3103 |
|
3104 - (id)UIDelegate |
|
3105 { |
|
3106 return _private->UIDelegate; |
|
3107 } |
|
3108 |
|
3109 - (void)setResourceLoadDelegate: delegate |
|
3110 { |
|
3111 _private->resourceProgressDelegate = delegate; |
|
3112 [self _cacheResourceLoadDelegateImplementations]; |
|
3113 } |
|
3114 |
|
3115 - (id)resourceLoadDelegate |
|
3116 { |
|
3117 return _private->resourceProgressDelegate; |
|
3118 } |
|
3119 |
|
3120 - (void)setDownloadDelegate: delegate |
|
3121 { |
|
3122 _private->downloadDelegate = delegate; |
|
3123 } |
|
3124 |
|
3125 |
|
3126 - (id)downloadDelegate |
|
3127 { |
|
3128 return _private->downloadDelegate; |
|
3129 } |
|
3130 |
|
3131 - (void)setPolicyDelegate:delegate |
|
3132 { |
|
3133 _private->policyDelegate = delegate; |
|
3134 [_private->policyDelegateForwarder release]; |
|
3135 _private->policyDelegateForwarder = nil; |
|
3136 } |
|
3137 |
|
3138 - (id)policyDelegate |
|
3139 { |
|
3140 return _private->policyDelegate; |
|
3141 } |
|
3142 |
|
3143 - (void)setFrameLoadDelegate:delegate |
|
3144 { |
|
3145 // <rdar://problem/6950660> - Due to some subtle WebKit changes - presumably to delegate callback behavior - we've |
|
3146 // unconvered a latent bug in at least one WebKit app where the delegate wasn't properly retained by the app and |
|
3147 // was dealloc'ed before being cleared. |
|
3148 // This is an effort to keep such apps working for now. |
|
3149 if ([self _needsFrameLoadDelegateRetainQuirk]) { |
|
3150 [delegate retain]; |
|
3151 [_private->frameLoadDelegate release]; |
|
3152 } |
|
3153 |
|
3154 _private->frameLoadDelegate = delegate; |
|
3155 [self _cacheFrameLoadDelegateImplementations]; |
|
3156 |
|
3157 #if ENABLE(ICONDATABASE) |
|
3158 // If this delegate wants callbacks for icons, fire up the icon database. |
|
3159 if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc) |
|
3160 [WebIconDatabase sharedIconDatabase]; |
|
3161 #endif |
|
3162 } |
|
3163 |
|
3164 - (id)frameLoadDelegate |
|
3165 { |
|
3166 return _private->frameLoadDelegate; |
|
3167 } |
|
3168 |
|
3169 - (WebFrame *)mainFrame |
|
3170 { |
|
3171 // This can be called in initialization, before _private has been set up (3465613) |
|
3172 if (!_private || !_private->page) |
|
3173 return nil; |
|
3174 return kit(_private->page->mainFrame()); |
|
3175 } |
|
3176 |
|
3177 - (WebFrame *)selectedFrame |
|
3178 { |
|
3179 if (_private->usesDocumentViews) { |
|
3180 // If the first responder is a view in our tree, we get the frame containing the first responder. |
|
3181 // This is faster than searching the frame hierarchy, and will give us a result even in the case |
|
3182 // where the focused frame doesn't actually contain a selection. |
|
3183 WebFrame *focusedFrame = [self _focusedFrame]; |
|
3184 if (focusedFrame) |
|
3185 return focusedFrame; |
|
3186 } |
|
3187 |
|
3188 // If the first responder is outside of our view tree, we search for a frame containing a selection. |
|
3189 // There should be at most only one of these. |
|
3190 return [[self mainFrame] _findFrameWithSelection]; |
|
3191 } |
|
3192 |
|
3193 - (WebBackForwardList *)backForwardList |
|
3194 { |
|
3195 if (!_private->page) |
|
3196 return nil; |
|
3197 if (!_private->page->backForwardList()->enabled()) |
|
3198 return nil; |
|
3199 return kit(_private->page->backForwardList()); |
|
3200 } |
|
3201 |
|
3202 - (void)setMaintainsBackForwardList:(BOOL)flag |
|
3203 { |
|
3204 if (!_private->page) |
|
3205 return; |
|
3206 _private->page->backForwardList()->setEnabled(flag); |
|
3207 } |
|
3208 |
|
3209 - (BOOL)goBack |
|
3210 { |
|
3211 if (!_private->page) |
|
3212 return NO; |
|
3213 |
|
3214 return _private->page->goBack(); |
|
3215 } |
|
3216 |
|
3217 - (BOOL)goForward |
|
3218 { |
|
3219 if (!_private->page) |
|
3220 return NO; |
|
3221 |
|
3222 return _private->page->goForward(); |
|
3223 } |
|
3224 |
|
3225 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item |
|
3226 { |
|
3227 if (!_private->page) |
|
3228 return NO; |
|
3229 |
|
3230 _private->page->goToItem(core(item), FrameLoadTypeIndexedBackForward); |
|
3231 return YES; |
|
3232 } |
|
3233 |
|
3234 - (void)setTextSizeMultiplier:(float)m |
|
3235 { |
|
3236 [self _setZoomMultiplier:m isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; |
|
3237 } |
|
3238 |
|
3239 - (float)textSizeMultiplier |
|
3240 { |
|
3241 return [self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f; |
|
3242 } |
|
3243 |
|
3244 - (void)_setZoomMultiplier:(float)multiplier isTextOnly:(BOOL)isTextOnly |
|
3245 { |
|
3246 // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>) |
|
3247 _private->zoomMultiplier = multiplier; |
|
3248 |
|
3249 ASSERT(_private->page); |
|
3250 if (_private->page) |
|
3251 _private->page->settings()->setZoomMode(isTextOnly ? ZoomTextOnly : ZoomPage); |
|
3252 |
|
3253 // FIXME: It would be nice to rework this code so that _private->zoomMultiplier doesn't exist |
|
3254 // and instead FrameView::zoomFactor is used. |
|
3255 Frame* coreFrame = [self _mainCoreFrame]; |
|
3256 if (coreFrame) { |
|
3257 if (FrameView* view = coreFrame->view()) |
|
3258 view->setZoomFactor(multiplier, isTextOnly ? ZoomTextOnly : ZoomPage); |
|
3259 } |
|
3260 } |
|
3261 |
|
3262 - (float)_zoomMultiplier:(BOOL)isTextOnly |
|
3263 { |
|
3264 if (isTextOnly != [self _realZoomMultiplierIsTextOnly]) |
|
3265 return 1.0f; |
|
3266 return _private->zoomMultiplier; |
|
3267 } |
|
3268 |
|
3269 - (float)_realZoomMultiplier |
|
3270 { |
|
3271 return _private->zoomMultiplier; |
|
3272 } |
|
3273 |
|
3274 - (BOOL)_realZoomMultiplierIsTextOnly |
|
3275 { |
|
3276 if (!_private->page) |
|
3277 return NO; |
|
3278 |
|
3279 return _private->page->settings()->zoomMode() == ZoomTextOnly; |
|
3280 } |
|
3281 |
|
3282 #define MinimumZoomMultiplier 0.5f |
|
3283 #define MaximumZoomMultiplier 3.0f |
|
3284 #define ZoomMultiplierRatio 1.2f |
|
3285 |
|
3286 - (BOOL)_canZoomOut:(BOOL)isTextOnly |
|
3287 { |
|
3288 id docView = [[[self mainFrame] frameView] documentView]; |
|
3289 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { |
|
3290 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; |
|
3291 return [zoomingDocView _canZoomOut]; |
|
3292 } |
|
3293 return [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio > MinimumZoomMultiplier; |
|
3294 } |
|
3295 |
|
3296 |
|
3297 - (BOOL)_canZoomIn:(BOOL)isTextOnly |
|
3298 { |
|
3299 id docView = [[[self mainFrame] frameView] documentView]; |
|
3300 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { |
|
3301 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; |
|
3302 return [zoomingDocView _canZoomIn]; |
|
3303 } |
|
3304 return [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio < MaximumZoomMultiplier; |
|
3305 } |
|
3306 |
|
3307 - (IBAction)_zoomOut:(id)sender isTextOnly:(BOOL)isTextOnly |
|
3308 { |
|
3309 id docView = [[[self mainFrame] frameView] documentView]; |
|
3310 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { |
|
3311 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; |
|
3312 return [zoomingDocView _zoomOut:sender]; |
|
3313 } |
|
3314 float newScale = [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio; |
|
3315 if (newScale > MinimumZoomMultiplier) |
|
3316 [self _setZoomMultiplier:newScale isTextOnly:isTextOnly]; |
|
3317 } |
|
3318 |
|
3319 - (IBAction)_zoomIn:(id)sender isTextOnly:(BOOL)isTextOnly |
|
3320 { |
|
3321 id docView = [[[self mainFrame] frameView] documentView]; |
|
3322 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { |
|
3323 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; |
|
3324 return [zoomingDocView _zoomIn:sender]; |
|
3325 } |
|
3326 float newScale = [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio; |
|
3327 if (newScale < MaximumZoomMultiplier) |
|
3328 [self _setZoomMultiplier:newScale isTextOnly:isTextOnly]; |
|
3329 } |
|
3330 |
|
3331 - (BOOL)_canResetZoom:(BOOL)isTextOnly |
|
3332 { |
|
3333 id docView = [[[self mainFrame] frameView] documentView]; |
|
3334 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { |
|
3335 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; |
|
3336 return [zoomingDocView _canResetZoom]; |
|
3337 } |
|
3338 return [self _zoomMultiplier:isTextOnly] != 1.0f; |
|
3339 } |
|
3340 |
|
3341 - (IBAction)_resetZoom:(id)sender isTextOnly:(BOOL)isTextOnly |
|
3342 { |
|
3343 id docView = [[[self mainFrame] frameView] documentView]; |
|
3344 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { |
|
3345 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; |
|
3346 return [zoomingDocView _resetZoom:sender]; |
|
3347 } |
|
3348 if ([self _zoomMultiplier:isTextOnly] != 1.0f) |
|
3349 [self _setZoomMultiplier:1.0f isTextOnly:isTextOnly]; |
|
3350 } |
|
3351 |
|
3352 - (void)setApplicationNameForUserAgent:(NSString *)applicationName |
|
3353 { |
|
3354 NSString *name = [applicationName copy]; |
|
3355 [_private->applicationNameForUserAgent release]; |
|
3356 _private->applicationNameForUserAgent = name; |
|
3357 if (!_private->userAgentOverridden) |
|
3358 _private->userAgent = String(); |
|
3359 } |
|
3360 |
|
3361 - (NSString *)applicationNameForUserAgent |
|
3362 { |
|
3363 return [[_private->applicationNameForUserAgent retain] autorelease]; |
|
3364 } |
|
3365 |
|
3366 - (void)setCustomUserAgent:(NSString *)userAgentString |
|
3367 { |
|
3368 _private->userAgent = userAgentString; |
|
3369 _private->userAgentOverridden = userAgentString != nil; |
|
3370 } |
|
3371 |
|
3372 - (NSString *)customUserAgent |
|
3373 { |
|
3374 if (!_private->userAgentOverridden) |
|
3375 return nil; |
|
3376 return _private->userAgent; |
|
3377 } |
|
3378 |
|
3379 - (void)setMediaStyle:(NSString *)mediaStyle |
|
3380 { |
|
3381 if (_private->mediaStyle != mediaStyle) { |
|
3382 [_private->mediaStyle release]; |
|
3383 _private->mediaStyle = [mediaStyle copy]; |
|
3384 } |
|
3385 } |
|
3386 |
|
3387 - (NSString *)mediaStyle |
|
3388 { |
|
3389 return _private->mediaStyle; |
|
3390 } |
|
3391 |
|
3392 - (BOOL)supportsTextEncoding |
|
3393 { |
|
3394 id documentView = [[[self mainFrame] frameView] documentView]; |
|
3395 return [documentView conformsToProtocol:@protocol(WebDocumentText)] |
|
3396 && [documentView supportsTextEncoding]; |
|
3397 } |
|
3398 |
|
3399 - (void)setCustomTextEncodingName:(NSString *)encoding |
|
3400 { |
|
3401 NSString *oldEncoding = [self customTextEncodingName]; |
|
3402 if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) |
|
3403 return; |
|
3404 if (Frame* mainFrame = [self _mainCoreFrame]) |
|
3405 mainFrame->loader()->reloadWithOverrideEncoding(encoding); |
|
3406 } |
|
3407 |
|
3408 - (NSString *)_mainFrameOverrideEncoding |
|
3409 { |
|
3410 WebDataSource *dataSource = [[self mainFrame] provisionalDataSource]; |
|
3411 if (dataSource == nil) |
|
3412 dataSource = [[self mainFrame] _dataSource]; |
|
3413 if (dataSource == nil) |
|
3414 return nil; |
|
3415 return nsStringNilIfEmpty([dataSource _documentLoader]->overrideEncoding()); |
|
3416 } |
|
3417 |
|
3418 - (NSString *)customTextEncodingName |
|
3419 { |
|
3420 return [self _mainFrameOverrideEncoding]; |
|
3421 } |
|
3422 |
|
3423 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script |
|
3424 { |
|
3425 // Return statements are only valid in a function but some applications pass in scripts |
|
3426 // prefixed with return (<rdar://problems/5103720&4616860>) since older WebKit versions |
|
3427 // silently ignored the return. If the application is linked against an earlier version |
|
3428 // of WebKit we will strip the return so the script wont fail. |
|
3429 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_JAVASCRIPT_RETURN_QUIRK)) { |
|
3430 NSRange returnStringRange = [script rangeOfString:@"return "]; |
|
3431 if (returnStringRange.length && !returnStringRange.location) |
|
3432 script = [script substringFromIndex:returnStringRange.location + returnStringRange.length]; |
|
3433 } |
|
3434 |
|
3435 NSString *result = [[self mainFrame] _stringByEvaluatingJavaScriptFromString:script]; |
|
3436 // The only way stringByEvaluatingJavaScriptFromString can return nil is if the frame was removed by the script |
|
3437 // Since there's no way to get rid of the main frame, result will never ever be nil here. |
|
3438 ASSERT(result); |
|
3439 |
|
3440 return result; |
|
3441 } |
|
3442 |
|
3443 - (WebScriptObject *)windowScriptObject |
|
3444 { |
|
3445 Frame* coreFrame = [self _mainCoreFrame]; |
|
3446 if (!coreFrame) |
|
3447 return nil; |
|
3448 return coreFrame->script()->windowScriptObject(); |
|
3449 } |
|
3450 |
|
3451 // Get the appropriate user-agent string for a particular URL. |
|
3452 - (NSString *)userAgentForURL:(NSURL *)url |
|
3453 { |
|
3454 if (_private->useSiteSpecificSpoofing) { |
|
3455 // No current site-specific spoofs. |
|
3456 } |
|
3457 |
|
3458 if (_private->userAgent.isNull()) |
|
3459 _private->userAgent = [[self class] _standardUserAgentWithApplicationName:_private->applicationNameForUserAgent]; |
|
3460 |
|
3461 return _private->userAgent; |
|
3462 } |
|
3463 |
|
3464 - (void)setHostWindow:(NSWindow *)hostWindow |
|
3465 { |
|
3466 if (_private->closed && hostWindow) |
|
3467 return; |
|
3468 if (hostWindow == _private->hostWindow) |
|
3469 return; |
|
3470 |
|
3471 Frame* coreFrame = [self _mainCoreFrame]; |
|
3472 if (_private->usesDocumentViews) { |
|
3473 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) |
|
3474 [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow]; |
|
3475 } |
|
3476 if (_private->hostWindow && [self window] != _private->hostWindow) |
|
3477 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow]; |
|
3478 if (hostWindow) |
|
3479 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow]; |
|
3480 [_private->hostWindow release]; |
|
3481 _private->hostWindow = [hostWindow retain]; |
|
3482 if (_private->usesDocumentViews) { |
|
3483 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) |
|
3484 [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow]; |
|
3485 } |
|
3486 } |
|
3487 |
|
3488 - (NSWindow *)hostWindow |
|
3489 { |
|
3490 // -[WebView hostWindow] can sometimes be called from the WebView's [super dealloc] method |
|
3491 // so we check here to make sure it's not null. |
|
3492 if (!_private) |
|
3493 return nil; |
|
3494 |
|
3495 return _private->hostWindow; |
|
3496 } |
|
3497 |
|
3498 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point |
|
3499 { |
|
3500 return [[self _frameViewAtWindowPoint:point] documentView]; |
|
3501 } |
|
3502 |
|
3503 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint |
|
3504 { |
|
3505 WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint]; |
|
3506 if (!frameView) |
|
3507 return nil; |
|
3508 NSView <WebDocumentView> *documentView = [frameView documentView]; |
|
3509 if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) { |
|
3510 NSPoint point = [documentView convertPoint:windowPoint fromView:nil]; |
|
3511 return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point]; |
|
3512 } |
|
3513 return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey]; |
|
3514 } |
|
3515 |
|
3516 - (NSDictionary *)elementAtPoint:(NSPoint)point |
|
3517 { |
|
3518 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]]; |
|
3519 } |
|
3520 |
|
3521 // The following 2 internal NSView methods are called on the drag destination to make scrolling while dragging work. |
|
3522 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination. |
|
3523 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination. |
|
3524 // Forward these calls to the document subview to make its scroll view scroll. |
|
3525 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta |
|
3526 { |
|
3527 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; |
|
3528 [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta]; |
|
3529 } |
|
3530 |
|
3531 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo |
|
3532 { |
|
3533 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; |
|
3534 return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo]; |
|
3535 } |
|
3536 |
|
3537 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo |
|
3538 { |
|
3539 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; |
|
3540 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); |
|
3541 IntPoint client([draggingInfo draggingLocation]); |
|
3542 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); |
|
3543 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); |
|
3544 return core(self)->dragController()->dragEntered(&dragData); |
|
3545 } |
|
3546 |
|
3547 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo |
|
3548 { |
|
3549 Page* page = core(self); |
|
3550 if (!page) |
|
3551 return NSDragOperationNone; |
|
3552 |
|
3553 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; |
|
3554 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); |
|
3555 IntPoint client([draggingInfo draggingLocation]); |
|
3556 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); |
|
3557 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); |
|
3558 return page->dragController()->dragUpdated(&dragData); |
|
3559 } |
|
3560 |
|
3561 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo |
|
3562 { |
|
3563 Page* page = core(self); |
|
3564 if (!page) |
|
3565 return; |
|
3566 |
|
3567 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; |
|
3568 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); |
|
3569 IntPoint client([draggingInfo draggingLocation]); |
|
3570 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); |
|
3571 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); |
|
3572 page->dragController()->dragExited(&dragData); |
|
3573 } |
|
3574 |
|
3575 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo |
|
3576 { |
|
3577 return YES; |
|
3578 } |
|
3579 |
|
3580 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo |
|
3581 { |
|
3582 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; |
|
3583 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]]? (WebHTMLView*)view : nil); |
|
3584 IntPoint client([draggingInfo draggingLocation]); |
|
3585 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); |
|
3586 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); |
|
3587 return core(self)->dragController()->performDrag(&dragData); |
|
3588 } |
|
3589 |
|
3590 - (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types |
|
3591 { |
|
3592 NSView *hitView = [super _hitTest:point dragTypes:types]; |
|
3593 if (!hitView && [[self superview] mouse:*point inRect:[self frame]]) |
|
3594 return self; |
|
3595 return hitView; |
|
3596 } |
|
3597 |
|
3598 - (BOOL)acceptsFirstResponder |
|
3599 { |
|
3600 if (_private->usesDocumentViews) |
|
3601 return [[[self mainFrame] frameView] acceptsFirstResponder]; |
|
3602 |
|
3603 // FIXME (Viewless): Need more code from WebHTMLView here. |
|
3604 return YES; |
|
3605 } |
|
3606 |
|
3607 - (BOOL)becomeFirstResponder |
|
3608 { |
|
3609 if (_private->usesDocumentViews) { |
|
3610 if (_private->becomingFirstResponder) { |
|
3611 // Fix for unrepro infinite recursion reported in Radar 4448181. If we hit this assert on |
|
3612 // a debug build, we should figure out what causes the problem and do a better fix. |
|
3613 ASSERT_NOT_REACHED(); |
|
3614 return NO; |
|
3615 } |
|
3616 |
|
3617 // This works together with setNextKeyView to splice the WebView into |
|
3618 // the key loop similar to the way NSScrollView does this. Note that |
|
3619 // WebFrameView has very similar code. |
|
3620 NSWindow *window = [self window]; |
|
3621 WebFrameView *mainFrameView = [[self mainFrame] frameView]; |
|
3622 |
|
3623 NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming]; |
|
3624 BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self); |
|
3625 |
|
3626 if ([window keyViewSelectionDirection] == NSSelectingPrevious) { |
|
3627 NSView *previousValidKeyView = [self previousValidKeyView]; |
|
3628 if (previousValidKeyView != self && previousValidKeyView != mainFrameView) { |
|
3629 _private->becomingFirstResponder = YES; |
|
3630 _private->becomingFirstResponderFromOutside = fromOutside; |
|
3631 [window makeFirstResponder:previousValidKeyView]; |
|
3632 _private->becomingFirstResponderFromOutside = NO; |
|
3633 _private->becomingFirstResponder = NO; |
|
3634 return YES; |
|
3635 } |
|
3636 return NO; |
|
3637 } |
|
3638 |
|
3639 if ([mainFrameView acceptsFirstResponder]) { |
|
3640 _private->becomingFirstResponder = YES; |
|
3641 _private->becomingFirstResponderFromOutside = fromOutside; |
|
3642 [window makeFirstResponder:mainFrameView]; |
|
3643 _private->becomingFirstResponderFromOutside = NO; |
|
3644 _private->becomingFirstResponder = NO; |
|
3645 return YES; |
|
3646 } |
|
3647 |
|
3648 return NO; |
|
3649 } |
|
3650 |
|
3651 // FIXME (Viewless): Need more code from WebHTMLView here. |
|
3652 return YES; |
|
3653 } |
|
3654 |
|
3655 - (NSView *)_webcore_effectiveFirstResponder |
|
3656 { |
|
3657 if (_private && _private->usesDocumentViews) { |
|
3658 if (WebFrameView *frameView = [[self mainFrame] frameView]) |
|
3659 return [frameView _webcore_effectiveFirstResponder]; |
|
3660 } |
|
3661 return [super _webcore_effectiveFirstResponder]; |
|
3662 } |
|
3663 |
|
3664 - (void)setNextKeyView:(NSView *)view |
|
3665 { |
|
3666 if (_private && _private->usesDocumentViews) { |
|
3667 // This works together with becomeFirstResponder to splice the WebView into |
|
3668 // the key loop similar to the way NSScrollView does this. Note that |
|
3669 // WebFrameView has similar code. |
|
3670 if (WebFrameView *mainFrameView = [[self mainFrame] frameView]) { |
|
3671 [mainFrameView setNextKeyView:view]; |
|
3672 return; |
|
3673 } |
|
3674 } |
|
3675 |
|
3676 [super setNextKeyView:view]; |
|
3677 } |
|
3678 |
|
3679 static WebFrame *incrementFrame(WebFrame *frame, BOOL forward, BOOL wrapFlag) |
|
3680 { |
|
3681 Frame* coreFrame = core(frame); |
|
3682 return kit(forward |
|
3683 ? coreFrame->tree()->traverseNextWithWrap(wrapFlag) |
|
3684 : coreFrame->tree()->traversePreviousWithWrap(wrapFlag)); |
|
3685 } |
|
3686 |
|
3687 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag |
|
3688 { |
|
3689 return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO]; |
|
3690 } |
|
3691 |
|
3692 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType |
|
3693 { |
|
3694 [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType]; |
|
3695 [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType]; |
|
3696 |
|
3697 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) |
|
3698 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner |
|
3699 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness |
|
3700 if ([viewClass class] == [WebHTMLView class]) |
|
3701 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType); |
|
3702 } |
|
3703 |
|
3704 - (void)setGroupName:(NSString *)groupName |
|
3705 { |
|
3706 if (!_private->page) |
|
3707 return; |
|
3708 _private->page->setGroupName(groupName); |
|
3709 } |
|
3710 |
|
3711 - (NSString *)groupName |
|
3712 { |
|
3713 if (!_private->page) |
|
3714 return nil; |
|
3715 return _private->page->groupName(); |
|
3716 } |
|
3717 |
|
3718 - (double)estimatedProgress |
|
3719 { |
|
3720 if (!_private->page) |
|
3721 return 0.0; |
|
3722 return _private->page->progress()->estimatedProgress(); |
|
3723 } |
|
3724 |
|
3725 - (NSArray *)pasteboardTypesForSelection |
|
3726 { |
|
3727 NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView]; |
|
3728 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) { |
|
3729 return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection]; |
|
3730 } |
|
3731 return [NSArray array]; |
|
3732 } |
|
3733 |
|
3734 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard |
|
3735 { |
|
3736 WebFrame *frame = [self _selectedOrMainFrame]; |
|
3737 if (frame && [frame _hasSelection]) { |
|
3738 NSView <WebDocumentView> *documentView = [[frame frameView] documentView]; |
|
3739 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) |
|
3740 [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard]; |
|
3741 } |
|
3742 } |
|
3743 |
|
3744 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element |
|
3745 { |
|
3746 if ([element objectForKey:WebElementImageURLKey] != nil) { |
|
3747 return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)]; |
|
3748 } else if ([element objectForKey:WebElementLinkURLKey] != nil) { |
|
3749 return [NSPasteboard _web_writableTypesForURL]; |
|
3750 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) { |
|
3751 return [self pasteboardTypesForSelection]; |
|
3752 } |
|
3753 return [NSArray array]; |
|
3754 } |
|
3755 |
|
3756 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard |
|
3757 { |
|
3758 if ([element objectForKey:WebElementImageURLKey] != nil) { |
|
3759 [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard]; |
|
3760 } else if ([element objectForKey:WebElementLinkURLKey] != nil) { |
|
3761 [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard]; |
|
3762 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) { |
|
3763 [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard]; |
|
3764 } |
|
3765 } |
|
3766 |
|
3767 - (void)moveDragCaretToPoint:(NSPoint)point |
|
3768 { |
|
3769 if (Page* page = core(self)) |
|
3770 page->dragController()->placeDragCaret(IntPoint([self convertPoint:point toView:nil])); |
|
3771 } |
|
3772 |
|
3773 - (void)removeDragCaret |
|
3774 { |
|
3775 if (Page* page = core(self)) |
|
3776 page->dragController()->dragEnded(); |
|
3777 } |
|
3778 |
|
3779 - (void)setMainFrameURL:(NSString *)URLString |
|
3780 { |
|
3781 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]]; |
|
3782 } |
|
3783 |
|
3784 - (NSString *)mainFrameURL |
|
3785 { |
|
3786 WebDataSource *ds; |
|
3787 ds = [[self mainFrame] provisionalDataSource]; |
|
3788 if (!ds) |
|
3789 ds = [[self mainFrame] _dataSource]; |
|
3790 return [[[ds request] URL] _web_originalDataAsString]; |
|
3791 } |
|
3792 |
|
3793 - (BOOL)isLoading |
|
3794 { |
|
3795 LOG (Bindings, "isLoading = %d", (int)[self _isLoading]); |
|
3796 return [self _isLoading]; |
|
3797 } |
|
3798 |
|
3799 - (NSString *)mainFrameTitle |
|
3800 { |
|
3801 NSString *mainFrameTitle = [[[self mainFrame] _dataSource] pageTitle]; |
|
3802 return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@""; |
|
3803 } |
|
3804 |
|
3805 - (NSImage *)mainFrameIcon |
|
3806 { |
|
3807 return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] _dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize]; |
|
3808 } |
|
3809 |
|
3810 - (DOMDocument *)mainFrameDocument |
|
3811 { |
|
3812 // only return the actual value if the state we're in gives NSTreeController |
|
3813 // enough time to release its observers on the old model |
|
3814 if (_private->mainFrameDocumentReady) |
|
3815 return [[self mainFrame] DOMDocument]; |
|
3816 return nil; |
|
3817 } |
|
3818 |
|
3819 - (void)setDrawsBackground:(BOOL)drawsBackground |
|
3820 { |
|
3821 if (_private->drawsBackground == drawsBackground) |
|
3822 return; |
|
3823 _private->drawsBackground = drawsBackground; |
|
3824 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; |
|
3825 } |
|
3826 |
|
3827 - (BOOL)drawsBackground |
|
3828 { |
|
3829 // This method can be called beneath -[NSView dealloc] after we have cleared _private, |
|
3830 // indirectly via -[WebFrameView viewDidMoveToWindow]. |
|
3831 return !_private || _private->drawsBackground; |
|
3832 } |
|
3833 |
|
3834 - (void)setShouldUpdateWhileOffscreen:(BOOL)updateWhileOffscreen |
|
3835 { |
|
3836 if (_private->shouldUpdateWhileOffscreen == updateWhileOffscreen) |
|
3837 return; |
|
3838 _private->shouldUpdateWhileOffscreen = updateWhileOffscreen; |
|
3839 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; |
|
3840 } |
|
3841 |
|
3842 - (BOOL)shouldUpdateWhileOffscreen |
|
3843 { |
|
3844 return _private->shouldUpdateWhileOffscreen; |
|
3845 } |
|
3846 |
|
3847 - (void)setCurrentNodeHighlight:(WebNodeHighlight *)nodeHighlight |
|
3848 { |
|
3849 id old = _private->currentNodeHighlight; |
|
3850 _private->currentNodeHighlight = [nodeHighlight retain]; |
|
3851 [old release]; |
|
3852 } |
|
3853 |
|
3854 - (WebNodeHighlight *)currentNodeHighlight |
|
3855 { |
|
3856 return _private->currentNodeHighlight; |
|
3857 } |
|
3858 |
|
3859 - (NSView *)previousValidKeyView |
|
3860 { |
|
3861 NSView *result = [super previousValidKeyView]; |
|
3862 |
|
3863 // Work around AppKit bug 6905484. If the result is a view that's inside this one, it's |
|
3864 // possible it is the wrong answer, because the fact that it's a descendant causes the |
|
3865 // code that implements key view redirection to fail; this means we won't redirect to |
|
3866 // the toolbar, for example, when we hit the edge of a window. Since the bug is specific |
|
3867 // to cases where the receiver of previousValidKeyView is an ancestor of the last valid |
|
3868 // key view in the loop, we can sidestep it by walking along previous key views until |
|
3869 // we find one that is not a superview, then using that to call previousValidKeyView. |
|
3870 |
|
3871 if (![result isDescendantOf:self]) |
|
3872 return result; |
|
3873 |
|
3874 // Use a visited set so we don't loop indefinitely when walking crazy key loops. |
|
3875 // AppKit uses such sets internally and we want our loop to be as robust as its loops. |
|
3876 RetainPtr<CFMutableSetRef> visitedViews = CFSetCreateMutable(0, 0, 0); |
|
3877 CFSetAddValue(visitedViews.get(), result); |
|
3878 |
|
3879 NSView *previousView = self; |
|
3880 do { |
|
3881 CFSetAddValue(visitedViews.get(), previousView); |
|
3882 previousView = [previousView previousKeyView]; |
|
3883 if (!previousView || CFSetGetValue(visitedViews.get(), previousView)) |
|
3884 return result; |
|
3885 } while ([result isDescendantOf:previousView]); |
|
3886 return [previousView previousValidKeyView]; |
|
3887 } |
|
3888 |
|
3889 @end |
|
3890 |
|
3891 @implementation WebView (WebIBActions) |
|
3892 |
|
3893 - (IBAction)takeStringURLFrom: sender |
|
3894 { |
|
3895 NSString *URLString = [sender stringValue]; |
|
3896 |
|
3897 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]]; |
|
3898 } |
|
3899 |
|
3900 - (BOOL)canGoBack |
|
3901 { |
|
3902 if (!_private->page) |
|
3903 return NO; |
|
3904 |
|
3905 return !!_private->page->backForwardList()->backItem(); |
|
3906 } |
|
3907 |
|
3908 - (BOOL)canGoForward |
|
3909 { |
|
3910 if (!_private->page) |
|
3911 return NO; |
|
3912 |
|
3913 return !!_private->page->backForwardList()->forwardItem(); |
|
3914 } |
|
3915 |
|
3916 - (IBAction)goBack:(id)sender |
|
3917 { |
|
3918 [self goBack]; |
|
3919 } |
|
3920 |
|
3921 - (IBAction)goForward:(id)sender |
|
3922 { |
|
3923 [self goForward]; |
|
3924 } |
|
3925 |
|
3926 - (IBAction)stopLoading:(id)sender |
|
3927 { |
|
3928 [[self mainFrame] stopLoading]; |
|
3929 } |
|
3930 |
|
3931 - (IBAction)reload:(id)sender |
|
3932 { |
|
3933 [[self mainFrame] reload]; |
|
3934 } |
|
3935 |
|
3936 - (IBAction)reloadFromOrigin:(id)sender |
|
3937 { |
|
3938 [[self mainFrame] reloadFromOrigin]; |
|
3939 } |
|
3940 |
|
3941 // FIXME: This code should move into WebCore so that it is not duplicated in each WebKit. |
|
3942 // (This includes canMakeTextSmaller/Larger, makeTextSmaller/Larger, and canMakeTextStandardSize/makeTextStandardSize) |
|
3943 - (BOOL)canMakeTextSmaller |
|
3944 { |
|
3945 return [self _canZoomOut:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; |
|
3946 } |
|
3947 |
|
3948 - (IBAction)makeTextSmaller:(id)sender |
|
3949 { |
|
3950 return [self _zoomOut:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; |
|
3951 } |
|
3952 |
|
3953 - (BOOL)canMakeTextLarger |
|
3954 { |
|
3955 return [self _canZoomIn:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; |
|
3956 } |
|
3957 |
|
3958 - (IBAction)makeTextLarger:(id)sender |
|
3959 { |
|
3960 return [self _zoomIn:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; |
|
3961 } |
|
3962 |
|
3963 - (BOOL)canMakeTextStandardSize |
|
3964 { |
|
3965 return [self _canResetZoom:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; |
|
3966 } |
|
3967 |
|
3968 - (IBAction)makeTextStandardSize:(id)sender |
|
3969 { |
|
3970 return [self _resetZoom:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; |
|
3971 } |
|
3972 |
|
3973 - (IBAction)toggleSmartInsertDelete:(id)sender |
|
3974 { |
|
3975 [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]]; |
|
3976 } |
|
3977 |
|
3978 - (IBAction)toggleContinuousSpellChecking:(id)sender |
|
3979 { |
|
3980 [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]]; |
|
3981 } |
|
3982 |
|
3983 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item |
|
3984 { |
|
3985 id responder = [self _responderForResponderOperations]; |
|
3986 if (responder != self && [responder respondsToSelector:[item action]]) { |
|
3987 if ([responder respondsToSelector:@selector(validateUserInterfaceItemWithoutDelegate:)]) |
|
3988 return [responder validateUserInterfaceItemWithoutDelegate:item]; |
|
3989 if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)]) |
|
3990 return [responder validateUserInterfaceItem:item]; |
|
3991 return YES; |
|
3992 } |
|
3993 return NO; |
|
3994 } |
|
3995 |
|
3996 #define VALIDATE(name) \ |
|
3997 else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; } |
|
3998 |
|
3999 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item |
|
4000 { |
|
4001 SEL action = [item action]; |
|
4002 |
|
4003 if (action == @selector(goBack:)) { |
|
4004 return [self canGoBack]; |
|
4005 } else if (action == @selector(goForward:)) { |
|
4006 return [self canGoForward]; |
|
4007 } else if (action == @selector(makeTextLarger:)) { |
|
4008 return [self canMakeTextLarger]; |
|
4009 } else if (action == @selector(makeTextSmaller:)) { |
|
4010 return [self canMakeTextSmaller]; |
|
4011 } else if (action == @selector(makeTextStandardSize:)) { |
|
4012 return [self canMakeTextStandardSize]; |
|
4013 } else if (action == @selector(reload:)) { |
|
4014 return [[self mainFrame] _dataSource] != nil; |
|
4015 } else if (action == @selector(stopLoading:)) { |
|
4016 return [self _isLoading]; |
|
4017 } else if (action == @selector(toggleContinuousSpellChecking:)) { |
|
4018 BOOL checkMark = NO; |
|
4019 BOOL retVal = NO; |
|
4020 if ([self _continuousCheckingAllowed]) { |
|
4021 checkMark = [self isContinuousSpellCheckingEnabled]; |
|
4022 retVal = YES; |
|
4023 } |
|
4024 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4025 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4026 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4027 } |
|
4028 return retVal; |
|
4029 } else if (action == @selector(toggleSmartInsertDelete:)) { |
|
4030 BOOL checkMark = [self smartInsertDeleteEnabled]; |
|
4031 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4032 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4033 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4034 } |
|
4035 return YES; |
|
4036 #ifndef BUILDING_ON_TIGER |
|
4037 } else if (action == @selector(toggleGrammarChecking:)) { |
|
4038 BOOL checkMark = [self isGrammarCheckingEnabled]; |
|
4039 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4040 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4041 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4042 } |
|
4043 return YES; |
|
4044 #endif |
|
4045 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) |
|
4046 } else if (action == @selector(toggleAutomaticQuoteSubstitution:)) { |
|
4047 BOOL checkMark = [self isAutomaticQuoteSubstitutionEnabled]; |
|
4048 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4049 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4050 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4051 } |
|
4052 return YES; |
|
4053 } else if (action == @selector(toggleAutomaticLinkDetection:)) { |
|
4054 BOOL checkMark = [self isAutomaticLinkDetectionEnabled]; |
|
4055 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4056 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4057 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4058 } |
|
4059 return YES; |
|
4060 } else if (action == @selector(toggleAutomaticDashSubstitution:)) { |
|
4061 BOOL checkMark = [self isAutomaticDashSubstitutionEnabled]; |
|
4062 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4063 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4064 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4065 } |
|
4066 return YES; |
|
4067 } else if (action == @selector(toggleAutomaticTextReplacement:)) { |
|
4068 BOOL checkMark = [self isAutomaticTextReplacementEnabled]; |
|
4069 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4070 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4071 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4072 } |
|
4073 return YES; |
|
4074 } else if (action == @selector(toggleAutomaticSpellingCorrection:)) { |
|
4075 BOOL checkMark = [self isAutomaticSpellingCorrectionEnabled]; |
|
4076 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { |
|
4077 NSMenuItem *menuItem = (NSMenuItem *)item; |
|
4078 [menuItem setState:checkMark ? NSOnState : NSOffState]; |
|
4079 } |
|
4080 return YES; |
|
4081 #endif |
|
4082 } |
|
4083 FOR_EACH_RESPONDER_SELECTOR(VALIDATE) |
|
4084 |
|
4085 return YES; |
|
4086 } |
|
4087 |
|
4088 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item |
|
4089 { |
|
4090 BOOL result = [self validateUserInterfaceItemWithoutDelegate:item]; |
|
4091 return CallUIDelegateReturningBoolean(result, self, @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result); |
|
4092 } |
|
4093 |
|
4094 @end |
|
4095 |
|
4096 @implementation WebView (WebPendingPublic) |
|
4097 |
|
4098 - (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode |
|
4099 { |
|
4100 if (runLoop && mode) |
|
4101 core(self)->addSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode)); |
|
4102 } |
|
4103 |
|
4104 - (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode |
|
4105 { |
|
4106 if (runLoop && mode) |
|
4107 core(self)->removeSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode)); |
|
4108 } |
|
4109 |
|
4110 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection |
|
4111 { |
|
4112 if (_private->closed) |
|
4113 return NO; |
|
4114 |
|
4115 // Get the frame holding the selection, or start with the main frame |
|
4116 WebFrame *startFrame = [self _selectedOrMainFrame]; |
|
4117 |
|
4118 // Search the first frame, then all the other frames, in order |
|
4119 NSView <WebDocumentSearching> *startSearchView = nil; |
|
4120 WebFrame *frame = startFrame; |
|
4121 do { |
|
4122 WebFrame *nextFrame = incrementFrame(frame, forward, wrapFlag); |
|
4123 |
|
4124 BOOL onlyOneFrame = (frame == nextFrame); |
|
4125 ASSERT(!onlyOneFrame || frame == startFrame); |
|
4126 |
|
4127 id <WebDocumentView> view = [[frame frameView] documentView]; |
|
4128 if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) { |
|
4129 NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view; |
|
4130 |
|
4131 if (frame == startFrame) |
|
4132 startSearchView = searchView; |
|
4133 |
|
4134 BOOL foundString; |
|
4135 // In some cases we have to search some content twice; see comment later in this method. |
|
4136 // We can avoid ever doing this in the common one-frame case by passing YES for wrapFlag |
|
4137 // here, and then bailing out before we get to the code that would search again in the |
|
4138 // same content. |
|
4139 BOOL wrapOnThisPass = wrapFlag && onlyOneFrame; |
|
4140 if ([searchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)]) |
|
4141 foundString = [(NSView <WebDocumentIncrementalSearching> *)searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass startInSelection:startInSelection]; |
|
4142 else |
|
4143 foundString = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass]; |
|
4144 |
|
4145 if (foundString) { |
|
4146 if (frame != startFrame) |
|
4147 [startFrame _clearSelection]; |
|
4148 [[self window] makeFirstResponder:searchView]; |
|
4149 return YES; |
|
4150 } |
|
4151 |
|
4152 if (onlyOneFrame) |
|
4153 return NO; |
|
4154 } |
|
4155 frame = nextFrame; |
|
4156 } while (frame && frame != startFrame); |
|
4157 |
|
4158 // If there are multiple frames and wrapFlag is true and we've visited each one without finding a result, we still need to search in the |
|
4159 // first-searched frame up to the selection. However, the API doesn't provide a way to search only up to a particular point. The only |
|
4160 // way to make sure the entire frame is searched is to pass YES for the wrapFlag. When there are no matches, this will search again |
|
4161 // some content that we already searched on the first pass. In the worst case, we could search the entire contents of this frame twice. |
|
4162 // To fix this, we'd need to add a mechanism to specify a range in which to search. |
|
4163 if (wrapFlag && startSearchView) { |
|
4164 BOOL foundString; |
|
4165 if ([startSearchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)]) |
|
4166 foundString = [(NSView <WebDocumentIncrementalSearching> *)startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES startInSelection:startInSelection]; |
|
4167 else |
|
4168 foundString = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES]; |
|
4169 if (foundString) { |
|
4170 [[self window] makeFirstResponder:startSearchView]; |
|
4171 return YES; |
|
4172 } |
|
4173 } |
|
4174 return NO; |
|
4175 } |
|
4176 |
|
4177 - (void)setHoverFeedbackSuspended:(BOOL)newValue |
|
4178 { |
|
4179 if (_private->hoverFeedbackSuspended == newValue) |
|
4180 return; |
|
4181 |
|
4182 _private->hoverFeedbackSuspended = newValue; |
|
4183 |
|
4184 if (_private->usesDocumentViews) { |
|
4185 id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView]; |
|
4186 // FIXME: in a perfect world we'd do this in a general way that worked with any document view, |
|
4187 // such as by calling a protocol method or using respondsToSelector or sending a notification. |
|
4188 // But until there is any need for these more general solutions, we'll just hardwire it to work |
|
4189 // with WebHTMLView. |
|
4190 // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not |
|
4191 // on each subframe separately. |
|
4192 if ([documentView isKindOfClass:[WebHTMLView class]]) |
|
4193 [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged]; |
|
4194 return; |
|
4195 } |
|
4196 |
|
4197 [self _updateMouseoverWithFakeEvent]; |
|
4198 } |
|
4199 |
|
4200 - (BOOL)isHoverFeedbackSuspended |
|
4201 { |
|
4202 return _private->hoverFeedbackSuspended; |
|
4203 } |
|
4204 |
|
4205 - (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady |
|
4206 { |
|
4207 // by setting this to NO, calls to mainFrameDocument are forced to return nil |
|
4208 // setting this to YES lets it return the actual DOMDocument value |
|
4209 // we use this to tell NSTreeController to reset its observers and clear its state |
|
4210 if (_private->mainFrameDocumentReady == mainFrameDocumentReady) |
|
4211 return; |
|
4212 [self _willChangeValueForKey:_WebMainFrameDocumentKey]; |
|
4213 _private->mainFrameDocumentReady = mainFrameDocumentReady; |
|
4214 [self _didChangeValueForKey:_WebMainFrameDocumentKey]; |
|
4215 // this will cause observers to call mainFrameDocument where this flag will be checked |
|
4216 } |
|
4217 |
|
4218 // This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it |
|
4219 // until the day comes when we're no longer supporting Mail on Tiger. |
|
4220 - (WebFrame *)_frameForCurrentSelection |
|
4221 { |
|
4222 return [self _selectedOrMainFrame]; |
|
4223 } |
|
4224 |
|
4225 - (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements |
|
4226 { |
|
4227 _private->tabKeyCyclesThroughElementsChanged = YES; |
|
4228 if (_private->page) |
|
4229 _private->page->setTabKeyCyclesThroughElements(cyclesElements); |
|
4230 } |
|
4231 |
|
4232 - (BOOL)tabKeyCyclesThroughElements |
|
4233 { |
|
4234 return _private->page && _private->page->tabKeyCyclesThroughElements(); |
|
4235 } |
|
4236 |
|
4237 - (void)setScriptDebugDelegate:(id)delegate |
|
4238 { |
|
4239 _private->scriptDebugDelegate = delegate; |
|
4240 [self _cacheScriptDebugDelegateImplementations]; |
|
4241 |
|
4242 if (delegate) |
|
4243 [self _attachScriptDebuggerToAllFrames]; |
|
4244 else |
|
4245 [self _detachScriptDebuggerFromAllFrames]; |
|
4246 } |
|
4247 |
|
4248 - (id)scriptDebugDelegate |
|
4249 { |
|
4250 return _private->scriptDebugDelegate; |
|
4251 } |
|
4252 |
|
4253 - (void)setHistoryDelegate:(id)delegate |
|
4254 { |
|
4255 _private->historyDelegate = delegate; |
|
4256 [self _cacheHistoryDelegateImplementations]; |
|
4257 } |
|
4258 |
|
4259 - (id)historyDelegate |
|
4260 { |
|
4261 return _private->historyDelegate; |
|
4262 } |
|
4263 |
|
4264 - (BOOL)shouldClose |
|
4265 { |
|
4266 Frame* coreFrame = [self _mainCoreFrame]; |
|
4267 if (!coreFrame) |
|
4268 return YES; |
|
4269 return coreFrame->loader()->shouldClose(); |
|
4270 } |
|
4271 |
|
4272 static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue jsValue) |
|
4273 { |
|
4274 NSAppleEventDescriptor* aeDesc = 0; |
|
4275 if (jsValue.isBoolean()) |
|
4276 return [NSAppleEventDescriptor descriptorWithBoolean:jsValue.getBoolean()]; |
|
4277 if (jsValue.isString()) |
|
4278 return [NSAppleEventDescriptor descriptorWithString:ustringToString(jsValue.getString(exec))]; |
|
4279 if (jsValue.isNumber()) { |
|
4280 double value = jsValue.uncheckedGetNumber(); |
|
4281 int intValue = value; |
|
4282 if (value == intValue) |
|
4283 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt32 bytes:&intValue length:sizeof(intValue)]; |
|
4284 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&value length:sizeof(value)]; |
|
4285 } |
|
4286 if (jsValue.isObject()) { |
|
4287 JSObject* object = jsValue.getObject(); |
|
4288 if (object->inherits(&DateInstance::info)) { |
|
4289 DateInstance* date = static_cast<DateInstance*>(object); |
|
4290 double ms = date->internalNumber(); |
|
4291 if (!isnan(ms)) { |
|
4292 CFAbsoluteTime utcSeconds = ms / 1000 - kCFAbsoluteTimeIntervalSince1970; |
|
4293 LongDateTime ldt; |
|
4294 if (noErr == UCConvertCFAbsoluteTimeToLongDateTime(utcSeconds, &ldt)) |
|
4295 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&ldt length:sizeof(ldt)]; |
|
4296 } |
|
4297 } |
|
4298 else if (object->inherits(&JSArray::info)) { |
|
4299 DEFINE_STATIC_LOCAL(HashSet<JSObject*>, visitedElems, ()); |
|
4300 if (!visitedElems.contains(object)) { |
|
4301 visitedElems.add(object); |
|
4302 |
|
4303 JSArray* array = static_cast<JSArray*>(object); |
|
4304 aeDesc = [NSAppleEventDescriptor listDescriptor]; |
|
4305 unsigned numItems = array->length(); |
|
4306 for (unsigned i = 0; i < numItems; ++i) |
|
4307 [aeDesc insertDescriptor:aeDescFromJSValue(exec, array->get(exec, i)) atIndex:0]; |
|
4308 |
|
4309 visitedElems.remove(object); |
|
4310 return aeDesc; |
|
4311 } |
|
4312 } |
|
4313 JSValue primitive = object->toPrimitive(exec); |
|
4314 if (exec->hadException()) { |
|
4315 exec->clearException(); |
|
4316 return [NSAppleEventDescriptor nullDescriptor]; |
|
4317 } |
|
4318 return aeDescFromJSValue(exec, primitive); |
|
4319 } |
|
4320 if (jsValue.isUndefined()) |
|
4321 return [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue]; |
|
4322 ASSERT(jsValue.isNull()); |
|
4323 return [NSAppleEventDescriptor nullDescriptor]; |
|
4324 } |
|
4325 |
|
4326 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script |
|
4327 { |
|
4328 Frame* coreFrame = [self _mainCoreFrame]; |
|
4329 if (!coreFrame) |
|
4330 return nil; |
|
4331 if (!coreFrame->document()) |
|
4332 return nil; |
|
4333 JSValue result = coreFrame->script()->executeScript(script, true).jsValue(); |
|
4334 if (!result) // FIXME: pass errors |
|
4335 return 0; |
|
4336 JSLock lock(SilenceAssertionsOnly); |
|
4337 return aeDescFromJSValue(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec(), result); |
|
4338 } |
|
4339 |
|
4340 - (BOOL)canMarkAllTextMatches |
|
4341 { |
|
4342 WebFrame *frame = [self mainFrame]; |
|
4343 do { |
|
4344 id <WebDocumentView> view = [[frame frameView] documentView]; |
|
4345 if (view && ![view conformsToProtocol:@protocol(WebMultipleTextMatches)]) |
|
4346 return NO; |
|
4347 |
|
4348 frame = incrementFrame(frame, YES, NO); |
|
4349 } while (frame); |
|
4350 |
|
4351 return YES; |
|
4352 } |
|
4353 |
|
4354 - (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit |
|
4355 { |
|
4356 WebFrame *frame = [self mainFrame]; |
|
4357 unsigned matchCount = 0; |
|
4358 do { |
|
4359 id <WebDocumentView> view = [[frame frameView] documentView]; |
|
4360 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) { |
|
4361 [(NSView <WebMultipleTextMatches>*)view setMarkedTextMatchesAreHighlighted:highlight]; |
|
4362 |
|
4363 ASSERT(limit == 0 || matchCount < limit); |
|
4364 matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount]; |
|
4365 |
|
4366 // Stop looking if we've reached the limit. A limit of 0 means no limit. |
|
4367 if (limit > 0 && matchCount >= limit) |
|
4368 break; |
|
4369 } |
|
4370 |
|
4371 frame = incrementFrame(frame, YES, NO); |
|
4372 } while (frame); |
|
4373 |
|
4374 return matchCount; |
|
4375 } |
|
4376 |
|
4377 - (void)unmarkAllTextMatches |
|
4378 { |
|
4379 WebFrame *frame = [self mainFrame]; |
|
4380 do { |
|
4381 id <WebDocumentView> view = [[frame frameView] documentView]; |
|
4382 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) |
|
4383 [(NSView <WebMultipleTextMatches>*)view unmarkAllTextMatches]; |
|
4384 |
|
4385 frame = incrementFrame(frame, YES, NO); |
|
4386 } while (frame); |
|
4387 } |
|
4388 |
|
4389 - (NSArray *)rectsForTextMatches |
|
4390 { |
|
4391 NSMutableArray *result = [NSMutableArray array]; |
|
4392 WebFrame *frame = [self mainFrame]; |
|
4393 do { |
|
4394 id <WebDocumentView> view = [[frame frameView] documentView]; |
|
4395 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) { |
|
4396 NSView <WebMultipleTextMatches> *documentView = (NSView <WebMultipleTextMatches> *)view; |
|
4397 NSRect documentViewVisibleRect = [documentView visibleRect]; |
|
4398 NSArray *originalRects = [documentView rectsForTextMatches]; |
|
4399 unsigned rectCount = [originalRects count]; |
|
4400 unsigned rectIndex; |
|
4401 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
4402 for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) { |
|
4403 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue]; |
|
4404 // Clip rect to document view's visible rect so rect is confined to subframe |
|
4405 r = NSIntersectionRect(r, documentViewVisibleRect); |
|
4406 if (NSIsEmptyRect(r)) |
|
4407 continue; |
|
4408 |
|
4409 // Convert rect to our coordinate system |
|
4410 r = [documentView convertRect:r toView:self]; |
|
4411 [result addObject:[NSValue valueWithRect:r]]; |
|
4412 if (rectIndex % 10 == 0) { |
|
4413 [pool drain]; |
|
4414 pool = [[NSAutoreleasePool alloc] init]; |
|
4415 } |
|
4416 } |
|
4417 [pool drain]; |
|
4418 } |
|
4419 |
|
4420 frame = incrementFrame(frame, YES, NO); |
|
4421 } while (frame); |
|
4422 |
|
4423 return result; |
|
4424 } |
|
4425 |
|
4426 - (void)scrollDOMRangeToVisible:(DOMRange *)range |
|
4427 { |
|
4428 [[[[range startContainer] ownerDocument] webFrame] _scrollDOMRangeToVisible:range]; |
|
4429 } |
|
4430 |
|
4431 - (BOOL)allowsUndo |
|
4432 { |
|
4433 return _private->allowsUndo; |
|
4434 } |
|
4435 |
|
4436 - (void)setAllowsUndo:(BOOL)flag |
|
4437 { |
|
4438 _private->allowsUndo = flag; |
|
4439 } |
|
4440 |
|
4441 - (void)setPageSizeMultiplier:(float)m |
|
4442 { |
|
4443 [self _setZoomMultiplier:m isTextOnly:NO]; |
|
4444 } |
|
4445 |
|
4446 - (float)pageSizeMultiplier |
|
4447 { |
|
4448 return ![self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f; |
|
4449 } |
|
4450 |
|
4451 - (BOOL)canZoomPageIn |
|
4452 { |
|
4453 return [self _canZoomIn:NO]; |
|
4454 } |
|
4455 |
|
4456 - (IBAction)zoomPageIn:(id)sender |
|
4457 { |
|
4458 return [self _zoomIn:sender isTextOnly:NO]; |
|
4459 } |
|
4460 |
|
4461 - (BOOL)canZoomPageOut |
|
4462 { |
|
4463 return [self _canZoomOut:NO]; |
|
4464 } |
|
4465 |
|
4466 - (IBAction)zoomPageOut:(id)sender |
|
4467 { |
|
4468 return [self _zoomOut:sender isTextOnly:NO]; |
|
4469 } |
|
4470 |
|
4471 - (BOOL)canResetPageZoom |
|
4472 { |
|
4473 return [self _canResetZoom:NO]; |
|
4474 } |
|
4475 |
|
4476 - (IBAction)resetPageZoom:(id)sender |
|
4477 { |
|
4478 return [self _resetZoom:sender isTextOnly:NO]; |
|
4479 } |
|
4480 |
|
4481 - (void)setMediaVolume:(float)volume |
|
4482 { |
|
4483 if (_private->page) |
|
4484 _private->page->setMediaVolume(volume); |
|
4485 } |
|
4486 |
|
4487 - (float)mediaVolume |
|
4488 { |
|
4489 if (!_private->page) |
|
4490 return 0; |
|
4491 |
|
4492 return _private->page->mediaVolume(); |
|
4493 } |
|
4494 |
|
4495 - (void)addVisitedLinks:(NSArray *)visitedLinks |
|
4496 { |
|
4497 PageGroup& group = core(self)->group(); |
|
4498 |
|
4499 NSEnumerator *enumerator = [visitedLinks objectEnumerator]; |
|
4500 while (NSString *url = [enumerator nextObject]) { |
|
4501 size_t length = [url length]; |
|
4502 const UChar* characters = CFStringGetCharactersPtr(reinterpret_cast<CFStringRef>(url)); |
|
4503 if (characters) |
|
4504 group.addVisitedLink(characters, length); |
|
4505 else { |
|
4506 Vector<UChar, 512> buffer(length); |
|
4507 [url getCharacters:buffer.data()]; |
|
4508 group.addVisitedLink(buffer.data(), length); |
|
4509 } |
|
4510 } |
|
4511 } |
|
4512 |
|
4513 @end |
|
4514 |
|
4515 @implementation WebView (WebViewPrintingPrivate) |
|
4516 |
|
4517 - (float)_headerHeight |
|
4518 { |
|
4519 return CallUIDelegateReturningFloat(self, @selector(webViewHeaderHeight:)); |
|
4520 } |
|
4521 |
|
4522 - (float)_footerHeight |
|
4523 { |
|
4524 return CallUIDelegateReturningFloat(self, @selector(webViewFooterHeight:)); |
|
4525 } |
|
4526 |
|
4527 - (void)_drawHeaderInRect:(NSRect)rect |
|
4528 { |
|
4529 #ifdef DEBUG_HEADER_AND_FOOTER |
|
4530 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; |
|
4531 [currentContext saveGraphicsState]; |
|
4532 [[NSColor yellowColor] set]; |
|
4533 NSRectFill(rect); |
|
4534 [currentContext restoreGraphicsState]; |
|
4535 #endif |
|
4536 |
|
4537 SEL selector = @selector(webView:drawHeaderInRect:); |
|
4538 if (![_private->UIDelegate respondsToSelector:selector]) |
|
4539 return; |
|
4540 |
|
4541 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; |
|
4542 [currentContext saveGraphicsState]; |
|
4543 |
|
4544 NSRectClip(rect); |
|
4545 CallUIDelegate(self, selector, rect); |
|
4546 |
|
4547 [currentContext restoreGraphicsState]; |
|
4548 } |
|
4549 |
|
4550 - (void)_drawFooterInRect:(NSRect)rect |
|
4551 { |
|
4552 #ifdef DEBUG_HEADER_AND_FOOTER |
|
4553 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; |
|
4554 [currentContext saveGraphicsState]; |
|
4555 [[NSColor cyanColor] set]; |
|
4556 NSRectFill(rect); |
|
4557 [currentContext restoreGraphicsState]; |
|
4558 #endif |
|
4559 |
|
4560 SEL selector = @selector(webView:drawFooterInRect:); |
|
4561 if (![_private->UIDelegate respondsToSelector:selector]) |
|
4562 return; |
|
4563 |
|
4564 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; |
|
4565 [currentContext saveGraphicsState]; |
|
4566 |
|
4567 NSRectClip(rect); |
|
4568 CallUIDelegate(self, selector, rect); |
|
4569 |
|
4570 [currentContext restoreGraphicsState]; |
|
4571 } |
|
4572 |
|
4573 - (void)_adjustPrintingMarginsForHeaderAndFooter |
|
4574 { |
|
4575 NSPrintOperation *op = [NSPrintOperation currentOperation]; |
|
4576 NSPrintInfo *info = [op printInfo]; |
|
4577 NSMutableDictionary *infoDictionary = [info dictionary]; |
|
4578 |
|
4579 // We need to modify the top and bottom margins in the NSPrintInfo to account for the space needed by the |
|
4580 // header and footer. Because this method can be called more than once on the same NSPrintInfo (see 5038087), |
|
4581 // we stash away the unmodified top and bottom margins the first time this method is called, and we read from |
|
4582 // those stashed-away values on subsequent calls. |
|
4583 float originalTopMargin; |
|
4584 float originalBottomMargin; |
|
4585 NSNumber *originalTopMarginNumber = [infoDictionary objectForKey:WebKitOriginalTopPrintingMarginKey]; |
|
4586 if (!originalTopMarginNumber) { |
|
4587 ASSERT(![infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey]); |
|
4588 originalTopMargin = [info topMargin]; |
|
4589 originalBottomMargin = [info bottomMargin]; |
|
4590 [infoDictionary setObject:[NSNumber numberWithFloat:originalTopMargin] forKey:WebKitOriginalTopPrintingMarginKey]; |
|
4591 [infoDictionary setObject:[NSNumber numberWithFloat:originalBottomMargin] forKey:WebKitOriginalBottomPrintingMarginKey]; |
|
4592 } else { |
|
4593 ASSERT([originalTopMarginNumber isKindOfClass:[NSNumber class]]); |
|
4594 ASSERT([[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] isKindOfClass:[NSNumber class]]); |
|
4595 originalTopMargin = [originalTopMarginNumber floatValue]; |
|
4596 originalBottomMargin = [[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] floatValue]; |
|
4597 } |
|
4598 |
|
4599 float scale = [op _web_pageSetupScaleFactor]; |
|
4600 [info setTopMargin:originalTopMargin + [self _headerHeight] * scale]; |
|
4601 [info setBottomMargin:originalBottomMargin + [self _footerHeight] * scale]; |
|
4602 } |
|
4603 |
|
4604 - (void)_drawHeaderAndFooter |
|
4605 { |
|
4606 // The header and footer rect height scales with the page, but the width is always |
|
4607 // all the way across the printed page (inset by printing margins). |
|
4608 NSPrintOperation *op = [NSPrintOperation currentOperation]; |
|
4609 float scale = [op _web_pageSetupScaleFactor]; |
|
4610 NSPrintInfo *printInfo = [op printInfo]; |
|
4611 NSSize paperSize = [printInfo paperSize]; |
|
4612 float headerFooterLeft = [printInfo leftMargin]/scale; |
|
4613 float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale; |
|
4614 NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] , |
|
4615 headerFooterWidth, [self _footerHeight]); |
|
4616 NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale, |
|
4617 headerFooterWidth, [self _headerHeight]); |
|
4618 |
|
4619 [self _drawHeaderInRect:headerRect]; |
|
4620 [self _drawFooterInRect:footerRect]; |
|
4621 } |
|
4622 @end |
|
4623 |
|
4624 @implementation WebView (WebDebugBinding) |
|
4625 |
|
4626 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context |
|
4627 { |
|
4628 LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context); |
|
4629 [super addObserver:anObserver forKeyPath:keyPath options:options context:context]; |
|
4630 } |
|
4631 |
|
4632 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath |
|
4633 { |
|
4634 LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath); |
|
4635 [super removeObserver:anObserver forKeyPath:keyPath]; |
|
4636 } |
|
4637 |
|
4638 @end |
|
4639 |
|
4640 //========================================================================================== |
|
4641 // Editing |
|
4642 |
|
4643 @implementation WebView (WebViewCSS) |
|
4644 |
|
4645 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement |
|
4646 { |
|
4647 // FIXME: is this the best level for this conversion? |
|
4648 if (pseudoElement == nil) |
|
4649 pseudoElement = @""; |
|
4650 |
|
4651 return [[element ownerDocument] getComputedStyle:element pseudoElement:pseudoElement]; |
|
4652 } |
|
4653 |
|
4654 @end |
|
4655 |
|
4656 @implementation WebView (WebViewEditing) |
|
4657 |
|
4658 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point |
|
4659 { |
|
4660 Page* page = core(self); |
|
4661 if (!page) |
|
4662 return nil; |
|
4663 return kit(page->mainFrame()->editor()->rangeForPoint(IntPoint([self convertPoint:point toView:nil])).get()); |
|
4664 } |
|
4665 |
|
4666 - (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag |
|
4667 { |
|
4668 // FIXME: This quirk is needed due to <rdar://problem/4985321> - We can phase it out once Aperture can adopt the new behavior on their end |
|
4669 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"]) |
|
4670 return YES; |
|
4671 return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag]; |
|
4672 } |
|
4673 |
|
4674 - (BOOL)maintainsInactiveSelection |
|
4675 { |
|
4676 return NO; |
|
4677 } |
|
4678 |
|
4679 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity |
|
4680 { |
|
4681 Frame* coreFrame = core([self _selectedOrMainFrame]); |
|
4682 if (!coreFrame) |
|
4683 return; |
|
4684 |
|
4685 if (range == nil) |
|
4686 coreFrame->selection()->clear(); |
|
4687 else { |
|
4688 // Derive the frame to use from the range passed in. |
|
4689 // Using _selectedOrMainFrame could give us a different document than |
|
4690 // the one the range uses. |
|
4691 coreFrame = core([range startContainer])->document()->frame(); |
|
4692 if (!coreFrame) |
|
4693 return; |
|
4694 |
|
4695 coreFrame->selection()->setSelectedRange(core(range), core(selectionAffinity), true); |
|
4696 } |
|
4697 } |
|
4698 |
|
4699 - (DOMRange *)selectedDOMRange |
|
4700 { |
|
4701 Frame* coreFrame = core([self _selectedOrMainFrame]); |
|
4702 if (!coreFrame) |
|
4703 return nil; |
|
4704 return kit(coreFrame->selection()->toNormalizedRange().get()); |
|
4705 } |
|
4706 |
|
4707 - (NSSelectionAffinity)selectionAffinity |
|
4708 { |
|
4709 Frame* coreFrame = core([self _selectedOrMainFrame]); |
|
4710 if (!coreFrame) |
|
4711 return NSSelectionAffinityDownstream; |
|
4712 return kit(coreFrame->selection()->affinity()); |
|
4713 } |
|
4714 |
|
4715 - (void)setEditable:(BOOL)flag |
|
4716 { |
|
4717 if (_private->editable != flag) { |
|
4718 _private->editable = flag; |
|
4719 if (!_private->tabKeyCyclesThroughElementsChanged && _private->page) |
|
4720 _private->page->setTabKeyCyclesThroughElements(!flag); |
|
4721 Frame* mainFrame = [self _mainCoreFrame]; |
|
4722 if (mainFrame) { |
|
4723 if (flag) { |
|
4724 mainFrame->applyEditingStyleToBodyElement(); |
|
4725 // If the WebView is made editable and the selection is empty, set it to something. |
|
4726 if (![self selectedDOMRange]) |
|
4727 mainFrame->setSelectionFromNone(); |
|
4728 } |
|
4729 } |
|
4730 } |
|
4731 } |
|
4732 |
|
4733 - (BOOL)isEditable |
|
4734 { |
|
4735 return _private->editable; |
|
4736 } |
|
4737 |
|
4738 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style |
|
4739 { |
|
4740 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to |
|
4741 // change the API to allow this. |
|
4742 [[self _selectedOrMainFrame] _setTypingStyle:style withUndoAction:EditActionUnspecified]; |
|
4743 } |
|
4744 |
|
4745 - (DOMCSSStyleDeclaration *)typingStyle |
|
4746 { |
|
4747 return [[self _selectedOrMainFrame] _typingStyle]; |
|
4748 } |
|
4749 |
|
4750 - (void)setSmartInsertDeleteEnabled:(BOOL)flag |
|
4751 { |
|
4752 if (_private->smartInsertDeleteEnabled != flag) { |
|
4753 _private->smartInsertDeleteEnabled = flag; |
|
4754 [[NSUserDefaults standardUserDefaults] setBool:_private->smartInsertDeleteEnabled forKey:WebSmartInsertDeleteEnabled]; |
|
4755 } |
|
4756 if (flag) |
|
4757 [self setSelectTrailingWhitespaceEnabled:false]; |
|
4758 } |
|
4759 |
|
4760 - (BOOL)smartInsertDeleteEnabled |
|
4761 { |
|
4762 return _private->smartInsertDeleteEnabled; |
|
4763 } |
|
4764 |
|
4765 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag |
|
4766 { |
|
4767 if (continuousSpellCheckingEnabled != flag) { |
|
4768 continuousSpellCheckingEnabled = flag; |
|
4769 [[NSUserDefaults standardUserDefaults] setBool:continuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled]; |
|
4770 } |
|
4771 |
|
4772 if ([self isContinuousSpellCheckingEnabled]) { |
|
4773 [[self class] _preflightSpellChecker]; |
|
4774 } else { |
|
4775 [[self mainFrame] _unmarkAllMisspellings]; |
|
4776 } |
|
4777 } |
|
4778 |
|
4779 - (BOOL)isContinuousSpellCheckingEnabled |
|
4780 { |
|
4781 return (continuousSpellCheckingEnabled && [self _continuousCheckingAllowed]); |
|
4782 } |
|
4783 |
|
4784 - (NSInteger)spellCheckerDocumentTag |
|
4785 { |
|
4786 if (!_private->hasSpellCheckerDocumentTag) { |
|
4787 _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag]; |
|
4788 _private->hasSpellCheckerDocumentTag = YES; |
|
4789 } |
|
4790 return _private->spellCheckerDocumentTag; |
|
4791 } |
|
4792 |
|
4793 - (NSUndoManager *)undoManager |
|
4794 { |
|
4795 if (!_private->allowsUndo) |
|
4796 return nil; |
|
4797 |
|
4798 NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self]; |
|
4799 if (undoManager) |
|
4800 return undoManager; |
|
4801 |
|
4802 return [super undoManager]; |
|
4803 } |
|
4804 |
|
4805 - (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector |
|
4806 { |
|
4807 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; |
|
4808 if ([_private->editingDelegate respondsToSelector:selector]) |
|
4809 [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self]; |
|
4810 } |
|
4811 |
|
4812 - (void)setEditingDelegate:(id)delegate |
|
4813 { |
|
4814 if (_private->editingDelegate == delegate) |
|
4815 return; |
|
4816 |
|
4817 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; |
|
4818 |
|
4819 // remove notifications from current delegate |
|
4820 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self]; |
|
4821 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self]; |
|
4822 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self]; |
|
4823 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self]; |
|
4824 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self]; |
|
4825 |
|
4826 _private->editingDelegate = delegate; |
|
4827 [_private->editingDelegateForwarder release]; |
|
4828 _private->editingDelegateForwarder = nil; |
|
4829 |
|
4830 // add notifications for new delegate |
|
4831 [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)]; |
|
4832 [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)]; |
|
4833 [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)]; |
|
4834 [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)]; |
|
4835 [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)]; |
|
4836 } |
|
4837 |
|
4838 - (id)editingDelegate |
|
4839 { |
|
4840 return _private->editingDelegate; |
|
4841 } |
|
4842 |
|
4843 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text |
|
4844 { |
|
4845 // FIXME: Should this really be attached to the document with the current selection? |
|
4846 DOMCSSStyleDeclaration *decl = [[[self _selectedOrMainFrame] DOMDocument] createCSSStyleDeclaration]; |
|
4847 [decl setCssText:text]; |
|
4848 return decl; |
|
4849 } |
|
4850 |
|
4851 @end |
|
4852 |
|
4853 @implementation WebView (WebViewGrammarChecking) |
|
4854 |
|
4855 // FIXME: This method should be merged into WebViewEditing when we're not in API freeze |
|
4856 - (BOOL)isGrammarCheckingEnabled |
|
4857 { |
|
4858 #ifdef BUILDING_ON_TIGER |
|
4859 return NO; |
|
4860 #else |
|
4861 return grammarCheckingEnabled; |
|
4862 #endif |
|
4863 } |
|
4864 |
|
4865 #ifndef BUILDING_ON_TIGER |
|
4866 // FIXME: This method should be merged into WebViewEditing when we're not in API freeze |
|
4867 - (void)setGrammarCheckingEnabled:(BOOL)flag |
|
4868 { |
|
4869 if (grammarCheckingEnabled == flag) |
|
4870 return; |
|
4871 |
|
4872 grammarCheckingEnabled = flag; |
|
4873 [[NSUserDefaults standardUserDefaults] setBool:grammarCheckingEnabled forKey:WebGrammarCheckingEnabled]; |
|
4874 |
|
4875 #ifndef BUILDING_ON_LEOPARD |
|
4876 [[NSSpellChecker sharedSpellChecker] updatePanels]; |
|
4877 #else |
|
4878 NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker]; |
|
4879 if ([spellChecker respondsToSelector:@selector(_updateGrammar)]) |
|
4880 [spellChecker performSelector:@selector(_updateGrammar)]; |
|
4881 #endif |
|
4882 |
|
4883 // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here |
|
4884 // because grammar checking only occurs on code paths that already preflight spell checking appropriately. |
|
4885 |
|
4886 if (![self isGrammarCheckingEnabled]) |
|
4887 [[self mainFrame] _unmarkAllBadGrammar]; |
|
4888 } |
|
4889 |
|
4890 // FIXME: This method should be merged into WebIBActions when we're not in API freeze |
|
4891 - (void)toggleGrammarChecking:(id)sender |
|
4892 { |
|
4893 [self setGrammarCheckingEnabled:![self isGrammarCheckingEnabled]]; |
|
4894 } |
|
4895 #endif |
|
4896 |
|
4897 @end |
|
4898 |
|
4899 @implementation WebView (WebViewTextChecking) |
|
4900 |
|
4901 - (BOOL)isAutomaticQuoteSubstitutionEnabled |
|
4902 { |
|
4903 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) |
|
4904 return NO; |
|
4905 #else |
|
4906 return automaticQuoteSubstitutionEnabled; |
|
4907 #endif |
|
4908 } |
|
4909 |
|
4910 - (BOOL)isAutomaticLinkDetectionEnabled |
|
4911 { |
|
4912 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) |
|
4913 return NO; |
|
4914 #else |
|
4915 return automaticLinkDetectionEnabled; |
|
4916 #endif |
|
4917 } |
|
4918 |
|
4919 - (BOOL)isAutomaticDashSubstitutionEnabled |
|
4920 { |
|
4921 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) |
|
4922 return NO; |
|
4923 #else |
|
4924 return automaticDashSubstitutionEnabled; |
|
4925 #endif |
|
4926 } |
|
4927 |
|
4928 - (BOOL)isAutomaticTextReplacementEnabled |
|
4929 { |
|
4930 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) |
|
4931 return NO; |
|
4932 #else |
|
4933 return automaticTextReplacementEnabled; |
|
4934 #endif |
|
4935 } |
|
4936 |
|
4937 - (BOOL)isAutomaticSpellingCorrectionEnabled |
|
4938 { |
|
4939 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) |
|
4940 return NO; |
|
4941 #else |
|
4942 return automaticSpellingCorrectionEnabled; |
|
4943 #endif |
|
4944 } |
|
4945 |
|
4946 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) |
|
4947 |
|
4948 - (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag |
|
4949 { |
|
4950 if (automaticQuoteSubstitutionEnabled == flag) |
|
4951 return; |
|
4952 automaticQuoteSubstitutionEnabled = flag; |
|
4953 [[NSUserDefaults standardUserDefaults] setBool:automaticQuoteSubstitutionEnabled forKey:WebAutomaticQuoteSubstitutionEnabled]; |
|
4954 [[NSSpellChecker sharedSpellChecker] updatePanels]; |
|
4955 } |
|
4956 |
|
4957 - (void)toggleAutomaticQuoteSubstitution:(id)sender |
|
4958 { |
|
4959 [self setAutomaticQuoteSubstitutionEnabled:![self isAutomaticQuoteSubstitutionEnabled]]; |
|
4960 } |
|
4961 |
|
4962 - (void)setAutomaticLinkDetectionEnabled:(BOOL)flag |
|
4963 { |
|
4964 if (automaticLinkDetectionEnabled == flag) |
|
4965 return; |
|
4966 automaticLinkDetectionEnabled = flag; |
|
4967 [[NSUserDefaults standardUserDefaults] setBool:automaticLinkDetectionEnabled forKey:WebAutomaticLinkDetectionEnabled]; |
|
4968 [[NSSpellChecker sharedSpellChecker] updatePanels]; |
|
4969 } |
|
4970 |
|
4971 - (void)toggleAutomaticLinkDetection:(id)sender |
|
4972 { |
|
4973 [self setAutomaticLinkDetectionEnabled:![self isAutomaticLinkDetectionEnabled]]; |
|
4974 } |
|
4975 |
|
4976 - (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag |
|
4977 { |
|
4978 if (automaticDashSubstitutionEnabled == flag) |
|
4979 return; |
|
4980 automaticDashSubstitutionEnabled = flag; |
|
4981 [[NSUserDefaults standardUserDefaults] setBool:automaticDashSubstitutionEnabled forKey:WebAutomaticDashSubstitutionEnabled]; |
|
4982 [[NSSpellChecker sharedSpellChecker] updatePanels]; |
|
4983 } |
|
4984 |
|
4985 - (void)toggleAutomaticDashSubstitution:(id)sender |
|
4986 { |
|
4987 [self setAutomaticDashSubstitutionEnabled:![self isAutomaticDashSubstitutionEnabled]]; |
|
4988 } |
|
4989 |
|
4990 - (void)setAutomaticTextReplacementEnabled:(BOOL)flag |
|
4991 { |
|
4992 if (automaticTextReplacementEnabled == flag) |
|
4993 return; |
|
4994 automaticTextReplacementEnabled = flag; |
|
4995 [[NSUserDefaults standardUserDefaults] setBool:automaticTextReplacementEnabled forKey:WebAutomaticTextReplacementEnabled]; |
|
4996 [[NSSpellChecker sharedSpellChecker] updatePanels]; |
|
4997 } |
|
4998 |
|
4999 - (void)toggleAutomaticTextReplacement:(id)sender |
|
5000 { |
|
5001 [self setAutomaticTextReplacementEnabled:![self isAutomaticTextReplacementEnabled]]; |
|
5002 } |
|
5003 |
|
5004 - (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag |
|
5005 { |
|
5006 if (automaticSpellingCorrectionEnabled == flag) |
|
5007 return; |
|
5008 automaticSpellingCorrectionEnabled = flag; |
|
5009 [[NSUserDefaults standardUserDefaults] setBool:automaticSpellingCorrectionEnabled forKey:WebAutomaticSpellingCorrectionEnabled]; |
|
5010 [[NSSpellChecker sharedSpellChecker] updatePanels]; |
|
5011 } |
|
5012 |
|
5013 - (void)toggleAutomaticSpellingCorrection:(id)sender |
|
5014 { |
|
5015 [self setAutomaticSpellingCorrectionEnabled:![self isAutomaticSpellingCorrectionEnabled]]; |
|
5016 } |
|
5017 |
|
5018 #endif |
|
5019 |
|
5020 @end |
|
5021 |
|
5022 @implementation WebView (WebViewUndoableEditing) |
|
5023 |
|
5024 - (void)replaceSelectionWithNode:(DOMNode *)node |
|
5025 { |
|
5026 [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:NO]; |
|
5027 } |
|
5028 |
|
5029 - (void)replaceSelectionWithText:(NSString *)text |
|
5030 { |
|
5031 [[self _selectedOrMainFrame] _replaceSelectionWithText:text selectReplacement:YES smartReplace:NO]; |
|
5032 } |
|
5033 |
|
5034 - (void)replaceSelectionWithMarkupString:(NSString *)markupString |
|
5035 { |
|
5036 [[self _selectedOrMainFrame] _replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO]; |
|
5037 } |
|
5038 |
|
5039 - (void)replaceSelectionWithArchive:(WebArchive *)archive |
|
5040 { |
|
5041 [[[self _selectedOrMainFrame] _dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES]; |
|
5042 } |
|
5043 |
|
5044 - (void)deleteSelection |
|
5045 { |
|
5046 WebFrame *webFrame = [self _selectedOrMainFrame]; |
|
5047 Frame* coreFrame = core(webFrame); |
|
5048 if (coreFrame) |
|
5049 coreFrame->editor()->deleteSelectionWithSmartDelete([(WebHTMLView *)[[webFrame frameView] documentView] _canSmartCopyOrDelete]); |
|
5050 } |
|
5051 |
|
5052 - (void)applyStyle:(DOMCSSStyleDeclaration *)style |
|
5053 { |
|
5054 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to |
|
5055 // change the API to allow this. |
|
5056 WebFrame *webFrame = [self _selectedOrMainFrame]; |
|
5057 Frame* coreFrame = core(webFrame); |
|
5058 if (coreFrame) |
|
5059 coreFrame->editor()->applyStyle(core(style)); |
|
5060 } |
|
5061 |
|
5062 @end |
|
5063 |
|
5064 @implementation WebView (WebViewEditingActions) |
|
5065 |
|
5066 - (void)_performResponderOperation:(SEL)selector with:(id)parameter |
|
5067 { |
|
5068 static BOOL reentered = NO; |
|
5069 if (reentered) { |
|
5070 [[self nextResponder] tryToPerform:selector with:parameter]; |
|
5071 return; |
|
5072 } |
|
5073 |
|
5074 // There are two possibilities here. |
|
5075 // |
|
5076 // One is that WebView has been called in its role as part of the responder chain. |
|
5077 // In that case, it's fine to call the first responder and end up calling down the |
|
5078 // responder chain again. Later we will return here with reentered = YES and continue |
|
5079 // past the WebView. |
|
5080 // |
|
5081 // The other is that we are being called directly, in which case we want to pass the |
|
5082 // selector down to the view inside us that can handle it, and continue down the |
|
5083 // responder chain as usual. |
|
5084 |
|
5085 // Pass this selector down to the first responder. |
|
5086 NSResponder *responder = [self _responderForResponderOperations]; |
|
5087 reentered = YES; |
|
5088 [responder tryToPerform:selector with:parameter]; |
|
5089 reentered = NO; |
|
5090 } |
|
5091 |
|
5092 #define FORWARD(name) \ |
|
5093 - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; } |
|
5094 |
|
5095 FOR_EACH_RESPONDER_SELECTOR(FORWARD) |
|
5096 |
|
5097 - (void)insertText:(NSString *)text |
|
5098 { |
|
5099 [self _performResponderOperation:_cmd with:text]; |
|
5100 } |
|
5101 |
|
5102 @end |
|
5103 |
|
5104 @implementation WebView (WebViewEditingInMail) |
|
5105 |
|
5106 - (void)_insertNewlineInQuotedContent |
|
5107 { |
|
5108 [[self _selectedOrMainFrame] _insertParagraphSeparatorInQuotedContent]; |
|
5109 } |
|
5110 |
|
5111 - (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle |
|
5112 { |
|
5113 [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle]; |
|
5114 } |
|
5115 |
|
5116 - (BOOL)_selectionIsCaret |
|
5117 { |
|
5118 Frame* coreFrame = core([self _selectedOrMainFrame]); |
|
5119 if (!coreFrame) |
|
5120 return NO; |
|
5121 return coreFrame->selection()->isCaret(); |
|
5122 } |
|
5123 |
|
5124 - (BOOL)_selectionIsAll |
|
5125 { |
|
5126 Frame* coreFrame = core([self _selectedOrMainFrame]); |
|
5127 if (!coreFrame) |
|
5128 return NO; |
|
5129 return coreFrame->selection()->isAll(MayLeaveEditableContent); |
|
5130 } |
|
5131 |
|
5132 @end |
|
5133 |
|
5134 static WebFrameView *containingFrameView(NSView *view) |
|
5135 { |
|
5136 while (view && ![view isKindOfClass:[WebFrameView class]]) |
|
5137 view = [view superview]; |
|
5138 return (WebFrameView *)view; |
|
5139 } |
|
5140 |
|
5141 @implementation WebView (WebFileInternal) |
|
5142 |
|
5143 + (void)_setCacheModel:(WebCacheModel)cacheModel |
|
5144 { |
|
5145 if (s_didSetCacheModel && cacheModel == s_cacheModel) |
|
5146 return; |
|
5147 |
|
5148 NSString *nsurlCacheDirectory = (NSString *)WebCFAutorelease(WKCopyFoundationCacheDirectory()); |
|
5149 if (!nsurlCacheDirectory) |
|
5150 nsurlCacheDirectory = NSHomeDirectory(); |
|
5151 |
|
5152 // As a fudge factor, use 1000 instead of 1024, in case the reported byte |
|
5153 // count doesn't align exactly to a megabyte boundary. |
|
5154 uint64_t memSize = WebMemorySize() / 1024 / 1000; |
|
5155 unsigned long long diskFreeSize = WebVolumeFreeSize(nsurlCacheDirectory) / 1024 / 1000; |
|
5156 NSURLCache *nsurlCache = [NSURLCache sharedURLCache]; |
|
5157 |
|
5158 unsigned cacheTotalCapacity = 0; |
|
5159 unsigned cacheMinDeadCapacity = 0; |
|
5160 unsigned cacheMaxDeadCapacity = 0; |
|
5161 double deadDecodedDataDeletionInterval = 0; |
|
5162 |
|
5163 unsigned pageCacheCapacity = 0; |
|
5164 |
|
5165 NSUInteger nsurlCacheMemoryCapacity = 0; |
|
5166 NSUInteger nsurlCacheDiskCapacity = 0; |
|
5167 |
|
5168 switch (cacheModel) { |
|
5169 case WebCacheModelDocumentViewer: { |
|
5170 // Page cache capacity (in pages) |
|
5171 pageCacheCapacity = 0; |
|
5172 |
|
5173 // Object cache capacities (in bytes) |
|
5174 if (memSize >= 2048) |
|
5175 cacheTotalCapacity = 96 * 1024 * 1024; |
|
5176 else if (memSize >= 1536) |
|
5177 cacheTotalCapacity = 64 * 1024 * 1024; |
|
5178 else if (memSize >= 1024) |
|
5179 cacheTotalCapacity = 32 * 1024 * 1024; |
|
5180 else if (memSize >= 512) |
|
5181 cacheTotalCapacity = 16 * 1024 * 1024; |
|
5182 |
|
5183 cacheMinDeadCapacity = 0; |
|
5184 cacheMaxDeadCapacity = 0; |
|
5185 |
|
5186 // Foundation memory cache capacity (in bytes) |
|
5187 nsurlCacheMemoryCapacity = 0; |
|
5188 |
|
5189 // Foundation disk cache capacity (in bytes) |
|
5190 nsurlCacheDiskCapacity = [nsurlCache diskCapacity]; |
|
5191 |
|
5192 break; |
|
5193 } |
|
5194 case WebCacheModelDocumentBrowser: { |
|
5195 // Page cache capacity (in pages) |
|
5196 if (memSize >= 1024) |
|
5197 pageCacheCapacity = 3; |
|
5198 else if (memSize >= 512) |
|
5199 pageCacheCapacity = 2; |
|
5200 else if (memSize >= 256) |
|
5201 pageCacheCapacity = 1; |
|
5202 else |
|
5203 pageCacheCapacity = 0; |
|
5204 |
|
5205 // Object cache capacities (in bytes) |
|
5206 if (memSize >= 2048) |
|
5207 cacheTotalCapacity = 96 * 1024 * 1024; |
|
5208 else if (memSize >= 1536) |
|
5209 cacheTotalCapacity = 64 * 1024 * 1024; |
|
5210 else if (memSize >= 1024) |
|
5211 cacheTotalCapacity = 32 * 1024 * 1024; |
|
5212 else if (memSize >= 512) |
|
5213 cacheTotalCapacity = 16 * 1024 * 1024; |
|
5214 |
|
5215 cacheMinDeadCapacity = cacheTotalCapacity / 8; |
|
5216 cacheMaxDeadCapacity = cacheTotalCapacity / 4; |
|
5217 |
|
5218 // Foundation memory cache capacity (in bytes) |
|
5219 if (memSize >= 2048) |
|
5220 nsurlCacheMemoryCapacity = 4 * 1024 * 1024; |
|
5221 else if (memSize >= 1024) |
|
5222 nsurlCacheMemoryCapacity = 2 * 1024 * 1024; |
|
5223 else if (memSize >= 512) |
|
5224 nsurlCacheMemoryCapacity = 1 * 1024 * 1024; |
|
5225 else |
|
5226 nsurlCacheMemoryCapacity = 512 * 1024; |
|
5227 |
|
5228 // Foundation disk cache capacity (in bytes) |
|
5229 if (diskFreeSize >= 16384) |
|
5230 nsurlCacheDiskCapacity = 50 * 1024 * 1024; |
|
5231 else if (diskFreeSize >= 8192) |
|
5232 nsurlCacheDiskCapacity = 40 * 1024 * 1024; |
|
5233 else if (diskFreeSize >= 4096) |
|
5234 nsurlCacheDiskCapacity = 30 * 1024 * 1024; |
|
5235 else |
|
5236 nsurlCacheDiskCapacity = 20 * 1024 * 1024; |
|
5237 |
|
5238 break; |
|
5239 } |
|
5240 case WebCacheModelPrimaryWebBrowser: { |
|
5241 // Page cache capacity (in pages) |
|
5242 // (Research indicates that value / page drops substantially after 3 pages.) |
|
5243 if (memSize >= 2048) |
|
5244 pageCacheCapacity = 5; |
|
5245 else if (memSize >= 1024) |
|
5246 pageCacheCapacity = 4; |
|
5247 else if (memSize >= 512) |
|
5248 pageCacheCapacity = 3; |
|
5249 else if (memSize >= 256) |
|
5250 pageCacheCapacity = 2; |
|
5251 else |
|
5252 pageCacheCapacity = 1; |
|
5253 |
|
5254 // Object cache capacities (in bytes) |
|
5255 // (Testing indicates that value / MB depends heavily on content and |
|
5256 // browsing pattern. Even growth above 128MB can have substantial |
|
5257 // value / MB for some content / browsing patterns.) |
|
5258 if (memSize >= 2048) |
|
5259 cacheTotalCapacity = 128 * 1024 * 1024; |
|
5260 else if (memSize >= 1536) |
|
5261 cacheTotalCapacity = 96 * 1024 * 1024; |
|
5262 else if (memSize >= 1024) |
|
5263 cacheTotalCapacity = 64 * 1024 * 1024; |
|
5264 else if (memSize >= 512) |
|
5265 cacheTotalCapacity = 32 * 1024 * 1024; |
|
5266 |
|
5267 cacheMinDeadCapacity = cacheTotalCapacity / 4; |
|
5268 cacheMaxDeadCapacity = cacheTotalCapacity / 2; |
|
5269 |
|
5270 // This code is here to avoid a PLT regression. We can remove it if we |
|
5271 // can prove that the overall system gain would justify the regression. |
|
5272 cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity); |
|
5273 |
|
5274 deadDecodedDataDeletionInterval = 60; |
|
5275 |
|
5276 // Foundation memory cache capacity (in bytes) |
|
5277 // (These values are small because WebCore does most caching itself.) |
|
5278 if (memSize >= 1024) |
|
5279 nsurlCacheMemoryCapacity = 4 * 1024 * 1024; |
|
5280 else if (memSize >= 512) |
|
5281 nsurlCacheMemoryCapacity = 2 * 1024 * 1024; |
|
5282 else if (memSize >= 256) |
|
5283 nsurlCacheMemoryCapacity = 1 * 1024 * 1024; |
|
5284 else |
|
5285 nsurlCacheMemoryCapacity = 512 * 1024; |
|
5286 |
|
5287 // Foundation disk cache capacity (in bytes) |
|
5288 if (diskFreeSize >= 16384) |
|
5289 nsurlCacheDiskCapacity = 175 * 1024 * 1024; |
|
5290 else if (diskFreeSize >= 8192) |
|
5291 nsurlCacheDiskCapacity = 150 * 1024 * 1024; |
|
5292 else if (diskFreeSize >= 4096) |
|
5293 nsurlCacheDiskCapacity = 125 * 1024 * 1024; |
|
5294 else if (diskFreeSize >= 2048) |
|
5295 nsurlCacheDiskCapacity = 100 * 1024 * 1024; |
|
5296 else if (diskFreeSize >= 1024) |
|
5297 nsurlCacheDiskCapacity = 75 * 1024 * 1024; |
|
5298 else |
|
5299 nsurlCacheDiskCapacity = 50 * 1024 * 1024; |
|
5300 |
|
5301 break; |
|
5302 } |
|
5303 default: |
|
5304 ASSERT_NOT_REACHED(); |
|
5305 }; |
|
5306 |
|
5307 #ifdef BUILDING_ON_TIGER |
|
5308 // Don't use a big Foundation disk cache on Tiger because, according to the |
|
5309 // PLT, the Foundation disk cache on Tiger is slower than the network. |
|
5310 nsurlCacheDiskCapacity = [nsurlCache diskCapacity]; |
|
5311 #endif |
|
5312 |
|
5313 // Don't shrink a big disk cache, since that would cause churn. |
|
5314 nsurlCacheDiskCapacity = max(nsurlCacheDiskCapacity, [nsurlCache diskCapacity]); |
|
5315 |
|
5316 cache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity); |
|
5317 cache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval); |
|
5318 pageCache()->setCapacity(pageCacheCapacity); |
|
5319 [nsurlCache setMemoryCapacity:nsurlCacheMemoryCapacity]; |
|
5320 [nsurlCache setDiskCapacity:nsurlCacheDiskCapacity]; |
|
5321 |
|
5322 s_cacheModel = cacheModel; |
|
5323 s_didSetCacheModel = YES; |
|
5324 } |
|
5325 |
|
5326 + (WebCacheModel)_cacheModel |
|
5327 { |
|
5328 return s_cacheModel; |
|
5329 } |
|
5330 |
|
5331 + (WebCacheModel)_didSetCacheModel |
|
5332 { |
|
5333 return s_didSetCacheModel; |
|
5334 } |
|
5335 |
|
5336 + (WebCacheModel)_maxCacheModelInAnyInstance |
|
5337 { |
|
5338 WebCacheModel cacheModel = WebCacheModelDocumentViewer; |
|
5339 NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator]; |
|
5340 while (WebPreferences *preferences = [[enumerator nextObject] preferences]) |
|
5341 cacheModel = max(cacheModel, [preferences cacheModel]); |
|
5342 return cacheModel; |
|
5343 } |
|
5344 |
|
5345 + (void)_preferencesChangedNotification:(NSNotification *)notification |
|
5346 { |
|
5347 WebPreferences *preferences = (WebPreferences *)[notification object]; |
|
5348 ASSERT([preferences isKindOfClass:[WebPreferences class]]); |
|
5349 |
|
5350 WebCacheModel cacheModel = [preferences cacheModel]; |
|
5351 if (![self _didSetCacheModel] || cacheModel > [self _cacheModel]) |
|
5352 [self _setCacheModel:cacheModel]; |
|
5353 else if (cacheModel < [self _cacheModel]) |
|
5354 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])]; |
|
5355 } |
|
5356 |
|
5357 + (void)_preferencesRemovedNotification:(NSNotification *)notification |
|
5358 { |
|
5359 WebPreferences *preferences = (WebPreferences *)[notification object]; |
|
5360 ASSERT([preferences isKindOfClass:[WebPreferences class]]); |
|
5361 |
|
5362 if ([preferences cacheModel] == [self _cacheModel]) |
|
5363 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])]; |
|
5364 } |
|
5365 |
|
5366 - (WebFrame *)_focusedFrame |
|
5367 { |
|
5368 NSResponder *resp = [[self window] firstResponder]; |
|
5369 if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:[[self mainFrame] frameView]]) { |
|
5370 WebFrameView *frameView = containingFrameView((NSView *)resp); |
|
5371 ASSERT(frameView != nil); |
|
5372 return [frameView webFrame]; |
|
5373 } |
|
5374 |
|
5375 return nil; |
|
5376 } |
|
5377 |
|
5378 - (BOOL)_isLoading |
|
5379 { |
|
5380 WebFrame *mainFrame = [self mainFrame]; |
|
5381 return [[mainFrame _dataSource] isLoading] |
|
5382 || [[mainFrame provisionalDataSource] isLoading]; |
|
5383 } |
|
5384 |
|
5385 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point |
|
5386 { |
|
5387 if (_private->closed) |
|
5388 return nil; |
|
5389 ASSERT(_private->usesDocumentViews); |
|
5390 NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]]; |
|
5391 if (![view isDescendantOf:[[self mainFrame] frameView]]) |
|
5392 return nil; |
|
5393 WebFrameView *frameView = containingFrameView(view); |
|
5394 ASSERT(frameView); |
|
5395 return frameView; |
|
5396 } |
|
5397 |
|
5398 + (void)_preflightSpellCheckerNow:(id)sender |
|
5399 { |
|
5400 [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer]; |
|
5401 } |
|
5402 |
|
5403 + (void)_preflightSpellChecker |
|
5404 { |
|
5405 // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch. |
|
5406 if ([NSSpellChecker sharedSpellCheckerExists]) { |
|
5407 [self _preflightSpellCheckerNow:self]; |
|
5408 } else { |
|
5409 [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0]; |
|
5410 } |
|
5411 } |
|
5412 |
|
5413 - (BOOL)_continuousCheckingAllowed |
|
5414 { |
|
5415 static BOOL allowContinuousSpellChecking = YES; |
|
5416 static BOOL readAllowContinuousSpellCheckingDefault = NO; |
|
5417 if (!readAllowContinuousSpellCheckingDefault) { |
|
5418 if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) { |
|
5419 allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"]; |
|
5420 } |
|
5421 readAllowContinuousSpellCheckingDefault = YES; |
|
5422 } |
|
5423 return allowContinuousSpellChecking; |
|
5424 } |
|
5425 |
|
5426 - (NSResponder *)_responderForResponderOperations |
|
5427 { |
|
5428 NSResponder *responder = [[self window] firstResponder]; |
|
5429 WebFrameView *mainFrameView = [[self mainFrame] frameView]; |
|
5430 |
|
5431 // If the current responder is outside of the webview, use our main frameView or its |
|
5432 // document view. We also do this for subviews of self that are siblings of the main |
|
5433 // frameView since clients might insert non-webview-related views there (see 4552713). |
|
5434 if (responder != self && ![mainFrameView _web_firstResponderIsSelfOrDescendantView]) { |
|
5435 responder = [mainFrameView documentView]; |
|
5436 if (!responder) |
|
5437 responder = mainFrameView; |
|
5438 } |
|
5439 return responder; |
|
5440 } |
|
5441 |
|
5442 - (void)_openFrameInNewWindowFromMenu:(NSMenuItem *)sender |
|
5443 { |
|
5444 ASSERT_ARG(sender, [sender isKindOfClass:[NSMenuItem class]]); |
|
5445 |
|
5446 NSDictionary *element = [sender representedObject]; |
|
5447 ASSERT([element isKindOfClass:[NSDictionary class]]); |
|
5448 |
|
5449 WebDataSource *dataSource = [(WebFrame *)[element objectForKey:WebElementFrameKey] dataSource]; |
|
5450 NSURLRequest *request = [[dataSource request] copy]; |
|
5451 ASSERT(request); |
|
5452 |
|
5453 [self _openNewWindowWithRequest:request]; |
|
5454 [request release]; |
|
5455 } |
|
5456 |
|
5457 - (void)_searchWithGoogleFromMenu:(id)sender |
|
5458 { |
|
5459 id documentView = [[[self selectedFrame] frameView] documentView]; |
|
5460 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) { |
|
5461 return; |
|
5462 } |
|
5463 |
|
5464 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString]; |
|
5465 if ([selectedString length] == 0) { |
|
5466 return; |
|
5467 } |
|
5468 |
|
5469 NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName]; |
|
5470 [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; |
|
5471 NSMutableString *s = [selectedString mutableCopy]; |
|
5472 const unichar nonBreakingSpaceCharacter = 0xA0; |
|
5473 NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1]; |
|
5474 [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])]; |
|
5475 [pasteboard setString:s forType:NSStringPboardType]; |
|
5476 [s release]; |
|
5477 |
|
5478 // FIXME: seems fragile to use the service by name, but this is what AppKit does |
|
5479 NSPerformService(@"Search With Google", pasteboard); |
|
5480 } |
|
5481 |
|
5482 - (void)_searchWithSpotlightFromMenu:(id)sender |
|
5483 { |
|
5484 id documentView = [[[self selectedFrame] frameView] documentView]; |
|
5485 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) |
|
5486 return; |
|
5487 |
|
5488 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString]; |
|
5489 if (![selectedString length]) |
|
5490 return; |
|
5491 |
|
5492 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) |
|
5493 [[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:selectedString]; |
|
5494 #else |
|
5495 (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions); |
|
5496 #endif |
|
5497 } |
|
5498 |
|
5499 #if USE(ACCELERATED_COMPOSITING) |
|
5500 - (void)_clearLayerSyncLoopObserver |
|
5501 { |
|
5502 if (!_private->layerSyncRunLoopObserver) |
|
5503 return; |
|
5504 |
|
5505 CFRunLoopObserverInvalidate(_private->layerSyncRunLoopObserver); |
|
5506 CFRelease(_private->layerSyncRunLoopObserver); |
|
5507 _private->layerSyncRunLoopObserver = 0; |
|
5508 } |
|
5509 #endif |
|
5510 |
|
5511 #if ENABLE(VIDEO) && USE(GSTREAMER) |
|
5512 - (void)_clearGlibLoopObserver |
|
5513 { |
|
5514 if (!_private->glibRunLoopObserver) |
|
5515 return; |
|
5516 |
|
5517 CFRunLoopObserverInvalidate(_private->glibRunLoopObserver); |
|
5518 CFRelease(_private->glibRunLoopObserver); |
|
5519 _private->glibRunLoopObserver = 0; |
|
5520 } |
|
5521 #endif |
|
5522 @end |
|
5523 |
|
5524 @implementation WebView (WebViewInternal) |
|
5525 |
|
5526 + (BOOL)shouldIncludeInWebKitStatistics |
|
5527 { |
|
5528 return NO; |
|
5529 } |
|
5530 |
|
5531 - (BOOL)_becomingFirstResponderFromOutside |
|
5532 { |
|
5533 return _private->becomingFirstResponderFromOutside; |
|
5534 } |
|
5535 |
|
5536 #if ENABLE(ICONDATABASE) |
|
5537 - (void)_receivedIconChangedNotification:(NSNotification *)notification |
|
5538 { |
|
5539 // Get the URL for this notification |
|
5540 NSDictionary *userInfo = [notification userInfo]; |
|
5541 ASSERT([userInfo isKindOfClass:[NSDictionary class]]); |
|
5542 NSString *urlString = [userInfo objectForKey:WebIconNotificationUserInfoURLKey]; |
|
5543 ASSERT([urlString isKindOfClass:[NSString class]]); |
|
5544 |
|
5545 // If that URL matches the current main frame, dispatch the delegate call, which will also unregister |
|
5546 // us for this notification |
|
5547 if ([[self mainFrameURL] isEqualTo:urlString]) |
|
5548 [self _dispatchDidReceiveIconFromWebFrame:[self mainFrame]]; |
|
5549 } |
|
5550 |
|
5551 - (void)_registerForIconNotification:(BOOL)listen |
|
5552 { |
|
5553 if (listen) |
|
5554 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_receivedIconChangedNotification:) name:WebIconDatabaseDidAddIconNotification object:nil]; |
|
5555 else |
|
5556 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebIconDatabaseDidAddIconNotification object:nil]; |
|
5557 } |
|
5558 |
|
5559 - (void)_dispatchDidReceiveIconFromWebFrame:(WebFrame *)webFrame |
|
5560 { |
|
5561 // FIXME: This willChangeValueForKey call is too late, because the icon has already changed by now. |
|
5562 [self _willChangeValueForKey:_WebMainFrameIconKey]; |
|
5563 |
|
5564 // Since we definitely have an icon and are about to send out the delegate call for that, this WebView doesn't need to listen for the general |
|
5565 // notification any longer |
|
5566 [self _registerForIconNotification:NO]; |
|
5567 |
|
5568 WebFrameLoadDelegateImplementationCache* cache = &_private->frameLoadDelegateImplementations; |
|
5569 if (cache->didReceiveIconForFrameFunc) { |
|
5570 Image* image = iconDatabase()->iconForPageURL(core(webFrame)->loader()->url().string(), IntSize(16, 16)); |
|
5571 if (NSImage *icon = webGetNSImage(image, NSMakeSize(16, 16))) |
|
5572 CallFrameLoadDelegate(cache->didReceiveIconForFrameFunc, self, @selector(webView:didReceiveIcon:forFrame:), icon, webFrame); |
|
5573 } |
|
5574 |
|
5575 [self _didChangeValueForKey:_WebMainFrameIconKey]; |
|
5576 } |
|
5577 #endif // ENABLE(ICONDATABASE) |
|
5578 |
|
5579 - (void)_addObject:(id)object forIdentifier:(unsigned long)identifier |
|
5580 { |
|
5581 ASSERT(!_private->identifierMap.contains(identifier)); |
|
5582 |
|
5583 // If the identifier map is initially empty it means we're starting a load |
|
5584 // of something. The semantic is that the web view should be around as long |
|
5585 // as something is loading. Because of that we retain the web view. |
|
5586 if (_private->identifierMap.isEmpty()) |
|
5587 CFRetain(self); |
|
5588 |
|
5589 _private->identifierMap.set(identifier, object); |
|
5590 } |
|
5591 |
|
5592 - (id)_objectForIdentifier:(unsigned long)identifier |
|
5593 { |
|
5594 return _private->identifierMap.get(identifier).get(); |
|
5595 } |
|
5596 |
|
5597 - (void)_removeObjectForIdentifier:(unsigned long)identifier |
|
5598 { |
|
5599 ASSERT(_private->identifierMap.contains(identifier)); |
|
5600 _private->identifierMap.remove(identifier); |
|
5601 |
|
5602 // If the identifier map is now empty it means we're no longer loading anything |
|
5603 // and we should release the web view. |
|
5604 if (_private->identifierMap.isEmpty()) |
|
5605 CFRelease(self); |
|
5606 } |
|
5607 |
|
5608 - (void)_retrieveKeyboardUIModeFromPreferences:(NSNotification *)notification |
|
5609 { |
|
5610 CFPreferencesAppSynchronize(UniversalAccessDomain); |
|
5611 |
|
5612 Boolean keyExistsAndHasValidFormat; |
|
5613 int mode = CFPreferencesGetAppIntegerValue(AppleKeyboardUIMode, UniversalAccessDomain, &keyExistsAndHasValidFormat); |
|
5614 |
|
5615 // The keyboard access mode is reported by two bits: |
|
5616 // Bit 0 is set if feature is on |
|
5617 // Bit 1 is set if full keyboard access works for any control, not just text boxes and lists |
|
5618 // We require both bits to be on. |
|
5619 // I do not know that we would ever get one bit on and the other off since |
|
5620 // checking the checkbox in system preferences which is marked as "Turn on full keyboard access" |
|
5621 // turns on both bits. |
|
5622 _private->_keyboardUIMode = (mode & 0x2) ? KeyboardAccessFull : KeyboardAccessDefault; |
|
5623 |
|
5624 // check for tabbing to links |
|
5625 if ([_private->preferences tabsToLinks]) |
|
5626 _private->_keyboardUIMode = (KeyboardUIMode)(_private->_keyboardUIMode | KeyboardAccessTabsToLinks); |
|
5627 } |
|
5628 |
|
5629 - (KeyboardUIMode)_keyboardUIMode |
|
5630 { |
|
5631 if (!_private->_keyboardUIModeAccessed) { |
|
5632 _private->_keyboardUIModeAccessed = YES; |
|
5633 |
|
5634 [self _retrieveKeyboardUIModeFromPreferences:nil]; |
|
5635 |
|
5636 [[NSDistributedNotificationCenter defaultCenter] |
|
5637 addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) |
|
5638 name:KeyboardUIModeDidChangeNotification object:nil]; |
|
5639 |
|
5640 [[NSNotificationCenter defaultCenter] |
|
5641 addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) |
|
5642 name:WebPreferencesChangedNotification object:nil]; |
|
5643 } |
|
5644 return _private->_keyboardUIMode; |
|
5645 } |
|
5646 |
|
5647 - (void)_setInsertionPasteboard:(NSPasteboard *)pasteboard |
|
5648 { |
|
5649 _private->insertionPasteboard = pasteboard; |
|
5650 } |
|
5651 |
|
5652 - (void)_selectionChanged |
|
5653 { |
|
5654 if (_private->usesDocumentViews) { |
|
5655 id documentView = [[[self _selectedOrMainFrame] frameView] documentView]; |
|
5656 if ([documentView isKindOfClass:[WebHTMLView class]]) |
|
5657 [documentView _selectionChanged]; |
|
5658 return; |
|
5659 } |
|
5660 |
|
5661 // FIXME (Viewless): We'll need code here. |
|
5662 } |
|
5663 |
|
5664 - (Frame*)_mainCoreFrame |
|
5665 { |
|
5666 return (_private && _private->page) ? _private->page->mainFrame() : 0; |
|
5667 } |
|
5668 |
|
5669 - (WebFrame *)_selectedOrMainFrame |
|
5670 { |
|
5671 WebFrame *result = [self selectedFrame]; |
|
5672 if (result == nil) |
|
5673 result = [self mainFrame]; |
|
5674 return result; |
|
5675 } |
|
5676 |
|
5677 #if USE(ACCELERATED_COMPOSITING) |
|
5678 |
|
5679 - (BOOL)_needsOneShotDrawingSynchronization |
|
5680 { |
|
5681 return _private->needsOneShotDrawingSynchronization; |
|
5682 } |
|
5683 |
|
5684 - (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization |
|
5685 { |
|
5686 _private->needsOneShotDrawingSynchronization = needsSynchronization; |
|
5687 } |
|
5688 |
|
5689 - (BOOL)_syncCompositingChanges |
|
5690 { |
|
5691 Frame* frame = [self _mainCoreFrame]; |
|
5692 if (frame && frame->view()) |
|
5693 return frame->view()->syncCompositingStateRecursive(); |
|
5694 |
|
5695 return YES; |
|
5696 } |
|
5697 |
|
5698 /* |
|
5699 The order of events with compositing updates is this: |
|
5700 |
|
5701 Start of runloop End of runloop |
|
5702 | | |
|
5703 --|-------------------------------------------------------|-- |
|
5704 ^ ^ ^ |
|
5705 | | | |
|
5706 NSWindow update, | CA commit |
|
5707 NSView drawing | |
|
5708 flush | |
|
5709 layerSyncRunLoopObserverCallBack |
|
5710 |
|
5711 To avoid flashing, we have to ensure that compositing changes (rendered via |
|
5712 the CoreAnimation rendering display link) appear on screen at the same time |
|
5713 as content painted into the window via the normal WebCore rendering path. |
|
5714 |
|
5715 CoreAnimation will commit any layer changes at the end of the runloop via |
|
5716 its "CA commit" observer. Those changes can then appear onscreen at any time |
|
5717 when the display link fires, which can result in unsynchronized rendering. |
|
5718 |
|
5719 To fix this, the GraphicsLayerCA code in WebCore does not change the CA |
|
5720 layer tree during style changes and layout; it stores up all changes and |
|
5721 commits them via syncCompositingState(). There are then two situations in |
|
5722 which we can call syncCompositingState(): |
|
5723 |
|
5724 1. When painting. FrameView::paintContents() makes a call to syncCompositingState(). |
|
5725 |
|
5726 2. When style changes/layout have made changes to the layer tree which do not |
|
5727 result in painting. In this case we need a run loop observer to do a |
|
5728 syncCompositingState() at an appropriate time. The observer will keep firing |
|
5729 until the time is right (essentially when there are no more pending layouts). |
|
5730 |
|
5731 */ |
|
5732 |
|
5733 static void layerSyncRunLoopObserverCallBack(CFRunLoopObserverRef, CFRunLoopActivity, void* info) |
|
5734 { |
|
5735 WebView *webView = reinterpret_cast<WebView*>(info); |
|
5736 NSWindow *window = [webView window]; |
|
5737 |
|
5738 // An NSWindow may not display in the next runloop cycle after dirtying due to delayed window display logic, |
|
5739 // in which case this observer can fire first. So if the window is due for a display, don't commit |
|
5740 // layer changes, otherwise they'll show on screen before the view drawing. |
|
5741 bool viewsNeedDisplay; |
|
5742 #ifndef __LP64__ |
|
5743 if (window && [window _wrapsCarbonWindow]) |
|
5744 viewsNeedDisplay = HIViewGetNeedsDisplay(HIViewGetRoot(static_cast<WindowRef>([window windowRef]))); |
|
5745 else |
|
5746 #endif |
|
5747 viewsNeedDisplay = [window viewsNeedDisplay]; |
|
5748 |
|
5749 if (viewsNeedDisplay) |
|
5750 return; |
|
5751 |
|
5752 if ([webView _syncCompositingChanges]) { |
|
5753 [webView _clearLayerSyncLoopObserver]; |
|
5754 // AppKit may have disabled screen updates, thinking an upcoming window flush will re-enable them. |
|
5755 // In case setNeedsDisplayInRect() has prevented the window from needing to be flushed, re-enable screen |
|
5756 // updates here. |
|
5757 if (![window isFlushWindowDisabled]) |
|
5758 [window _enableScreenUpdatesIfNeeded]; |
|
5759 } else { |
|
5760 // Since the WebView does not need display, -viewWillDraw will not be called. Perform pending layout now, |
|
5761 // so that the layers draw with up-to-date layout. |
|
5762 [webView _viewWillDrawInternal]; |
|
5763 } |
|
5764 } |
|
5765 |
|
5766 - (void)_scheduleCompositingLayerSync |
|
5767 { |
|
5768 if (_private->layerSyncRunLoopObserver) |
|
5769 return; |
|
5770 |
|
5771 // Run after AppKit does its window update. If we do any painting, we'll commit |
|
5772 // layer changes from FrameView::paintContents(), otherwise we'll commit via |
|
5773 // _syncCompositingChanges when this observer fires. |
|
5774 const CFIndex runLoopOrder = NSDisplayWindowRunLoopOrdering + 1; |
|
5775 |
|
5776 // The WebView always outlives the observer, so no need to retain/release. |
|
5777 CFRunLoopObserverContext context = { 0, self, 0, 0, 0 }; |
|
5778 |
|
5779 _private->layerSyncRunLoopObserver = CFRunLoopObserverCreate(NULL, |
|
5780 kCFRunLoopBeforeWaiting | kCFRunLoopExit, true /* repeats */, |
|
5781 runLoopOrder, layerSyncRunLoopObserverCallBack, &context); |
|
5782 |
|
5783 CFRunLoopAddObserver(CFRunLoopGetCurrent(), _private->layerSyncRunLoopObserver, kCFRunLoopCommonModes); |
|
5784 } |
|
5785 |
|
5786 #endif |
|
5787 |
|
5788 #if ENABLE(VIDEO) |
|
5789 |
|
5790 - (void)_enterFullscreenForNode:(WebCore::Node*)node |
|
5791 { |
|
5792 ASSERT(node->hasTagName(WebCore::HTMLNames::videoTag)); |
|
5793 HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node); |
|
5794 |
|
5795 if (_private->fullscreenController) { |
|
5796 if ([_private->fullscreenController mediaElement] == videoElement) { |
|
5797 // The backend may just warn us that the underlaying plaftormMovie() |
|
5798 // has changed. Just force an update. |
|
5799 [_private->fullscreenController setMediaElement:videoElement]; |
|
5800 return; // No more to do. |
|
5801 } |
|
5802 |
|
5803 // First exit Fullscreen for the old mediaElement. |
|
5804 [_private->fullscreenController mediaElement]->exitFullscreen(); |
|
5805 // This previous call has to trigger _exitFullscreen, |
|
5806 // which has to clear _private->fullscreenController. |
|
5807 ASSERT(!_private->fullscreenController); |
|
5808 } |
|
5809 if (!_private->fullscreenController) { |
|
5810 _private->fullscreenController = [[WebVideoFullscreenController alloc] init]; |
|
5811 [_private->fullscreenController setMediaElement:videoElement]; |
|
5812 [_private->fullscreenController enterFullscreen:[[self window] screen]]; |
|
5813 } |
|
5814 else |
|
5815 [_private->fullscreenController setMediaElement:videoElement]; |
|
5816 } |
|
5817 |
|
5818 - (void)_exitFullscreen |
|
5819 { |
|
5820 if (!_private->fullscreenController) |
|
5821 return; |
|
5822 [_private->fullscreenController exitFullscreen]; |
|
5823 [_private->fullscreenController release]; |
|
5824 _private->fullscreenController = nil; |
|
5825 } |
|
5826 |
|
5827 #endif |
|
5828 |
|
5829 #if ENABLE(VIDEO) && USE(GSTREAMER) |
|
5830 |
|
5831 static void glibContextIterationCallback(CFRunLoopObserverRef, CFRunLoopActivity, void*) |
|
5832 { |
|
5833 g_main_context_iteration(0, FALSE); |
|
5834 } |
|
5835 |
|
5836 - (void)_scheduleGlibContextIterations |
|
5837 { |
|
5838 if (_private->glibRunLoopObserver) |
|
5839 return; |
|
5840 |
|
5841 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; |
|
5842 |
|
5843 // Create a run loop observer and attach it to the run loop. |
|
5844 CFRunLoopObserverContext context = {0, self, 0, 0, 0}; |
|
5845 _private->glibRunLoopObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, YES, 0, &glibContextIterationCallback, &context); |
|
5846 |
|
5847 if (_private->glibRunLoopObserver) { |
|
5848 CFRunLoopRef cfLoop = [myRunLoop getCFRunLoop]; |
|
5849 CFRunLoopAddObserver(cfLoop, _private->glibRunLoopObserver, kCFRunLoopDefaultMode); |
|
5850 } |
|
5851 |
|
5852 } |
|
5853 #endif |
|
5854 |
|
5855 |
|
5856 @end |
|
5857 |
|
5858 @implementation WebView (WebViewGeolocation) |
|
5859 |
|
5860 - (void)_setGeolocationProvider:(id<WebGeolocationProvider>)geolocationProvider |
|
5861 { |
|
5862 if (_private) |
|
5863 _private->_geolocationProvider = geolocationProvider; |
|
5864 } |
|
5865 |
|
5866 - (id<WebGeolocationProvider>)_geolocationProvider |
|
5867 { |
|
5868 if (_private) |
|
5869 return _private->_geolocationProvider; |
|
5870 return nil; |
|
5871 } |
|
5872 |
|
5873 - (void)_geolocationDidChangePosition:(WebGeolocationPosition *)position |
|
5874 { |
|
5875 #if ENABLE(CLIENT_BASED_GEOLOCATION) |
|
5876 if (_private && _private->page) |
|
5877 _private->page->geolocationController()->positionChanged(core(position)); |
|
5878 #endif |
|
5879 } |
|
5880 |
|
5881 - (void)_geolocationDidFailWithError:(NSError *)error |
|
5882 { |
|
5883 #if ENABLE(CLIENT_BASED_GEOLOCATION) |
|
5884 if (_private && _private->page) { |
|
5885 RefPtr<GeolocationError> geolocatioError = GeolocationError::create(GeolocationError::PositionUnavailable, [error localizedDescription]); |
|
5886 _private->page->geolocationController()->errorOccurred(geolocatioError.get()); |
|
5887 } |
|
5888 #endif |
|
5889 } |
|
5890 |
|
5891 @end |
|
5892 |
|
5893 @implementation WebView (WebViewPrivateStyleInfo) |
|
5894 |
|
5895 - (JSValueRef)_computedStyleIncludingVisitedInfo:(JSContextRef)context forElement:(JSValueRef)value |
|
5896 { |
|
5897 JSLock lock(SilenceAssertionsOnly); |
|
5898 ExecState* exec = toJS(context); |
|
5899 if (!value) |
|
5900 return JSValueMakeUndefined(context); |
|
5901 JSValue jsValue = toJS(exec, value); |
|
5902 if (!jsValue.inherits(&JSElement::s_info)) |
|
5903 return JSValueMakeUndefined(context); |
|
5904 JSElement* jsElement = static_cast<JSElement*>(asObject(jsValue)); |
|
5905 Element* element = jsElement->impl(); |
|
5906 RefPtr<CSSComputedStyleDeclaration> style = computedStyle(element, true); |
|
5907 return toRef(exec, toJS(exec, jsElement->globalObject(), style.get())); |
|
5908 } |
|
5909 |
|
5910 @end |
|
5911 |
|
5912 #ifdef BUILDING_ON_LEOPARD |
|
5913 |
|
5914 static IMP originalRecursivelyRemoveMailAttributesImp; |
|
5915 |
|
5916 static id objectElementDataAttribute(DOMHTMLObjectElement *self, SEL) |
|
5917 { |
|
5918 return [self getAttribute:@"data"]; |
|
5919 } |
|
5920 |
|
5921 static void recursivelyRemoveMailAttributes(DOMNode *self, SEL selector, BOOL a, BOOL b, BOOL c) |
|
5922 { |
|
5923 // While inside this Mail function, change the behavior of -[DOMHTMLObjectElement data] back to what it used to be |
|
5924 // before we fixed a bug in it (see http://trac.webkit.org/changeset/30044 for that change). |
|
5925 |
|
5926 // It's a little bit strange to patch a method defined by WebKit, but it helps keep this workaround self-contained. |
|
5927 |
|
5928 Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("DOMHTMLObjectElement"), @selector(data)); |
|
5929 IMP originalDataImp = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(objectElementDataAttribute)); |
|
5930 originalRecursivelyRemoveMailAttributesImp(self, selector, a, b, c); |
|
5931 method_setImplementation(methodToPatch, originalDataImp); |
|
5932 } |
|
5933 |
|
5934 #endif |
|
5935 |
|
5936 static void patchMailRemoveAttributesMethod() |
|
5937 { |
|
5938 #ifdef BUILDING_ON_LEOPARD |
|
5939 if (!WKAppVersionCheckLessThan(@"com.apple.mail", -1, 4.0)) |
|
5940 return; |
|
5941 Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("DOMNode"), @selector(recursivelyRemoveMailAttributes:convertObjectsToImages:convertEditableElements:)); |
|
5942 if (!methodToPatch) |
|
5943 return; |
|
5944 originalRecursivelyRemoveMailAttributesImp = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(recursivelyRemoveMailAttributes)); |
|
5945 #endif |
|
5946 } |