WebKit/mac/WebView/WebDataSource.mm
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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