WebKit/mac/WebView/WebArchive.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 "WebArchive.h"
       
    30 #import "WebArchiveInternal.h"
       
    31 
       
    32 #import "WebKitLogging.h"
       
    33 #import "WebNSObjectExtras.h"
       
    34 #import "WebResourceInternal.h"
       
    35 #import "WebTypesInternal.h"
       
    36 #import <JavaScriptCore/InitializeThreading.h>
       
    37 #import <WebCore/ArchiveResource.h>
       
    38 #import <WebCore/LegacyWebArchive.h>
       
    39 #import <WebCore/ThreadCheck.h>
       
    40 #import <WebCore/WebCoreObjCExtras.h>
       
    41 #import <wtf/Threading.h>
       
    42 
       
    43 using namespace WebCore;
       
    44 
       
    45 NSString *WebArchivePboardType = @"Apple Web Archive pasteboard type";
       
    46 
       
    47 static NSString * const WebMainResourceKey = @"WebMainResource";
       
    48 static NSString * const WebSubresourcesKey = @"WebSubresources";
       
    49 static NSString * const WebSubframeArchivesKey = @"WebSubframeArchives";
       
    50 
       
    51 @interface WebArchivePrivate : NSObject {
       
    52 @public
       
    53     WebResource *cachedMainResource;
       
    54     NSArray *cachedSubresources;
       
    55     NSArray *cachedSubframeArchives;
       
    56 @private
       
    57     RefPtr<LegacyWebArchive> coreArchive;
       
    58 }
       
    59 
       
    60 - (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)coreArchive;
       
    61 - (LegacyWebArchive*)coreArchive;
       
    62 - (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive;
       
    63 @end
       
    64 
       
    65 @implementation WebArchivePrivate
       
    66 
       
    67 + (void)initialize
       
    68 {
       
    69     JSC::initializeThreading();
       
    70     WTF::initializeMainThreadToProcessMainThread();
       
    71 #ifndef BUILDING_ON_TIGER
       
    72     WebCoreObjCFinalizeOnMainThread(self);
       
    73 #endif
       
    74 }
       
    75 
       
    76 - (id)init
       
    77 {
       
    78     self = [super init];
       
    79     if (!self)
       
    80         return nil;
       
    81     coreArchive = LegacyWebArchive::create();
       
    82     return self;
       
    83 }
       
    84 
       
    85 - (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)_coreArchive
       
    86 {
       
    87     self = [super init];
       
    88     if (!self || !_coreArchive) {
       
    89         [self release];
       
    90         return nil;
       
    91     }
       
    92     coreArchive = _coreArchive;
       
    93     return self;
       
    94 }
       
    95 
       
    96 - (LegacyWebArchive*)coreArchive
       
    97 {
       
    98     return coreArchive.get();
       
    99 }
       
   100 
       
   101 - (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive
       
   102 {
       
   103     ASSERT(coreArchive);
       
   104     ASSERT(newCoreArchive);
       
   105     coreArchive = newCoreArchive;
       
   106 }
       
   107 
       
   108 - (void)dealloc
       
   109 {
       
   110     if (WebCoreObjCScheduleDeallocateOnMainThread([WebArchivePrivate class], self))
       
   111         return;
       
   112     
       
   113     [cachedMainResource release];
       
   114     [cachedSubresources release];
       
   115     [cachedSubframeArchives release];
       
   116     
       
   117     [super dealloc];
       
   118 }
       
   119 
       
   120 @end
       
   121 
       
   122 @implementation WebArchive
       
   123 
       
   124 - (id)init
       
   125 {
       
   126     WebCoreThreadViolationCheckRoundTwo();
       
   127 
       
   128     self = [super init];
       
   129     if (!self)
       
   130         return nil;
       
   131     _private = [[WebArchivePrivate alloc] init];
       
   132     return self;
       
   133 }
       
   134 
       
   135 static BOOL isArrayOfClass(id object, Class elementClass)
       
   136 {
       
   137     if (![object isKindOfClass:[NSArray class]])
       
   138         return NO;
       
   139     NSArray *array = (NSArray *)object;
       
   140     NSUInteger count = [array count];
       
   141     for (NSUInteger i = 0; i < count; ++i)
       
   142         if (![[array objectAtIndex:i] isKindOfClass:elementClass])
       
   143             return NO;
       
   144     return YES;
       
   145 }
       
   146 
       
   147 - (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
       
   148 {
       
   149 #ifdef MAIL_THREAD_WORKAROUND
       
   150     if (needMailThreadWorkaround())
       
   151         return [[self _webkit_invokeOnMainThread] initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives];
       
   152 #endif
       
   153 
       
   154     WebCoreThreadViolationCheckRoundTwo();
       
   155 
       
   156     self = [super init];
       
   157     if (!self)
       
   158         return nil;
       
   159 
       
   160     _private = [[WebArchivePrivate alloc] init];
       
   161 
       
   162     _private->cachedMainResource = [mainResource retain];
       
   163     if (!_private->cachedMainResource) {
       
   164         [self release];
       
   165         return nil;
       
   166     }
       
   167     
       
   168     if (!subresources || isArrayOfClass(subresources, [WebResource class]))
       
   169         _private->cachedSubresources = [subresources retain];
       
   170     else {
       
   171         [self release];
       
   172         return nil;
       
   173     }
       
   174 
       
   175     if (!subframeArchives || isArrayOfClass(subframeArchives, [WebArchive class]))
       
   176         _private->cachedSubframeArchives = [subframeArchives retain];
       
   177     else {
       
   178         [self release];
       
   179         return nil;
       
   180     }
       
   181     
       
   182     RefPtr<ArchiveResource> coreMainResource = mainResource ? [mainResource _coreResource] : 0;
       
   183 
       
   184     Vector<PassRefPtr<ArchiveResource> > coreResources;
       
   185     NSEnumerator *enumerator = [subresources objectEnumerator];
       
   186     WebResource *subresource;
       
   187     while ((subresource = [enumerator nextObject]) != nil)
       
   188         coreResources.append([subresource _coreResource]);
       
   189 
       
   190     Vector<PassRefPtr<LegacyWebArchive> > coreArchives;
       
   191     enumerator = [subframeArchives objectEnumerator];
       
   192     WebArchive *subframeArchive;
       
   193     while ((subframeArchive = [enumerator nextObject]) != nil)
       
   194         coreArchives.append([subframeArchive->_private coreArchive]);
       
   195 
       
   196     [_private setCoreArchive:LegacyWebArchive::create(coreMainResource.release(), coreResources, coreArchives)];
       
   197     if (![_private coreArchive]) {
       
   198         [self release];
       
   199         return nil;
       
   200     }
       
   201 
       
   202     return self;
       
   203 }
       
   204 
       
   205 - (id)initWithData:(NSData *)data
       
   206 {
       
   207     WebCoreThreadViolationCheckRoundTwo();
       
   208 
       
   209     self = [super init];
       
   210     if (!self)
       
   211         return nil;
       
   212         
       
   213 #if !LOG_DISABLED
       
   214     CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
       
   215 #endif
       
   216 
       
   217     _private = [[WebArchivePrivate alloc] init];
       
   218     RefPtr<LegacyWebArchive> coreArchive = LegacyWebArchive::create(SharedBuffer::wrapNSData(data).get());
       
   219     if (!coreArchive) {
       
   220         [self release];
       
   221         return nil;
       
   222     }
       
   223         
       
   224     [_private setCoreArchive:coreArchive.release()];
       
   225         
       
   226 #if !LOG_DISABLED
       
   227     CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
       
   228     CFAbsoluteTime duration = end - start;
       
   229 #endif
       
   230     LOG(Timing, "Parsing web archive with [NSPropertyListSerialization propertyListFromData::::] took %f seconds", duration);
       
   231     
       
   232     return self;
       
   233 }
       
   234 
       
   235 - (id)initWithCoder:(NSCoder *)decoder
       
   236 {    
       
   237     WebResource *mainResource = nil;
       
   238     NSArray *subresources = nil;
       
   239     NSArray *subframeArchives = nil;
       
   240     
       
   241     @try {
       
   242         id object = [decoder decodeObjectForKey:WebMainResourceKey];
       
   243         if ([object isKindOfClass:[WebResource class]])
       
   244             mainResource = object;
       
   245         object = [decoder decodeObjectForKey:WebSubresourcesKey];
       
   246         if (isArrayOfClass(object, [WebResource class]))
       
   247             subresources = object;
       
   248         object = [decoder decodeObjectForKey:WebSubframeArchivesKey];
       
   249         if (isArrayOfClass(object, [WebArchive class]))
       
   250             subframeArchives = object;
       
   251     } @catch(id) {
       
   252         [self release];
       
   253         return nil;
       
   254     }
       
   255 
       
   256     return [self initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives];
       
   257 }
       
   258 
       
   259 - (void)encodeWithCoder:(NSCoder *)encoder
       
   260 {
       
   261     [encoder encodeObject:[self mainResource] forKey:WebMainResourceKey];
       
   262     [encoder encodeObject:[self subresources] forKey:WebSubresourcesKey];
       
   263     [encoder encodeObject:[self subframeArchives] forKey:WebSubframeArchivesKey];    
       
   264 }
       
   265 
       
   266 - (void)dealloc
       
   267 {
       
   268     [_private release];
       
   269     [super dealloc];
       
   270 }
       
   271 
       
   272 - (id)copyWithZone:(NSZone *)zone
       
   273 {
       
   274     return [self retain];
       
   275 }
       
   276 
       
   277 - (WebResource *)mainResource
       
   278 {
       
   279 #ifdef MAIL_THREAD_WORKAROUND
       
   280     if (needMailThreadWorkaround())
       
   281         return [[self _webkit_invokeOnMainThread] mainResource];
       
   282 #endif
       
   283 
       
   284     WebCoreThreadViolationCheckRoundTwo();
       
   285 
       
   286     // Currently from WebKit API perspective, WebArchives are entirely immutable once created
       
   287     // If they ever become mutable, we'll need to rethink this. 
       
   288     if (!_private->cachedMainResource) {
       
   289         LegacyWebArchive* coreArchive = [_private coreArchive];
       
   290         if (coreArchive)
       
   291             _private->cachedMainResource = [[WebResource alloc] _initWithCoreResource:coreArchive->mainResource()];
       
   292     }
       
   293     
       
   294     return [[_private->cachedMainResource retain] autorelease];
       
   295 }
       
   296 
       
   297 - (NSArray *)subresources
       
   298 {
       
   299 #ifdef MAIL_THREAD_WORKAROUND
       
   300     if (needMailThreadWorkaround())
       
   301         return [[self _webkit_invokeOnMainThread] subresources];
       
   302 #endif
       
   303 
       
   304     WebCoreThreadViolationCheckRoundTwo();
       
   305 
       
   306     // Currently from WebKit API perspective, WebArchives are entirely immutable once created
       
   307     // If they ever become mutable, we'll need to rethink this.     
       
   308     if (!_private->cachedSubresources) {
       
   309         LegacyWebArchive* coreArchive = [_private coreArchive];
       
   310         if (!coreArchive)
       
   311             _private->cachedSubresources = [[NSArray alloc] init];
       
   312         else {
       
   313             const Vector<RefPtr<ArchiveResource> >& subresources(coreArchive->subresources());
       
   314             NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:subresources.size()];
       
   315             _private->cachedSubresources = mutableArray;
       
   316             for (unsigned i = 0; i < subresources.size(); ++i) {
       
   317                 WebResource *resource = [[WebResource alloc] _initWithCoreResource:subresources[i].get()];
       
   318                 if (resource) {
       
   319                     [mutableArray addObject:resource];
       
   320                     [resource release];
       
   321                 }
       
   322             }
       
   323         }
       
   324     }
       
   325     // Maintain the WebKit 3 behavior of this API, which is documented and
       
   326     // relied upon by some clients, of returning nil if there are no subresources.
       
   327     return [_private->cachedSubresources count] ? [[_private->cachedSubresources retain] autorelease] : nil;
       
   328 }
       
   329 
       
   330 - (NSArray *)subframeArchives
       
   331 {
       
   332 #ifdef MAIL_THREAD_WORKAROUND
       
   333     if (needMailThreadWorkaround())
       
   334         return [[self _webkit_invokeOnMainThread] subframeArchives];
       
   335 #endif
       
   336 
       
   337     WebCoreThreadViolationCheckRoundTwo();
       
   338 
       
   339     // Currently from WebKit API perspective, WebArchives are entirely immutable once created
       
   340     // If they ever become mutable, we'll need to rethink this.  
       
   341     if (!_private->cachedSubframeArchives) {
       
   342         LegacyWebArchive* coreArchive = [_private coreArchive];
       
   343         if (!coreArchive)
       
   344             _private->cachedSubframeArchives = [[NSArray alloc] init];
       
   345         else {
       
   346             const Vector<RefPtr<Archive> >& subframeArchives(coreArchive->subframeArchives());
       
   347             NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:subframeArchives.size()];
       
   348             _private->cachedSubframeArchives = mutableArray;
       
   349             for (unsigned i = 0; i < subframeArchives.size(); ++i) {
       
   350                 WebArchive *archive = [[WebArchive alloc] _initWithCoreLegacyWebArchive:(LegacyWebArchive *)subframeArchives[i].get()];
       
   351                 [mutableArray addObject:archive];
       
   352                 [archive release];
       
   353             }
       
   354         }
       
   355     }
       
   356     
       
   357     return [[_private->cachedSubframeArchives retain] autorelease];
       
   358 }
       
   359 
       
   360 - (NSData *)data
       
   361 {
       
   362     WebCoreThreadViolationCheckRoundTwo();
       
   363 
       
   364 #if !LOG_DISABLED
       
   365     CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
       
   366 #endif
       
   367 
       
   368     RetainPtr<CFDataRef> data = [_private coreArchive]->rawDataRepresentation();
       
   369     
       
   370 #if !LOG_DISABLED
       
   371     CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
       
   372     CFAbsoluteTime duration = end - start;
       
   373 #endif
       
   374     LOG(Timing, "Serializing web archive to raw CFPropertyList data took %f seconds", duration);
       
   375         
       
   376     return [[(NSData *)data.get() retain] autorelease];
       
   377 }
       
   378 
       
   379 @end
       
   380 
       
   381 @implementation WebArchive (WebInternal)
       
   382 
       
   383 - (id)_initWithCoreLegacyWebArchive:(PassRefPtr<WebCore::LegacyWebArchive>)coreLegacyWebArchive
       
   384 {
       
   385     WebCoreThreadViolationCheckRoundTwo();
       
   386 
       
   387     self = [super init];
       
   388     if (!self)
       
   389         return nil;
       
   390     
       
   391     _private = [[WebArchivePrivate alloc] initWithCoreArchive:coreLegacyWebArchive];
       
   392     if (!_private) {
       
   393         [self release];
       
   394         return nil;
       
   395     }
       
   396 
       
   397     return self;
       
   398 }
       
   399 
       
   400 - (WebCore::LegacyWebArchive *)_coreLegacyWebArchive
       
   401 {
       
   402     WebCoreThreadViolationCheckRoundTwo();
       
   403 
       
   404     return [_private coreArchive];
       
   405 }
       
   406 
       
   407 @end