|
1 /* |
|
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
|
3 * |
|
4 * Redistribution and use in source and binary forms, with or without |
|
5 * modification, are permitted provided that the following conditions |
|
6 * are met: |
|
7 * |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
|
14 * its contributors may be used to endorse or promote products derived |
|
15 * from this software without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
|
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
|
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #import "WebDataSource.h" |
|
30 |
|
31 #import "WebArchive.h" |
|
32 #import "WebArchiveInternal.h" |
|
33 #import "WebDataSourceInternal.h" |
|
34 #import "WebDocument.h" |
|
35 #import "WebDocumentLoaderMac.h" |
|
36 #import "WebFrameInternal.h" |
|
37 #import "WebFrameLoadDelegate.h" |
|
38 #import "WebFrameLoaderClient.h" |
|
39 #import "WebHTMLRepresentation.h" |
|
40 #import "WebKitErrorsPrivate.h" |
|
41 #import "WebKitLogging.h" |
|
42 #import "WebKitStatisticsPrivate.h" |
|
43 #import "WebKitNSStringExtras.h" |
|
44 #import "WebNSURLExtras.h" |
|
45 #import "WebNSURLRequestExtras.h" |
|
46 #import "WebPDFRepresentation.h" |
|
47 #import "WebResourceInternal.h" |
|
48 #import "WebResourceLoadDelegate.h" |
|
49 #import "WebViewInternal.h" |
|
50 #import <WebCore/ApplicationCacheStorage.h> |
|
51 #import <WebCore/FrameLoader.h> |
|
52 #import <WebCore/KURL.h> |
|
53 #import <WebCore/LegacyWebArchive.h> |
|
54 #import <WebCore/MIMETypeRegistry.h> |
|
55 #import <WebCore/ResourceRequest.h> |
|
56 #import <WebCore/SharedBuffer.h> |
|
57 #import <WebCore/WebCoreObjCExtras.h> |
|
58 #import <WebCore/WebCoreURLResponse.h> |
|
59 #import <WebKit/DOMHTML.h> |
|
60 #import <WebKit/DOMPrivate.h> |
|
61 #import <runtime/InitializeThreading.h> |
|
62 #import <wtf/Assertions.h> |
|
63 #import <wtf/Threading.h> |
|
64 |
|
65 using namespace WebCore; |
|
66 |
|
67 @interface WebDataSourcePrivate : NSObject { |
|
68 @public |
|
69 WebDocumentLoaderMac* loader; |
|
70 |
|
71 id <WebDocumentRepresentation> representation; |
|
72 |
|
73 BOOL representationFinishedLoading; |
|
74 BOOL includedInWebKitStatistics; |
|
75 } |
|
76 @end |
|
77 |
|
78 @implementation WebDataSourcePrivate |
|
79 |
|
80 + (void)initialize |
|
81 { |
|
82 JSC::initializeThreading(); |
|
83 WTF::initializeMainThreadToProcessMainThread(); |
|
84 #ifndef BUILDING_ON_TIGER |
|
85 WebCoreObjCFinalizeOnMainThread(self); |
|
86 #endif |
|
87 } |
|
88 |
|
89 - (void)dealloc |
|
90 { |
|
91 if (WebCoreObjCScheduleDeallocateOnMainThread([WebDataSourcePrivate class], self)) |
|
92 return; |
|
93 |
|
94 ASSERT(loader); |
|
95 if (loader) { |
|
96 ASSERT(!loader->isLoading()); |
|
97 loader->detachDataSource(); |
|
98 loader->deref(); |
|
99 } |
|
100 |
|
101 [representation release]; |
|
102 |
|
103 [super dealloc]; |
|
104 } |
|
105 |
|
106 - (void)finalize |
|
107 { |
|
108 ASSERT_MAIN_THREAD(); |
|
109 |
|
110 ASSERT(loader); |
|
111 if (loader) { |
|
112 ASSERT(!loader->isLoading()); |
|
113 loader->detachDataSource(); |
|
114 loader->deref(); |
|
115 } |
|
116 |
|
117 [super finalize]; |
|
118 } |
|
119 |
|
120 @end |
|
121 |
|
122 @interface WebDataSource (WebFileInternal) |
|
123 @end |
|
124 |
|
125 @implementation WebDataSource (WebFileInternal) |
|
126 |
|
127 - (void)_setRepresentation:(id<WebDocumentRepresentation>)representation |
|
128 { |
|
129 [_private->representation release]; |
|
130 _private->representation = [representation retain]; |
|
131 _private->representationFinishedLoading = NO; |
|
132 } |
|
133 |
|
134 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCClass, NSArray *supportTypes) |
|
135 { |
|
136 NSEnumerator *enumerator = [supportTypes objectEnumerator]; |
|
137 ASSERT(enumerator != nil); |
|
138 NSString *mime = nil; |
|
139 while ((mime = [enumerator nextObject]) != nil) { |
|
140 // Don't clobber previously-registered classes. |
|
141 if ([allTypes objectForKey:mime] == nil) |
|
142 [allTypes setObject:objCClass forKey:mime]; |
|
143 } |
|
144 } |
|
145 |
|
146 + (Class)_representationClassForMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins |
|
147 { |
|
148 Class repClass; |
|
149 return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType allowingPlugins:allowPlugins] ? repClass : nil; |
|
150 } |
|
151 @end |
|
152 |
|
153 @implementation WebDataSource (WebPrivate) |
|
154 |
|
155 - (NSError *)_mainDocumentError |
|
156 { |
|
157 return _private->loader->mainDocumentError(); |
|
158 } |
|
159 |
|
160 - (void)_addSubframeArchives:(NSArray *)subframeArchives |
|
161 { |
|
162 // FIXME: This SPI is poor, poor design. Can we come up with another solution for those who need it? |
|
163 DocumentLoader* loader = [self _documentLoader]; |
|
164 ASSERT(loader); |
|
165 |
|
166 NSEnumerator *enumerator = [subframeArchives objectEnumerator]; |
|
167 WebArchive *archive; |
|
168 while ((archive = [enumerator nextObject]) != nil) |
|
169 loader->addAllArchiveResources([archive _coreLegacyWebArchive]); |
|
170 } |
|
171 |
|
172 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL |
|
173 { |
|
174 if ([URL isFileURL]) { |
|
175 NSString *path = [[URL path] stringByResolvingSymlinksInPath]; |
|
176 return [[[NSFileWrapper alloc] initWithPath:path] autorelease]; |
|
177 } |
|
178 |
|
179 WebResource *resource = [self subresourceForURL:URL]; |
|
180 if (resource) |
|
181 return [resource _fileWrapperRepresentation]; |
|
182 |
|
183 NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL]; |
|
184 if (cachedResponse) { |
|
185 NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease]; |
|
186 [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]]; |
|
187 return wrapper; |
|
188 } |
|
189 |
|
190 return nil; |
|
191 } |
|
192 |
|
193 - (NSString *)_responseMIMEType |
|
194 { |
|
195 return [[self response] MIMEType]; |
|
196 } |
|
197 |
|
198 - (BOOL)_transferApplicationCache:(NSString*)destinationBundleIdentifier |
|
199 { |
|
200 #if ENABLE(OFFLINE_WEB_APPLICATIONS) |
|
201 DocumentLoader* loader = [self _documentLoader]; |
|
202 |
|
203 if (!loader) |
|
204 return NO; |
|
205 |
|
206 NSString *cacheDir = [NSString _webkit_localCacheDirectoryWithBundleIdentifier:destinationBundleIdentifier]; |
|
207 |
|
208 return ApplicationCacheStorage::storeCopyOfCache(cacheDir, loader->applicationCacheHost()); |
|
209 #else |
|
210 return NO; |
|
211 #endif |
|
212 } |
|
213 |
|
214 - (void)_setDeferMainResourceDataLoad:(BOOL)flag |
|
215 { |
|
216 DocumentLoader* loader = [self _documentLoader]; |
|
217 |
|
218 if (!loader) |
|
219 return; |
|
220 |
|
221 loader->setDeferMainResourceDataLoad(flag); |
|
222 } |
|
223 |
|
224 @end |
|
225 |
|
226 @implementation WebDataSource (WebInternal) |
|
227 |
|
228 - (void)_finishedLoading |
|
229 { |
|
230 _private->representationFinishedLoading = YES; |
|
231 [[self representation] finishedLoadingWithDataSource:self]; |
|
232 } |
|
233 |
|
234 - (void)_receivedData:(NSData *)data |
|
235 { |
|
236 // protect self temporarily, as the bridge receivedData call could remove our last ref |
|
237 RetainPtr<WebDataSource*> protect(self); |
|
238 |
|
239 [[self representation] receivedData:data withDataSource:self]; |
|
240 |
|
241 if ([[self _webView] _usesDocumentViews]) |
|
242 [[[[self webFrame] frameView] documentView] dataSourceUpdated:self]; |
|
243 } |
|
244 |
|
245 - (void)_setMainDocumentError:(NSError *)error |
|
246 { |
|
247 if (!_private->representationFinishedLoading) { |
|
248 _private->representationFinishedLoading = YES; |
|
249 [[self representation] receivedError:error withDataSource:self]; |
|
250 } |
|
251 } |
|
252 |
|
253 - (void)_revertToProvisionalState |
|
254 { |
|
255 [self _setRepresentation:nil]; |
|
256 } |
|
257 |
|
258 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission |
|
259 { |
|
260 static NSMutableDictionary *repTypes = nil; |
|
261 static BOOL addedImageTypes = NO; |
|
262 |
|
263 if (!repTypes) { |
|
264 repTypes = [[NSMutableDictionary alloc] init]; |
|
265 addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]); |
|
266 |
|
267 // Since this is a "secret default" we don't both registering it. |
|
268 BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"]; |
|
269 if (!omitPDFSupport) |
|
270 addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]); |
|
271 } |
|
272 |
|
273 if (!addedImageTypes && !allowImageTypeOmission) { |
|
274 addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]); |
|
275 addedImageTypes = YES; |
|
276 } |
|
277 |
|
278 return repTypes; |
|
279 } |
|
280 |
|
281 - (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement |
|
282 { |
|
283 DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive]; |
|
284 if (fragment) |
|
285 [[self webFrame] _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO]; |
|
286 } |
|
287 |
|
288 // FIXME: There are few reasons why this method and many of its related methods can't be pushed entirely into WebCore in the future. |
|
289 - (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive |
|
290 { |
|
291 ASSERT(archive); |
|
292 WebResource *mainResource = [archive mainResource]; |
|
293 if (mainResource) { |
|
294 NSString *MIMEType = [mainResource MIMEType]; |
|
295 if ([WebView canShowMIMETypeAsHTML:MIMEType]) { |
|
296 NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding]; |
|
297 // FIXME: seems poor form to do this as a side effect of getting a document fragment |
|
298 if (DocumentLoader* loader = [self _documentLoader]) |
|
299 loader->addAllArchiveResources([archive _coreLegacyWebArchive]); |
|
300 |
|
301 DOMDocumentFragment *fragment = [[self webFrame] _documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]]; |
|
302 [markupString release]; |
|
303 return fragment; |
|
304 } else if (MIMETypeRegistry::isSupportedImageMIMEType(MIMEType)) { |
|
305 return [self _documentFragmentWithImageResource:mainResource]; |
|
306 |
|
307 } |
|
308 } |
|
309 return nil; |
|
310 } |
|
311 |
|
312 - (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource |
|
313 { |
|
314 DOMElement *imageElement = [self _imageElementWithImageResource:resource]; |
|
315 if (!imageElement) |
|
316 return 0; |
|
317 DOMDocumentFragment *fragment = [[[self webFrame] DOMDocument] createDocumentFragment]; |
|
318 [fragment appendChild:imageElement]; |
|
319 return fragment; |
|
320 } |
|
321 |
|
322 - (DOMElement *)_imageElementWithImageResource:(WebResource *)resource |
|
323 { |
|
324 if (!resource) |
|
325 return 0; |
|
326 |
|
327 [self addSubresource:resource]; |
|
328 |
|
329 DOMElement *imageElement = [[[self webFrame] DOMDocument] createElement:@"img"]; |
|
330 |
|
331 // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this. |
|
332 NSURL *URL = [resource URL]; |
|
333 [imageElement setAttribute:@"src" value:[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]]; |
|
334 |
|
335 return imageElement; |
|
336 } |
|
337 |
|
338 // May return nil if not initialized with a URL. |
|
339 - (NSURL *)_URL |
|
340 { |
|
341 const KURL& url = _private->loader->url(); |
|
342 if (url.isEmpty()) |
|
343 return nil; |
|
344 return url; |
|
345 } |
|
346 |
|
347 - (WebView *)_webView |
|
348 { |
|
349 return [[self webFrame] webView]; |
|
350 } |
|
351 |
|
352 - (BOOL)_isDocumentHTML |
|
353 { |
|
354 NSString *MIMEType = [self _responseMIMEType]; |
|
355 return [WebView canShowMIMETypeAsHTML:MIMEType]; |
|
356 } |
|
357 |
|
358 - (void)_makeRepresentation |
|
359 { |
|
360 Class repClass = [[self class] _representationClassForMIMEType:[self _responseMIMEType] allowingPlugins:[[[self _webView] preferences] arePlugInsEnabled]]; |
|
361 |
|
362 // Check if the data source was already bound? |
|
363 if (![[self representation] isKindOfClass:repClass]) { |
|
364 id newRep = repClass != nil ? [[repClass alloc] init] : nil; |
|
365 [self _setRepresentation:(id <WebDocumentRepresentation>)newRep]; |
|
366 [newRep release]; |
|
367 } |
|
368 |
|
369 [_private->representation setDataSource:self]; |
|
370 } |
|
371 |
|
372 - (DocumentLoader*)_documentLoader |
|
373 { |
|
374 return _private->loader; |
|
375 } |
|
376 |
|
377 - (id)_initWithDocumentLoader:(PassRefPtr<WebDocumentLoaderMac>)loader |
|
378 { |
|
379 self = [super init]; |
|
380 if (!self) |
|
381 return nil; |
|
382 |
|
383 _private = [[WebDataSourcePrivate alloc] init]; |
|
384 |
|
385 _private->loader = loader.releaseRef(); |
|
386 |
|
387 LOG(Loading, "creating datasource for %@", static_cast<NSURL *>(_private->loader->request().url())); |
|
388 |
|
389 if ((_private->includedInWebKitStatistics = [[self webFrame] _isIncludedInWebKitStatistics])) |
|
390 ++WebDataSourceCount; |
|
391 |
|
392 return self; |
|
393 } |
|
394 |
|
395 @end |
|
396 |
|
397 @implementation WebDataSource |
|
398 |
|
399 - (id)initWithRequest:(NSURLRequest *)request |
|
400 { |
|
401 return [self _initWithDocumentLoader:WebDocumentLoaderMac::create(request, SubstituteData())]; |
|
402 } |
|
403 |
|
404 - (void)dealloc |
|
405 { |
|
406 if (_private && _private->includedInWebKitStatistics) |
|
407 --WebDataSourceCount; |
|
408 |
|
409 [_private release]; |
|
410 |
|
411 [super dealloc]; |
|
412 } |
|
413 |
|
414 - (void)finalize |
|
415 { |
|
416 if (_private && _private->includedInWebKitStatistics) |
|
417 --WebDataSourceCount; |
|
418 |
|
419 [super finalize]; |
|
420 } |
|
421 |
|
422 - (NSData *)data |
|
423 { |
|
424 RefPtr<SharedBuffer> mainResourceData = _private->loader->mainResourceData(); |
|
425 if (!mainResourceData) |
|
426 return nil; |
|
427 return [mainResourceData->createNSData() autorelease]; |
|
428 } |
|
429 |
|
430 - (id <WebDocumentRepresentation>)representation |
|
431 { |
|
432 return _private->representation; |
|
433 } |
|
434 |
|
435 - (WebFrame *)webFrame |
|
436 { |
|
437 FrameLoader* frameLoader = _private->loader->frameLoader(); |
|
438 if (!frameLoader) |
|
439 return nil; |
|
440 return static_cast<WebFrameLoaderClient*>(frameLoader->client())->webFrame(); |
|
441 } |
|
442 |
|
443 - (NSURLRequest *)initialRequest |
|
444 { |
|
445 return _private->loader->originalRequest().nsURLRequest(); |
|
446 } |
|
447 |
|
448 - (NSMutableURLRequest *)request |
|
449 { |
|
450 FrameLoader* frameLoader = _private->loader->frameLoader(); |
|
451 if (!frameLoader || !frameLoader->frameHasLoaded()) |
|
452 return nil; |
|
453 |
|
454 // FIXME: this cast is dubious |
|
455 return (NSMutableURLRequest *)_private->loader->request().nsURLRequest(); |
|
456 } |
|
457 |
|
458 - (NSURLResponse *)response |
|
459 { |
|
460 return _private->loader->response().nsURLResponse(); |
|
461 } |
|
462 |
|
463 - (NSString *)textEncodingName |
|
464 { |
|
465 NSString *textEncodingName = _private->loader->overrideEncoding(); |
|
466 if (!textEncodingName) |
|
467 textEncodingName = [[self response] textEncodingName]; |
|
468 return textEncodingName; |
|
469 } |
|
470 |
|
471 - (BOOL)isLoading |
|
472 { |
|
473 return _private->loader->isLoadingInAPISense(); |
|
474 } |
|
475 |
|
476 // Returns nil or the page title. |
|
477 - (NSString *)pageTitle |
|
478 { |
|
479 return [[self representation] title]; |
|
480 } |
|
481 |
|
482 - (NSURL *)unreachableURL |
|
483 { |
|
484 const KURL& unreachableURL = _private->loader->unreachableURL(); |
|
485 if (unreachableURL.isEmpty()) |
|
486 return nil; |
|
487 return unreachableURL; |
|
488 } |
|
489 |
|
490 - (WebArchive *)webArchive |
|
491 { |
|
492 // it makes no sense to grab a WebArchive from an uncommitted document. |
|
493 if (!_private->loader->isCommitted()) |
|
494 return nil; |
|
495 |
|
496 return [[[WebArchive alloc] _initWithCoreLegacyWebArchive:LegacyWebArchive::create(core([self webFrame]))] autorelease]; |
|
497 } |
|
498 |
|
499 - (WebResource *)mainResource |
|
500 { |
|
501 RefPtr<ArchiveResource> coreResource = _private->loader->mainResource(); |
|
502 return [[[WebResource alloc] _initWithCoreResource:coreResource.release()] autorelease]; |
|
503 } |
|
504 |
|
505 - (NSArray *)subresources |
|
506 { |
|
507 Vector<PassRefPtr<ArchiveResource> > coreSubresources; |
|
508 _private->loader->getSubresources(coreSubresources); |
|
509 |
|
510 NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:coreSubresources.size()]; |
|
511 for (unsigned i = 0; i < coreSubresources.size(); ++i) { |
|
512 WebResource *resource = [[WebResource alloc] _initWithCoreResource:coreSubresources[i]]; |
|
513 if (resource) { |
|
514 [subresources addObject:resource]; |
|
515 [resource release]; |
|
516 } |
|
517 } |
|
518 |
|
519 return [subresources autorelease]; |
|
520 } |
|
521 |
|
522 - (WebResource *)subresourceForURL:(NSURL *)URL |
|
523 { |
|
524 RefPtr<ArchiveResource> subresource = _private->loader->subresource(URL); |
|
525 |
|
526 return subresource ? [[[WebResource alloc] _initWithCoreResource:subresource.get()] autorelease] : nil; |
|
527 } |
|
528 |
|
529 - (void)addSubresource:(WebResource *)subresource |
|
530 { |
|
531 _private->loader->addArchiveResource([subresource _coreResource]); |
|
532 } |
|
533 |
|
534 @end |