diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/WebView/WebDataSource.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKit/WebView/WebDataSource.mm Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebDataSource.h" + +#import "WebArchive.h" +#import "WebArchiver.h" +#import "WebDataSourceInternal.h" +#import "WebDocument.h" +#import "WebDocumentLoaderMac.h" +#import "WebFrameBridge.h" +#import "WebFrameInternal.h" +#import "WebFrameLoadDelegate.h" +#import "WebFrameLoaderClient.h" +#import "WebHTMLRepresentation.h" +#import "WebKitErrorsPrivate.h" +#import "WebKitLogging.h" +#import "WebKitStatisticsPrivate.h" +#import "WebNSURLExtras.h" +#import "WebNSURLRequestExtras.h" +#import "WebPDFRepresentation.h" +#import "WebResourceLoadDelegate.h" +#import "WebResourcePrivate.h" +#import "WebUnarchivingState.h" +#import "WebViewInternal.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +using namespace WebCore; + +@interface WebDataSourcePrivate : NSObject { +@public + WebDocumentLoaderMac* loader; + + id representation; + + WebUnarchivingState *unarchivingState; + BOOL representationFinishedLoading; +} +@end + +@implementation WebDataSourcePrivate + +#ifndef BUILDING_ON_TIGER ++ (void)initialize +{ + WebCoreObjCFinalizeOnMainThread(self); +} +#endif + +- (void)dealloc +{ + ASSERT(!loader->isLoading()); + loader->detachDataSource(); + loader->deref(); + + [representation release]; + [unarchivingState release]; + + [super dealloc]; +} + +- (void)finalize +{ + ASSERT_MAIN_THREAD(); + + ASSERT(!loader->isLoading()); + loader->detachDataSource(); + loader->deref(); + + [super finalize]; +} + +@end + +@interface WebDataSource (WebFileInternal) +@end + +@implementation WebDataSource (WebFileInternal) + +- (void)_setRepresentation:(id)representation +{ + [_private->representation release]; + _private->representation = [representation retain]; + _private->representationFinishedLoading = NO; +} + +static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCClass, NSArray *supportTypes) +{ + NSEnumerator *enumerator = [supportTypes objectEnumerator]; + ASSERT(enumerator != nil); + NSString *mime = nil; + while ((mime = [enumerator nextObject]) != nil) { + // Don't clobber previously-registered classes. + if ([allTypes objectForKey:mime] == nil) + [allTypes setObject:objCClass forKey:mime]; + } +} + ++ (Class)_representationClassForMIMEType:(NSString *)MIMEType +{ + Class repClass; + return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil; +} + +@end + +@implementation WebDataSource (WebPrivate) + +- (NSError *)_mainDocumentError +{ + return _private->loader->mainDocumentError(); +} + +- (void)_addSubframeArchives:(NSArray *)subframeArchives +{ + NSEnumerator *enumerator = [subframeArchives objectEnumerator]; + WebArchive *archive; + while ((archive = [enumerator nextObject]) != nil) + [self _addToUnarchiveState:archive]; +} + +- (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL +{ + if ([URL isFileURL]) { + NSString *path = [[URL path] stringByResolvingSymlinksInPath]; + return [[[NSFileWrapper alloc] initWithPath:path] autorelease]; + } + + WebResource *resource = [self subresourceForURL:URL]; + if (resource) + return [resource _fileWrapperRepresentation]; + + NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL]; + if (cachedResponse) { + NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease]; + [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]]; + return wrapper; + } + + return nil; +} + +@end + +@implementation WebDataSource (WebInternal) + +- (void)_finishedLoading +{ + _private->representationFinishedLoading = YES; + [[self representation] finishedLoadingWithDataSource:self]; +} + +- (void)_receivedData:(NSData *)data +{ + // protect self temporarily, as the bridge receivedData call could remove our last ref + RetainPtr protect(self); + + [[self representation] receivedData:data withDataSource:self]; + [[[[self webFrame] frameView] documentView] dataSourceUpdated:self]; +} + +- (void)_setMainDocumentError:(NSError *)error +{ + if (!_private->representationFinishedLoading) { + _private->representationFinishedLoading = YES; + [[self representation] receivedError:error withDataSource:self]; + } +} + +- (void)_clearUnarchivingState +{ + [_private->unarchivingState release]; + _private->unarchivingState = nil; +} + +- (void)_revertToProvisionalState +{ + [self _setRepresentation:nil]; +} + ++ (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission +{ + static NSMutableDictionary *repTypes = nil; + static BOOL addedImageTypes = NO; + + if (!repTypes) { + repTypes = [[NSMutableDictionary alloc] init]; + addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]); + + // Since this is a "secret default" we don't both registering it. + BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"]; + if (!omitPDFSupport) + addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]); + } + + if (!addedImageTypes && !allowImageTypeOmission) { + addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]); + addedImageTypes = YES; + } + + return repTypes; +} + +- (WebResource *)_archivedSubresourceForURL:(NSURL *)URL +{ + return [_private->unarchivingState archivedResourceForURL:URL]; +} + +- (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement +{ + DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive]; + if (fragment) + [[self _bridge] replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO]; +} + +- (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive +{ + ASSERT(archive); + WebResource *mainResource = [archive mainResource]; + if (mainResource) { + NSString *MIMEType = [mainResource MIMEType]; + if ([WebView canShowMIMETypeAsHTML:MIMEType]) { + NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding]; + // FIXME: seems poor form to do this as a side effect of getting a document fragment + [self _addToUnarchiveState:archive]; + DOMDocumentFragment *fragment = [[self _bridge] documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]]; + [markupString release]; + return fragment; + } else if (MIMETypeRegistry::isSupportedImageMIMEType(MIMEType)) { + return [self _documentFragmentWithImageResource:mainResource]; + + } + } + return nil; +} + +- (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource +{ + DOMElement *imageElement = [self _imageElementWithImageResource:resource]; + if (!imageElement) + return 0; + DOMDocumentFragment *fragment = [[[self webFrame] DOMDocument] createDocumentFragment]; + [fragment appendChild:imageElement]; + return fragment; +} + +- (DOMElement *)_imageElementWithImageResource:(WebResource *)resource +{ + if (!resource) + return 0; + + [self addSubresource:resource]; + + DOMElement *imageElement = [[[self webFrame] DOMDocument] createElement:@"img"]; + + // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this. + NSURL *URL = [resource URL]; + [imageElement setAttribute:@"src" value:[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]]; + + return imageElement; +} + +// May return nil if not initialized with a URL. +- (NSURL *)_URL +{ + KURL URL = _private->loader->URL(); + return URL.isEmpty() ? nil : URL.getNSURL(); +} + +- (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName +{ + return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName]; +} + +- (WebFrameBridge *)_bridge +{ + ASSERT(_private->loader->isCommitted()); + return [[self webFrame] _bridge]; +} + +- (WebView *)_webView +{ + return [[self webFrame] webView]; +} + +- (BOOL)_isDocumentHTML +{ + NSString *MIMEType = [[self response] MIMEType]; + return [WebView canShowMIMETypeAsHTML:MIMEType]; +} + +-(void)_makeRepresentation +{ + Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]]; + + // Check if the data source was already bound? + if (![[self representation] isKindOfClass:repClass]) { + id newRep = repClass != nil ? [[repClass alloc] init] : nil; + [self _setRepresentation:(id )newRep]; + [newRep release]; + } + + [_private->representation setDataSource:self]; +} + +- (void)_addToUnarchiveState:(WebArchive *)archive +{ + if (!_private->unarchivingState) + _private->unarchivingState = [[WebUnarchivingState alloc] init]; + [_private->unarchivingState addArchive:archive]; +} + +- (DocumentLoader*)_documentLoader +{ + return _private->loader; +} + +- (id)_initWithDocumentLoader:(WebDocumentLoaderMac *)loader +{ + self = [super init]; + if (!self) + return nil; + + _private = [[WebDataSourcePrivate alloc] init]; + + _private->loader = loader; + loader->ref(); + + LOG(Loading, "creating datasource for %@", _private->loader->request().url().getNSURL()); + + ++WebDataSourceCount; + + return self; +} + +@end + +@implementation WebDataSource + +- (id)initWithRequest:(NSURLRequest *)request +{ + return [self _initWithDocumentLoader:new WebDocumentLoaderMac(request, SubstituteData())]; +} + +- (void)dealloc +{ + --WebDataSourceCount; + + [_private release]; + + [super dealloc]; +} + +- (void)finalize +{ + --WebDataSourceCount; + + [super finalize]; +} + +- (NSData *)data +{ + RefPtr mainResourceData = _private->loader->mainResourceData(); + if (!mainResourceData) + return nil; + return [mainResourceData->createNSData() autorelease]; +} + +- (id )representation +{ + return _private->representation; +} + +- (WebFrame *)webFrame +{ + FrameLoader* frameLoader = _private->loader->frameLoader(); + if (!frameLoader) + return nil; + return static_cast(frameLoader->client())->webFrame(); +} + +- (NSURLRequest *)initialRequest +{ + return _private->loader->initialRequest().nsURLRequest(); +} + +- (NSMutableURLRequest *)request +{ + FrameLoader* frameLoader = _private->loader->frameLoader(); + if (!frameLoader || !frameLoader->frameHasLoaded()) + return nil; + + // FIXME: this cast is dubious + return (NSMutableURLRequest *)_private->loader->request().nsURLRequest(); +} + +- (NSURLResponse *)response +{ + return _private->loader->response().nsURLResponse(); +} + +- (NSString *)textEncodingName +{ + NSString *textEncodingName = _private->loader->overrideEncoding(); + if (!textEncodingName) + textEncodingName = [[self response] textEncodingName]; + return textEncodingName; +} + +- (BOOL)isLoading +{ + return _private->loader->isLoadingInAPISense(); +} + +// Returns nil or the page title. +- (NSString *)pageTitle +{ + return [[self representation] title]; +} + +- (NSURL *)unreachableURL +{ + KURL URL = _private->loader->unreachableURL(); + return URL.isEmpty() ? nil : URL.getNSURL(); +} + +- (WebArchive *)webArchive +{ + // it makes no sense to grab a WebArchive from an uncommitted document. + if (!_private->loader->isCommitted()) + return nil; + return [WebArchiver archiveFrame:[self webFrame]]; +} + +- (WebResource *)mainResource +{ + NSURLResponse *response = [self response]; + return [[[WebResource alloc] initWithData:[self data] + URL:[response URL] + MIMEType:[response MIMEType] + textEncodingName:[response textEncodingName] + frameName:[[self webFrame] name]] autorelease]; +} + +- (NSArray *)subresources +{ + if (!_private->loader->isCommitted()) + return [NSMutableArray array]; + + NSArray *datas; + NSArray *responses; + [[self _bridge] getAllResourceDatas:&datas andResponses:&responses]; + ASSERT([datas count] == [responses count]); + + NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]]; + for (unsigned i = 0; i < [datas count]; ++i) { + NSURLResponse *response = [responses objectAtIndex:i]; + [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]]; + } + + return [subresources autorelease]; +} + +- (WebResource *)subresourceForURL:(NSURL *)URL +{ + if (!_private->loader->isCommitted()) + return nil; + + NSData *data; + NSURLResponse *response; + if (![[self _bridge] getData:&data andResponse:&response forURL:[URL _web_originalDataAsString]]) + return [self _archivedSubresourceForURL:URL]; + + return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease]; +} + +- (void)addSubresource:(WebResource *)subresource +{ + if (subresource) { + if (!_private->unarchivingState) + _private->unarchivingState = [[WebUnarchivingState alloc] init]; + [_private->unarchivingState addResource:subresource]; + } +} + +@end