--- /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 <JavaScriptCore/Assertions.h>
+#import <WebCore/FrameLoader.h>
+#import <WebCore/KURL.h>
+#import <WebCore/MIMETypeRegistry.h>
+#import <WebCore/ResourceRequest.h>
+#import <WebCore/SharedBuffer.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <WebKit/DOMHTML.h>
+#import <WebKit/DOMPrivate.h>
+#import <WebKitSystemInterface.h>
+
+using namespace WebCore;
+
+@interface WebDataSourcePrivate : NSObject {
+@public
+ WebDocumentLoaderMac* loader;
+
+ id <WebDocumentRepresentation> 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<WebDocumentRepresentation>)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<WebDataSource*> 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 <WebDocumentRepresentation>)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<SharedBuffer> mainResourceData = _private->loader->mainResourceData();
+ if (!mainResourceData)
+ return nil;
+ return [mainResourceData->createNSData() autorelease];
+}
+
+- (id <WebDocumentRepresentation>)representation
+{
+ return _private->representation;
+}
+
+- (WebFrame *)webFrame
+{
+ FrameLoader* frameLoader = _private->loader->frameLoader();
+ if (!frameLoader)
+ return nil;
+ return static_cast<WebFrameLoaderClient*>(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