webengine/osswebengine/WebKit/WebView/WebDataSource.mm
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005, 2006, 2007 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 "WebArchiver.h"
       
    33 #import "WebDataSourceInternal.h"
       
    34 #import "WebDocument.h"
       
    35 #import "WebDocumentLoaderMac.h"
       
    36 #import "WebFrameBridge.h"
       
    37 #import "WebFrameInternal.h"
       
    38 #import "WebFrameLoadDelegate.h"
       
    39 #import "WebFrameLoaderClient.h"
       
    40 #import "WebHTMLRepresentation.h"
       
    41 #import "WebKitErrorsPrivate.h"
       
    42 #import "WebKitLogging.h"
       
    43 #import "WebKitStatisticsPrivate.h"
       
    44 #import "WebNSURLExtras.h"
       
    45 #import "WebNSURLRequestExtras.h"
       
    46 #import "WebPDFRepresentation.h"
       
    47 #import "WebResourceLoadDelegate.h"
       
    48 #import "WebResourcePrivate.h"
       
    49 #import "WebUnarchivingState.h"
       
    50 #import "WebViewInternal.h"
       
    51 #import <JavaScriptCore/Assertions.h>
       
    52 #import <WebCore/FrameLoader.h>
       
    53 #import <WebCore/KURL.h>
       
    54 #import <WebCore/MIMETypeRegistry.h>
       
    55 #import <WebCore/ResourceRequest.h>
       
    56 #import <WebCore/SharedBuffer.h>
       
    57 #import <WebCore/WebCoreObjCExtras.h>
       
    58 #import <WebKit/DOMHTML.h>
       
    59 #import <WebKit/DOMPrivate.h>
       
    60 #import <WebKitSystemInterface.h>
       
    61 
       
    62 using namespace WebCore;
       
    63 
       
    64 @interface WebDataSourcePrivate : NSObject {
       
    65 @public
       
    66     WebDocumentLoaderMac* loader;
       
    67    
       
    68     id <WebDocumentRepresentation> representation;
       
    69     
       
    70     WebUnarchivingState *unarchivingState;
       
    71     BOOL representationFinishedLoading;
       
    72 }
       
    73 @end
       
    74 
       
    75 @implementation WebDataSourcePrivate 
       
    76 
       
    77 #ifndef BUILDING_ON_TIGER
       
    78 + (void)initialize
       
    79 {
       
    80     WebCoreObjCFinalizeOnMainThread(self);
       
    81 }
       
    82 #endif
       
    83 
       
    84 - (void)dealloc
       
    85 {
       
    86     ASSERT(!loader->isLoading());
       
    87     loader->detachDataSource();
       
    88     loader->deref();
       
    89     
       
    90     [representation release];
       
    91     [unarchivingState release];
       
    92 
       
    93     [super dealloc];
       
    94 }
       
    95 
       
    96 - (void)finalize
       
    97 {
       
    98     ASSERT_MAIN_THREAD();
       
    99 
       
   100     ASSERT(!loader->isLoading());
       
   101     loader->detachDataSource();
       
   102     loader->deref();
       
   103 
       
   104     [super finalize];
       
   105 }
       
   106 
       
   107 @end
       
   108 
       
   109 @interface WebDataSource (WebFileInternal)
       
   110 @end
       
   111 
       
   112 @implementation WebDataSource (WebFileInternal)
       
   113 
       
   114 - (void)_setRepresentation:(id<WebDocumentRepresentation>)representation
       
   115 {
       
   116     [_private->representation release];
       
   117     _private->representation = [representation retain];
       
   118     _private->representationFinishedLoading = NO;
       
   119 }
       
   120 
       
   121 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCClass, NSArray *supportTypes)
       
   122 {
       
   123     NSEnumerator *enumerator = [supportTypes objectEnumerator];
       
   124     ASSERT(enumerator != nil);
       
   125     NSString *mime = nil;
       
   126     while ((mime = [enumerator nextObject]) != nil) {
       
   127         // Don't clobber previously-registered classes.
       
   128         if ([allTypes objectForKey:mime] == nil)
       
   129             [allTypes setObject:objCClass forKey:mime];
       
   130     }
       
   131 }
       
   132 
       
   133 + (Class)_representationClassForMIMEType:(NSString *)MIMEType
       
   134 {
       
   135     Class repClass;
       
   136     return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil;
       
   137 }
       
   138 
       
   139 @end
       
   140 
       
   141 @implementation WebDataSource (WebPrivate)
       
   142 
       
   143 - (NSError *)_mainDocumentError
       
   144 {
       
   145     return _private->loader->mainDocumentError();
       
   146 }
       
   147 
       
   148 - (void)_addSubframeArchives:(NSArray *)subframeArchives
       
   149 {
       
   150     NSEnumerator *enumerator = [subframeArchives objectEnumerator];
       
   151     WebArchive *archive;
       
   152     while ((archive = [enumerator nextObject]) != nil)
       
   153         [self _addToUnarchiveState:archive];
       
   154 }
       
   155 
       
   156 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
       
   157 {
       
   158     if ([URL isFileURL]) {
       
   159         NSString *path = [[URL path] stringByResolvingSymlinksInPath];
       
   160         return [[[NSFileWrapper alloc] initWithPath:path] autorelease];
       
   161     }
       
   162     
       
   163     WebResource *resource = [self subresourceForURL:URL];
       
   164     if (resource)
       
   165         return [resource _fileWrapperRepresentation];
       
   166     
       
   167     NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL];
       
   168     if (cachedResponse) {
       
   169         NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
       
   170         [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
       
   171         return wrapper;
       
   172     }
       
   173     
       
   174     return nil;
       
   175 }
       
   176 
       
   177 @end
       
   178 
       
   179 @implementation WebDataSource (WebInternal)
       
   180 
       
   181 - (void)_finishedLoading
       
   182 {
       
   183     _private->representationFinishedLoading = YES;
       
   184     [[self representation] finishedLoadingWithDataSource:self];
       
   185 }
       
   186 
       
   187 - (void)_receivedData:(NSData *)data
       
   188 {
       
   189     // protect self temporarily, as the bridge receivedData call could remove our last ref
       
   190     RetainPtr<WebDataSource*> protect(self);
       
   191     
       
   192     [[self representation] receivedData:data withDataSource:self];
       
   193     [[[[self webFrame] frameView] documentView] dataSourceUpdated:self];
       
   194 }
       
   195 
       
   196 - (void)_setMainDocumentError:(NSError *)error
       
   197 {
       
   198     if (!_private->representationFinishedLoading) {
       
   199         _private->representationFinishedLoading = YES;
       
   200         [[self representation] receivedError:error withDataSource:self];
       
   201     }
       
   202 }
       
   203 
       
   204 - (void)_clearUnarchivingState
       
   205 {
       
   206     [_private->unarchivingState release];
       
   207     _private->unarchivingState = nil;
       
   208 }
       
   209 
       
   210 - (void)_revertToProvisionalState
       
   211 {
       
   212     [self _setRepresentation:nil];
       
   213 }
       
   214 
       
   215 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
       
   216 {
       
   217     static NSMutableDictionary *repTypes = nil;
       
   218     static BOOL addedImageTypes = NO;
       
   219     
       
   220     if (!repTypes) {
       
   221         repTypes = [[NSMutableDictionary alloc] init];
       
   222         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]);
       
   223         
       
   224         // Since this is a "secret default" we don't both registering it.
       
   225         BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
       
   226         if (!omitPDFSupport)
       
   227             addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]);
       
   228     }
       
   229     
       
   230     if (!addedImageTypes && !allowImageTypeOmission) {
       
   231         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]);
       
   232         addedImageTypes = YES;
       
   233     }
       
   234     
       
   235     return repTypes;
       
   236 }
       
   237 
       
   238 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
       
   239 {
       
   240     return [_private->unarchivingState archivedResourceForURL:URL];
       
   241 }
       
   242 
       
   243 - (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement
       
   244 {
       
   245     DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive];
       
   246     if (fragment)
       
   247         [[self _bridge] replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO];
       
   248 }
       
   249 
       
   250 - (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive
       
   251 {
       
   252     ASSERT(archive);
       
   253     WebResource *mainResource = [archive mainResource];
       
   254     if (mainResource) {
       
   255         NSString *MIMEType = [mainResource MIMEType];
       
   256         if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
       
   257             NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
       
   258             // FIXME: seems poor form to do this as a side effect of getting a document fragment
       
   259             [self _addToUnarchiveState:archive];
       
   260             DOMDocumentFragment *fragment = [[self _bridge] documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]];
       
   261             [markupString release];
       
   262             return fragment;
       
   263         } else if (MIMETypeRegistry::isSupportedImageMIMEType(MIMEType)) {
       
   264             return [self _documentFragmentWithImageResource:mainResource];
       
   265             
       
   266         }
       
   267     }
       
   268     return nil;
       
   269 }
       
   270 
       
   271 - (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource
       
   272 {
       
   273     DOMElement *imageElement = [self _imageElementWithImageResource:resource];
       
   274     if (!imageElement)
       
   275         return 0;
       
   276     DOMDocumentFragment *fragment = [[[self webFrame] DOMDocument] createDocumentFragment];
       
   277     [fragment appendChild:imageElement];
       
   278     return fragment;
       
   279 }
       
   280 
       
   281 - (DOMElement *)_imageElementWithImageResource:(WebResource *)resource
       
   282 {
       
   283     if (!resource)
       
   284         return 0;
       
   285     
       
   286     [self addSubresource:resource];
       
   287     
       
   288     DOMElement *imageElement = [[[self webFrame] DOMDocument] createElement:@"img"];
       
   289     
       
   290     // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this.
       
   291     NSURL *URL = [resource URL];
       
   292     [imageElement setAttribute:@"src" value:[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]];
       
   293     
       
   294     return imageElement;
       
   295 }
       
   296 
       
   297 // May return nil if not initialized with a URL.
       
   298 - (NSURL *)_URL
       
   299 {
       
   300     KURL URL = _private->loader->URL();
       
   301     return URL.isEmpty() ? nil : URL.getNSURL();
       
   302 }
       
   303 
       
   304 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
       
   305 {
       
   306     return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
       
   307 }
       
   308 
       
   309 - (WebFrameBridge *)_bridge
       
   310 {
       
   311     ASSERT(_private->loader->isCommitted());
       
   312     return [[self webFrame] _bridge];
       
   313 }
       
   314 
       
   315 - (WebView *)_webView
       
   316 {
       
   317     return [[self webFrame] webView];
       
   318 }
       
   319 
       
   320 - (BOOL)_isDocumentHTML
       
   321 {
       
   322     NSString *MIMEType = [[self response] MIMEType];
       
   323     return [WebView canShowMIMETypeAsHTML:MIMEType];
       
   324 }
       
   325 
       
   326 -(void)_makeRepresentation
       
   327 {
       
   328     Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
       
   329     
       
   330     // Check if the data source was already bound?
       
   331     if (![[self representation] isKindOfClass:repClass]) {
       
   332         id newRep = repClass != nil ? [[repClass alloc] init] : nil;
       
   333         [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
       
   334         [newRep release];
       
   335     }
       
   336     
       
   337     [_private->representation setDataSource:self];
       
   338 }
       
   339 
       
   340 - (void)_addToUnarchiveState:(WebArchive *)archive
       
   341 {
       
   342     if (!_private->unarchivingState)
       
   343         _private->unarchivingState = [[WebUnarchivingState alloc] init];
       
   344     [_private->unarchivingState addArchive:archive];
       
   345 }
       
   346 
       
   347 - (DocumentLoader*)_documentLoader
       
   348 {
       
   349     return _private->loader;
       
   350 }
       
   351 
       
   352 - (id)_initWithDocumentLoader:(WebDocumentLoaderMac *)loader
       
   353 {
       
   354     self = [super init];
       
   355     if (!self)
       
   356         return nil;
       
   357     
       
   358     _private = [[WebDataSourcePrivate alloc] init];
       
   359     
       
   360     _private->loader = loader;
       
   361     loader->ref();
       
   362         
       
   363     LOG(Loading, "creating datasource for %@", _private->loader->request().url().getNSURL());
       
   364     
       
   365     ++WebDataSourceCount;
       
   366     
       
   367     return self;    
       
   368 }
       
   369 
       
   370 @end
       
   371 
       
   372 @implementation WebDataSource
       
   373 
       
   374 - (id)initWithRequest:(NSURLRequest *)request
       
   375 {
       
   376     return [self _initWithDocumentLoader:new WebDocumentLoaderMac(request, SubstituteData())];
       
   377 }
       
   378 
       
   379 - (void)dealloc
       
   380 {
       
   381     --WebDataSourceCount;
       
   382     
       
   383     [_private release];
       
   384     
       
   385     [super dealloc];
       
   386 }
       
   387 
       
   388 - (void)finalize
       
   389 {
       
   390     --WebDataSourceCount;
       
   391 
       
   392     [super finalize];
       
   393 }
       
   394 
       
   395 - (NSData *)data
       
   396 {
       
   397     RefPtr<SharedBuffer> mainResourceData = _private->loader->mainResourceData();
       
   398     if (!mainResourceData)
       
   399         return nil;
       
   400     return [mainResourceData->createNSData() autorelease];
       
   401 }
       
   402 
       
   403 - (id <WebDocumentRepresentation>)representation
       
   404 {
       
   405     return _private->representation;
       
   406 }
       
   407 
       
   408 - (WebFrame *)webFrame
       
   409 {
       
   410     FrameLoader* frameLoader = _private->loader->frameLoader();
       
   411     if (!frameLoader)
       
   412         return nil;
       
   413     return static_cast<WebFrameLoaderClient*>(frameLoader->client())->webFrame();
       
   414 }
       
   415 
       
   416 - (NSURLRequest *)initialRequest
       
   417 {
       
   418     return _private->loader->initialRequest().nsURLRequest();
       
   419 }
       
   420 
       
   421 - (NSMutableURLRequest *)request
       
   422 {
       
   423     FrameLoader* frameLoader = _private->loader->frameLoader();
       
   424     if (!frameLoader || !frameLoader->frameHasLoaded())
       
   425         return nil;
       
   426 
       
   427     // FIXME: this cast is dubious
       
   428     return (NSMutableURLRequest *)_private->loader->request().nsURLRequest();
       
   429 }
       
   430 
       
   431 - (NSURLResponse *)response
       
   432 {
       
   433     return _private->loader->response().nsURLResponse();
       
   434 }
       
   435 
       
   436 - (NSString *)textEncodingName
       
   437 {
       
   438     NSString *textEncodingName = _private->loader->overrideEncoding();
       
   439     if (!textEncodingName)
       
   440         textEncodingName = [[self response] textEncodingName];
       
   441     return textEncodingName;
       
   442 }
       
   443 
       
   444 - (BOOL)isLoading
       
   445 {
       
   446     return _private->loader->isLoadingInAPISense();
       
   447 }
       
   448 
       
   449 // Returns nil or the page title.
       
   450 - (NSString *)pageTitle
       
   451 {
       
   452     return [[self representation] title];
       
   453 }
       
   454 
       
   455 - (NSURL *)unreachableURL
       
   456 {
       
   457     KURL URL = _private->loader->unreachableURL();
       
   458     return URL.isEmpty() ? nil : URL.getNSURL();
       
   459 }
       
   460 
       
   461 - (WebArchive *)webArchive
       
   462 {
       
   463     // it makes no sense to grab a WebArchive from an uncommitted document.
       
   464     if (!_private->loader->isCommitted())
       
   465         return nil;
       
   466     return [WebArchiver archiveFrame:[self webFrame]];
       
   467 }
       
   468 
       
   469 - (WebResource *)mainResource
       
   470 {
       
   471     NSURLResponse *response = [self response];
       
   472     return [[[WebResource alloc] initWithData:[self data]
       
   473                                           URL:[response URL] 
       
   474                                      MIMEType:[response MIMEType]
       
   475                              textEncodingName:[response textEncodingName]
       
   476                                     frameName:[[self webFrame] name]] autorelease];
       
   477 }
       
   478 
       
   479 - (NSArray *)subresources
       
   480 {
       
   481     if (!_private->loader->isCommitted())
       
   482         return [NSMutableArray array];
       
   483 
       
   484     NSArray *datas;
       
   485     NSArray *responses;
       
   486     [[self _bridge] getAllResourceDatas:&datas andResponses:&responses];
       
   487     ASSERT([datas count] == [responses count]);
       
   488 
       
   489     NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]];
       
   490     for (unsigned i = 0; i < [datas count]; ++i) {
       
   491         NSURLResponse *response = [responses objectAtIndex:i];
       
   492         [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]];
       
   493     }
       
   494 
       
   495     return [subresources autorelease];
       
   496 }
       
   497 
       
   498 - (WebResource *)subresourceForURL:(NSURL *)URL
       
   499 {
       
   500     if (!_private->loader->isCommitted())
       
   501         return nil;
       
   502 
       
   503     NSData *data;
       
   504     NSURLResponse *response;
       
   505     if (![[self _bridge] getData:&data andResponse:&response forURL:[URL _web_originalDataAsString]])
       
   506         return [self _archivedSubresourceForURL:URL];
       
   507 
       
   508     return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
       
   509 }
       
   510 
       
   511 - (void)addSubresource:(WebResource *)subresource
       
   512 {
       
   513     if (subresource) {
       
   514         if (!_private->unarchivingState)
       
   515             _private->unarchivingState = [[WebUnarchivingState alloc] init];
       
   516         [_private->unarchivingState addResource:subresource];
       
   517     }
       
   518 }
       
   519 
       
   520 @end