WebKit/mac/WebView/WebArchive.mm
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKit/mac/WebView/WebArchive.mm	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 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 "WebArchive.h"
+#import "WebArchiveInternal.h"
+
+#import "WebKitLogging.h"
+#import "WebNSObjectExtras.h"
+#import "WebResourceInternal.h"
+#import "WebTypesInternal.h"
+#import <JavaScriptCore/InitializeThreading.h>
+#import <WebCore/ArchiveResource.h>
+#import <WebCore/LegacyWebArchive.h>
+#import <WebCore/ThreadCheck.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <wtf/Threading.h>
+
+using namespace WebCore;
+
+NSString *WebArchivePboardType = @"Apple Web Archive pasteboard type";
+
+static NSString * const WebMainResourceKey = @"WebMainResource";
+static NSString * const WebSubresourcesKey = @"WebSubresources";
+static NSString * const WebSubframeArchivesKey = @"WebSubframeArchives";
+
+@interface WebArchivePrivate : NSObject {
+@public
+    WebResource *cachedMainResource;
+    NSArray *cachedSubresources;
+    NSArray *cachedSubframeArchives;
+@private
+    RefPtr<LegacyWebArchive> coreArchive;
+}
+
+- (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)coreArchive;
+- (LegacyWebArchive*)coreArchive;
+- (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive;
+@end
+
+@implementation WebArchivePrivate
+
++ (void)initialize
+{
+    JSC::initializeThreading();
+    WTF::initializeMainThreadToProcessMainThread();
+#ifndef BUILDING_ON_TIGER
+    WebCoreObjCFinalizeOnMainThread(self);
+#endif
+}
+
+- (id)init
+{
+    self = [super init];
+    if (!self)
+        return nil;
+    coreArchive = LegacyWebArchive::create();
+    return self;
+}
+
+- (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)_coreArchive
+{
+    self = [super init];
+    if (!self || !_coreArchive) {
+        [self release];
+        return nil;
+    }
+    coreArchive = _coreArchive;
+    return self;
+}
+
+- (LegacyWebArchive*)coreArchive
+{
+    return coreArchive.get();
+}
+
+- (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive
+{
+    ASSERT(coreArchive);
+    ASSERT(newCoreArchive);
+    coreArchive = newCoreArchive;
+}
+
+- (void)dealloc
+{
+    if (WebCoreObjCScheduleDeallocateOnMainThread([WebArchivePrivate class], self))
+        return;
+    
+    [cachedMainResource release];
+    [cachedSubresources release];
+    [cachedSubframeArchives release];
+    
+    [super dealloc];
+}
+
+@end
+
+@implementation WebArchive
+
+- (id)init
+{
+    WebCoreThreadViolationCheckRoundTwo();
+
+    self = [super init];
+    if (!self)
+        return nil;
+    _private = [[WebArchivePrivate alloc] init];
+    return self;
+}
+
+static BOOL isArrayOfClass(id object, Class elementClass)
+{
+    if (![object isKindOfClass:[NSArray class]])
+        return NO;
+    NSArray *array = (NSArray *)object;
+    NSUInteger count = [array count];
+    for (NSUInteger i = 0; i < count; ++i)
+        if (![[array objectAtIndex:i] isKindOfClass:elementClass])
+            return NO;
+    return YES;
+}
+
+- (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
+{
+#ifdef MAIL_THREAD_WORKAROUND
+    if (needMailThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives];
+#endif
+
+    WebCoreThreadViolationCheckRoundTwo();
+
+    self = [super init];
+    if (!self)
+        return nil;
+
+    _private = [[WebArchivePrivate alloc] init];
+
+    _private->cachedMainResource = [mainResource retain];
+    if (!_private->cachedMainResource) {
+        [self release];
+        return nil;
+    }
+    
+    if (!subresources || isArrayOfClass(subresources, [WebResource class]))
+        _private->cachedSubresources = [subresources retain];
+    else {
+        [self release];
+        return nil;
+    }
+
+    if (!subframeArchives || isArrayOfClass(subframeArchives, [WebArchive class]))
+        _private->cachedSubframeArchives = [subframeArchives retain];
+    else {
+        [self release];
+        return nil;
+    }
+    
+    RefPtr<ArchiveResource> coreMainResource = mainResource ? [mainResource _coreResource] : 0;
+
+    Vector<PassRefPtr<ArchiveResource> > coreResources;
+    NSEnumerator *enumerator = [subresources objectEnumerator];
+    WebResource *subresource;
+    while ((subresource = [enumerator nextObject]) != nil)
+        coreResources.append([subresource _coreResource]);
+
+    Vector<PassRefPtr<LegacyWebArchive> > coreArchives;
+    enumerator = [subframeArchives objectEnumerator];
+    WebArchive *subframeArchive;
+    while ((subframeArchive = [enumerator nextObject]) != nil)
+        coreArchives.append([subframeArchive->_private coreArchive]);
+
+    [_private setCoreArchive:LegacyWebArchive::create(coreMainResource.release(), coreResources, coreArchives)];
+    if (![_private coreArchive]) {
+        [self release];
+        return nil;
+    }
+
+    return self;
+}
+
+- (id)initWithData:(NSData *)data
+{
+    WebCoreThreadViolationCheckRoundTwo();
+
+    self = [super init];
+    if (!self)
+        return nil;
+        
+#if !LOG_DISABLED
+    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
+#endif
+
+    _private = [[WebArchivePrivate alloc] init];
+    RefPtr<LegacyWebArchive> coreArchive = LegacyWebArchive::create(SharedBuffer::wrapNSData(data).get());
+    if (!coreArchive) {
+        [self release];
+        return nil;
+    }
+        
+    [_private setCoreArchive:coreArchive.release()];
+        
+#if !LOG_DISABLED
+    CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
+    CFAbsoluteTime duration = end - start;
+#endif
+    LOG(Timing, "Parsing web archive with [NSPropertyListSerialization propertyListFromData::::] took %f seconds", duration);
+    
+    return self;
+}
+
+- (id)initWithCoder:(NSCoder *)decoder
+{    
+    WebResource *mainResource = nil;
+    NSArray *subresources = nil;
+    NSArray *subframeArchives = nil;
+    
+    @try {
+        id object = [decoder decodeObjectForKey:WebMainResourceKey];
+        if ([object isKindOfClass:[WebResource class]])
+            mainResource = object;
+        object = [decoder decodeObjectForKey:WebSubresourcesKey];
+        if (isArrayOfClass(object, [WebResource class]))
+            subresources = object;
+        object = [decoder decodeObjectForKey:WebSubframeArchivesKey];
+        if (isArrayOfClass(object, [WebArchive class]))
+            subframeArchives = object;
+    } @catch(id) {
+        [self release];
+        return nil;
+    }
+
+    return [self initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives];
+}
+
+- (void)encodeWithCoder:(NSCoder *)encoder
+{
+    [encoder encodeObject:[self mainResource] forKey:WebMainResourceKey];
+    [encoder encodeObject:[self subresources] forKey:WebSubresourcesKey];
+    [encoder encodeObject:[self subframeArchives] forKey:WebSubframeArchivesKey];    
+}
+
+- (void)dealloc
+{
+    [_private release];
+    [super dealloc];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    return [self retain];
+}
+
+- (WebResource *)mainResource
+{
+#ifdef MAIL_THREAD_WORKAROUND
+    if (needMailThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] mainResource];
+#endif
+
+    WebCoreThreadViolationCheckRoundTwo();
+
+    // Currently from WebKit API perspective, WebArchives are entirely immutable once created
+    // If they ever become mutable, we'll need to rethink this. 
+    if (!_private->cachedMainResource) {
+        LegacyWebArchive* coreArchive = [_private coreArchive];
+        if (coreArchive)
+            _private->cachedMainResource = [[WebResource alloc] _initWithCoreResource:coreArchive->mainResource()];
+    }
+    
+    return [[_private->cachedMainResource retain] autorelease];
+}
+
+- (NSArray *)subresources
+{
+#ifdef MAIL_THREAD_WORKAROUND
+    if (needMailThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] subresources];
+#endif
+
+    WebCoreThreadViolationCheckRoundTwo();
+
+    // Currently from WebKit API perspective, WebArchives are entirely immutable once created
+    // If they ever become mutable, we'll need to rethink this.     
+    if (!_private->cachedSubresources) {
+        LegacyWebArchive* coreArchive = [_private coreArchive];
+        if (!coreArchive)
+            _private->cachedSubresources = [[NSArray alloc] init];
+        else {
+            const Vector<RefPtr<ArchiveResource> >& subresources(coreArchive->subresources());
+            NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:subresources.size()];
+            _private->cachedSubresources = mutableArray;
+            for (unsigned i = 0; i < subresources.size(); ++i) {
+                WebResource *resource = [[WebResource alloc] _initWithCoreResource:subresources[i].get()];
+                if (resource) {
+                    [mutableArray addObject:resource];
+                    [resource release];
+                }
+            }
+        }
+    }
+    // Maintain the WebKit 3 behavior of this API, which is documented and
+    // relied upon by some clients, of returning nil if there are no subresources.
+    return [_private->cachedSubresources count] ? [[_private->cachedSubresources retain] autorelease] : nil;
+}
+
+- (NSArray *)subframeArchives
+{
+#ifdef MAIL_THREAD_WORKAROUND
+    if (needMailThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] subframeArchives];
+#endif
+
+    WebCoreThreadViolationCheckRoundTwo();
+
+    // Currently from WebKit API perspective, WebArchives are entirely immutable once created
+    // If they ever become mutable, we'll need to rethink this.  
+    if (!_private->cachedSubframeArchives) {
+        LegacyWebArchive* coreArchive = [_private coreArchive];
+        if (!coreArchive)
+            _private->cachedSubframeArchives = [[NSArray alloc] init];
+        else {
+            const Vector<RefPtr<Archive> >& subframeArchives(coreArchive->subframeArchives());
+            NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:subframeArchives.size()];
+            _private->cachedSubframeArchives = mutableArray;
+            for (unsigned i = 0; i < subframeArchives.size(); ++i) {
+                WebArchive *archive = [[WebArchive alloc] _initWithCoreLegacyWebArchive:(LegacyWebArchive *)subframeArchives[i].get()];
+                [mutableArray addObject:archive];
+                [archive release];
+            }
+        }
+    }
+    
+    return [[_private->cachedSubframeArchives retain] autorelease];
+}
+
+- (NSData *)data
+{
+    WebCoreThreadViolationCheckRoundTwo();
+
+#if !LOG_DISABLED
+    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
+#endif
+
+    RetainPtr<CFDataRef> data = [_private coreArchive]->rawDataRepresentation();
+    
+#if !LOG_DISABLED
+    CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
+    CFAbsoluteTime duration = end - start;
+#endif
+    LOG(Timing, "Serializing web archive to raw CFPropertyList data took %f seconds", duration);
+        
+    return [[(NSData *)data.get() retain] autorelease];
+}
+
+@end
+
+@implementation WebArchive (WebInternal)
+
+- (id)_initWithCoreLegacyWebArchive:(PassRefPtr<WebCore::LegacyWebArchive>)coreLegacyWebArchive
+{
+    WebCoreThreadViolationCheckRoundTwo();
+
+    self = [super init];
+    if (!self)
+        return nil;
+    
+    _private = [[WebArchivePrivate alloc] initWithCoreArchive:coreLegacyWebArchive];
+    if (!_private) {
+        [self release];
+        return nil;
+    }
+
+    return self;
+}
+
+- (WebCore::LegacyWebArchive *)_coreLegacyWebArchive
+{
+    WebCoreThreadViolationCheckRoundTwo();
+
+    return [_private coreArchive];
+}
+
+@end