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 "WebHTMLRepresentation.h" 30 31#import "DOMElementInternal.h" 32#import "DOMRangeInternal.h" 33#import "WebArchive.h" 34#import "WebBasePluginPackage.h" 35#import "WebDataSourceInternal.h" 36#import "WebDocumentPrivate.h" 37#import "WebFrameInternal.h" 38#import "WebKitNSStringExtras.h" 39#import "WebKitStatisticsPrivate.h" 40#import "WebNSAttributedStringExtras.h" 41#import "WebNSObjectExtras.h" 42#import "WebView.h" 43#import <Foundation/NSURLResponse.h> 44#import <WebCore/Document.h> 45#import <WebCore/DocumentLoader.h> 46#import <WebCore/Frame.h> 47#import <WebCore/FrameLoader.h> 48#import <WebCore/FrameLoaderClient.h> 49#import <WebCore/HTMLFormControlElement.h> 50#import <WebCore/HTMLFormElement.h> 51#import <WebCore/HTMLInputElement.h> 52#import <WebCore/HTMLNames.h> 53#import <WebCore/MIMETypeRegistry.h> 54#import <WebCore/Range.h> 55#import <WebCore/TextResourceDecoder.h> 56#import <WebKit/DOMHTMLInputElement.h> 57#import <wtf/Assertions.h> 58#import <wtf/StdLibExtras.h> 59 60using namespace WebCore; 61using namespace HTMLNames; 62 63@interface WebHTMLRepresentationPrivate : NSObject { 64@public 65 WebDataSource *dataSource; 66 67 BOOL hasSentResponseToPlugin; 68 id <WebPluginManualLoader> manualLoader; 69 NSView *pluginView; 70} 71@end 72 73@implementation WebHTMLRepresentationPrivate 74@end 75 76@implementation WebHTMLRepresentation 77 78static NSArray *stringArray(const HashSet<String>& set) 79{ 80 NSMutableArray *array = [NSMutableArray arrayWithCapacity:set.size()]; 81 HashSet<String>::const_iterator end = set.end(); 82 for (HashSet<String>::const_iterator it = set.begin(); it != end; ++it) 83 [array addObject:(NSString *)(*it)]; 84 return array; 85} 86 87static NSArray *concatenateArrays(NSArray *first, NSArray *second) 88{ 89 NSMutableArray *result = [[first mutableCopy] autorelease]; 90 [result addObjectsFromArray:second]; 91 return result; 92} 93 94+ (NSArray *)supportedMIMETypes 95{ 96 DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, staticSupportedMIMETypes, (concatenateArrays([self supportedNonImageMIMETypes], [self supportedImageMIMETypes]))); 97 return staticSupportedMIMETypes.get(); 98} 99 100+ (NSArray *)supportedNonImageMIMETypes 101{ 102 DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, staticSupportedNonImageMIMETypes, (stringArray(MIMETypeRegistry::getSupportedNonImageMIMETypes()))); 103 return staticSupportedNonImageMIMETypes.get(); 104} 105 106+ (NSArray *)supportedImageMIMETypes 107{ 108 DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, staticSupportedImageMIMETypes, (stringArray(MIMETypeRegistry::getSupportedImageMIMETypes()))); 109 return staticSupportedImageMIMETypes.get(); 110} 111 112- init 113{ 114 self = [super init]; 115 if (!self) 116 return nil; 117 118 _private = [[WebHTMLRepresentationPrivate alloc] init]; 119 120 ++WebHTMLRepresentationCount; 121 122 return self; 123} 124 125- (void)dealloc 126{ 127 --WebHTMLRepresentationCount; 128 129 [_private release]; 130 131 [super dealloc]; 132} 133 134- (void)finalize 135{ 136 --WebHTMLRepresentationCount; 137 138 [super finalize]; 139} 140 141- (void)_redirectDataToManualLoader:(id<WebPluginManualLoader>)manualLoader forPluginView:(NSView *)pluginView 142{ 143 _private->manualLoader = manualLoader; 144 _private->pluginView = pluginView; 145} 146 147- (void)setDataSource:(WebDataSource *)dataSource 148{ 149 _private->dataSource = dataSource; 150} 151 152- (BOOL)_isDisplayingWebArchive 153{ 154 return [[_private->dataSource _responseMIMEType] _webkit_isCaseInsensitiveEqualToString:@"application/x-webarchive"]; 155} 156 157- (void)receivedData:(NSData *)data withDataSource:(WebDataSource *)dataSource 158{ 159 WebFrame *webFrame = [dataSource webFrame]; 160 if (webFrame) { 161 if (!_private->pluginView) 162 [webFrame _receivedData:data textEncodingName:[[_private->dataSource response] textEncodingName]]; 163 164 // If the document is a stand-alone media document, now is the right time to cancel the WebKit load 165 Frame* coreFrame = core(webFrame); 166 if (coreFrame->document() && coreFrame->document()->isMediaDocument()) 167 coreFrame->loader()->documentLoader()->cancelMainResourceLoad(coreFrame->loader()->client()->pluginWillHandleLoadError(coreFrame->loader()->documentLoader()->response())); 168 169 if (_private->pluginView) { 170 if (!_private->hasSentResponseToPlugin) { 171 [_private->manualLoader pluginView:_private->pluginView receivedResponse:[dataSource response]]; 172 _private->hasSentResponseToPlugin = YES; 173 } 174 175 [_private->manualLoader pluginView:_private->pluginView receivedData:data]; 176 } 177 } 178} 179 180- (void)receivedError:(NSError *)error withDataSource:(WebDataSource *)dataSource 181{ 182 if (_private->pluginView) { 183 [_private->manualLoader pluginView:_private->pluginView receivedError:error]; 184 } 185} 186 187- (void)finishedLoadingWithDataSource:(WebDataSource *)dataSource 188{ 189 WebFrame *frame = [dataSource webFrame]; 190 191 if (_private->pluginView) { 192 [_private->manualLoader pluginViewFinishedLoading:_private->pluginView]; 193 return; 194 } 195 196 if (frame) { 197 if (![self _isDisplayingWebArchive]) { 198 // Telling the frame we received some data and passing nil as the data is our 199 // way to get work done that is normally done when the first bit of data is 200 // received, even for the case of a document with no data (like about:blank). 201 [frame _receivedData:nil textEncodingName:[[_private->dataSource response] textEncodingName]]; 202 } 203 204 WebView *webView = [frame webView]; 205 if ([webView isEditable]) 206 core(frame)->applyEditingStyleToBodyElement(); 207 } 208} 209 210- (BOOL)canProvideDocumentSource 211{ 212 return [[_private->dataSource webFrame] _canProvideDocumentSource]; 213} 214 215- (BOOL)canSaveAsWebArchive 216{ 217 return [[_private->dataSource webFrame] _canSaveAsWebArchive]; 218} 219 220- (NSString *)documentSource 221{ 222 if ([self _isDisplayingWebArchive]) { 223 SharedBuffer *parsedArchiveData = [_private->dataSource _documentLoader]->parsedArchiveData(); 224 NSData *nsData = parsedArchiveData ? parsedArchiveData->createNSData() : nil; 225 NSString *result = [[NSString alloc] initWithData:nsData encoding:NSUTF8StringEncoding]; 226 [nsData release]; 227 return [result autorelease]; 228 } 229 230 Frame* coreFrame = core([_private->dataSource webFrame]); 231 if (!coreFrame) 232 return nil; 233 Document* document = coreFrame->document(); 234 if (!document) 235 return nil; 236 TextResourceDecoder* decoder = document->decoder(); 237 if (!decoder) 238 return nil; 239 NSData *data = [_private->dataSource data]; 240 if (!data) 241 return nil; 242 return decoder->encoding().decode(reinterpret_cast<const char*>([data bytes]), [data length]); 243} 244 245- (NSString *)title 246{ 247 return nsStringNilIfEmpty([_private->dataSource _documentLoader]->title()); 248} 249 250- (DOMDocument *)DOMDocument 251{ 252 return [[_private->dataSource webFrame] DOMDocument]; 253} 254 255- (NSAttributedString *)attributedText 256{ 257 // FIXME: Implement 258 return nil; 259} 260 261- (NSAttributedString *)attributedStringFrom:(DOMNode *)startNode startOffset:(int)startOffset to:(DOMNode *)endNode endOffset:(int)endOffset 262{ 263 return [NSAttributedString _web_attributedStringFromRange:Range::create(core(startNode)->document(), core(startNode), startOffset, core(endNode), endOffset).get()]; 264} 265 266static HTMLFormElement* formElementFromDOMElement(DOMElement *element) 267{ 268 Element* node = core(element); 269 return node && node->hasTagName(formTag) ? static_cast<HTMLFormElement*>(node) : 0; 270} 271 272- (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form 273{ 274 HTMLFormElement* formElement = formElementFromDOMElement(form); 275 if (!formElement) 276 return nil; 277 Vector<HTMLFormControlElement*>& elements = formElement->formElements; 278 AtomicString targetName = name; 279 for (unsigned i = 0; i < elements.size(); i++) { 280 HTMLFormControlElement* elt = elements[i]; 281 if (elt->formControlName() == targetName) 282 return kit(elt); 283 } 284 return nil; 285} 286 287static HTMLInputElement* inputElementFromDOMElement(DOMElement* element) 288{ 289 Element* node = core(element); 290 return node && node->hasTagName(inputTag) ? static_cast<HTMLInputElement*>(node) : 0; 291} 292 293- (BOOL)elementDoesAutoComplete:(DOMElement *)element 294{ 295 HTMLInputElement* inputElement = inputElementFromDOMElement(element); 296 return inputElement 297 && inputElement->inputType() == HTMLInputElement::TEXT 298 && inputElement->autoComplete(); 299} 300 301- (BOOL)elementIsPassword:(DOMElement *)element 302{ 303 HTMLInputElement* inputElement = inputElementFromDOMElement(element); 304 return inputElement 305 && inputElement->inputType() == HTMLInputElement::PASSWORD; 306} 307 308- (DOMElement *)formForElement:(DOMElement *)element 309{ 310 HTMLInputElement* inputElement = inputElementFromDOMElement(element); 311 return inputElement ? kit(inputElement->form()) : 0; 312} 313 314- (DOMElement *)currentForm 315{ 316 return kit(core([_private->dataSource webFrame])->currentForm()); 317} 318 319- (NSArray *)controlsInForm:(DOMElement *)form 320{ 321 HTMLFormElement* formElement = formElementFromDOMElement(form); 322 if (!formElement) 323 return nil; 324 NSMutableArray *results = nil; 325 Vector<HTMLFormControlElement*>& elements = formElement->formElements; 326 for (unsigned i = 0; i < elements.size(); i++) { 327 if (elements[i]->isEnumeratable()) { // Skip option elements, other duds 328 DOMElement* de = kit(elements[i]); 329 if (!results) 330 results = [NSMutableArray arrayWithObject:de]; 331 else 332 [results addObject:de]; 333 } 334 } 335 return results; 336} 337 338- (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element 339{ 340 return core([_private->dataSource webFrame])->searchForLabelsBeforeElement(labels, core(element)); 341} 342 343- (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element 344{ 345 return core([_private->dataSource webFrame])->matchLabelsAgainstElement(labels, core(element)); 346} 347 348@end 349