/* * 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 "WebHTMLRepresentation.h" #import "DOMElementInternal.h" #import "DOMNodeInternal.h" #import "DOMRangeInternal.h" #import "WebArchive.h" #import "WebBasePluginPackage.h" #import "WebDataSourceInternal.h" #import "WebDocumentPrivate.h" #import "WebFrameInternal.h" #import "WebKitNSStringExtras.h" #import "WebKitStatisticsPrivate.h" #import "WebNSAttributedStringExtras.h" #import "WebNSObjectExtras.h" #import "WebTypesInternal.h" #import "WebView.h" #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import using namespace WebCore; using namespace HTMLNames; @interface WebHTMLRepresentationPrivate : NSObject { @public WebDataSource *dataSource; BOOL hasSentResponseToPlugin; BOOL includedInWebKitStatistics; id manualLoader; NSView *pluginView; } @end @implementation WebHTMLRepresentationPrivate @end @implementation WebHTMLRepresentation static NSArray *stringArray(const HashSet& set) { NSMutableArray *array = [NSMutableArray arrayWithCapacity:set.size()]; HashSet::const_iterator end = set.end(); for (HashSet::const_iterator it = set.begin(); it != end; ++it) [array addObject:(NSString *)(*it)]; return array; } static NSArray *concatenateArrays(NSArray *first, NSArray *second) { NSMutableArray *result = [[first mutableCopy] autorelease]; [result addObjectsFromArray:second]; return result; } + (NSArray *)supportedMIMETypes { DEFINE_STATIC_LOCAL(RetainPtr, staticSupportedMIMETypes, (concatenateArrays([self supportedNonImageMIMETypes], [self supportedImageMIMETypes]))); return staticSupportedMIMETypes.get(); } + (NSArray *)supportedNonImageMIMETypes { DEFINE_STATIC_LOCAL(RetainPtr, staticSupportedNonImageMIMETypes, (stringArray(MIMETypeRegistry::getSupportedNonImageMIMETypes()))); return staticSupportedNonImageMIMETypes.get(); } + (NSArray *)supportedImageMIMETypes { DEFINE_STATIC_LOCAL(RetainPtr, staticSupportedImageMIMETypes, (stringArray(MIMETypeRegistry::getSupportedImageMIMETypes()))); return staticSupportedImageMIMETypes.get(); } - (id)init { self = [super init]; if (!self) return nil; _private = [[WebHTMLRepresentationPrivate alloc] init]; return self; } - (void)dealloc { if (_private && _private->includedInWebKitStatistics) --WebHTMLRepresentationCount; [_private release]; [super dealloc]; } - (void)finalize { if (_private && _private->includedInWebKitStatistics) --WebHTMLRepresentationCount; [super finalize]; } - (void)_redirectDataToManualLoader:(id)manualLoader forPluginView:(NSView *)pluginView { _private->manualLoader = manualLoader; _private->pluginView = pluginView; } - (void)setDataSource:(WebDataSource *)dataSource { _private->dataSource = dataSource; if (!_private->includedInWebKitStatistics && [[dataSource webFrame] _isIncludedInWebKitStatistics]) { _private->includedInWebKitStatistics = YES; ++WebHTMLRepresentationCount; } } - (BOOL)_isDisplayingWebArchive { return [[_private->dataSource _responseMIMEType] _webkit_isCaseInsensitiveEqualToString:@"application/x-webarchive"]; } - (void)receivedData:(NSData *)data withDataSource:(WebDataSource *)dataSource { WebFrame *webFrame = [dataSource webFrame]; if (!webFrame) return; if (!_private->pluginView) [webFrame _commitData:data]; // If the document is a stand-alone media document, now is the right time to cancel the WebKit load Frame* coreFrame = core(webFrame); if (coreFrame->document()->isMediaDocument()) coreFrame->loader()->documentLoader()->cancelMainResourceLoad(coreFrame->loader()->client()->pluginWillHandleLoadError(coreFrame->loader()->documentLoader()->response())); if (_private->pluginView) { if (!_private->hasSentResponseToPlugin) { [_private->manualLoader pluginView:_private->pluginView receivedResponse:[dataSource response]]; _private->hasSentResponseToPlugin = YES; } [_private->manualLoader pluginView:_private->pluginView receivedData:data]; } } - (void)receivedError:(NSError *)error withDataSource:(WebDataSource *)dataSource { if (_private->pluginView) { [_private->manualLoader pluginView:_private->pluginView receivedError:error]; } } - (void)finishedLoadingWithDataSource:(WebDataSource *)dataSource { WebFrame* webFrame = [dataSource webFrame]; if (_private->pluginView) { [_private->manualLoader pluginViewFinishedLoading:_private->pluginView]; return; } if (!webFrame) return; if (![self _isDisplayingWebArchive]) { // Telling the frame we received some data and passing nil as the data is our // way to get work done that is normally done when the first bit of data is // received, even for the case of a document with no data (like about:blank). [webFrame _commitData:nil]; } WebView *webView = [webFrame webView]; if ([webView isEditable]) core(webFrame)->editor()->applyEditingStyleToBodyElement(); } - (BOOL)canProvideDocumentSource { return [[_private->dataSource webFrame] _canProvideDocumentSource]; } - (BOOL)canSaveAsWebArchive { return [[_private->dataSource webFrame] _canSaveAsWebArchive]; } - (NSString *)documentSource { if ([self _isDisplayingWebArchive]) { SharedBuffer *parsedArchiveData = [_private->dataSource _documentLoader]->parsedArchiveData(); NSData *nsData = parsedArchiveData ? parsedArchiveData->createNSData() : nil; NSString *result = [[NSString alloc] initWithData:nsData encoding:NSUTF8StringEncoding]; [nsData release]; return [result autorelease]; } Frame* coreFrame = core([_private->dataSource webFrame]); if (!coreFrame) return nil; Document* document = coreFrame->document(); if (!document) return nil; TextResourceDecoder* decoder = document->decoder(); if (!decoder) return nil; NSData *data = [_private->dataSource data]; if (!data) return nil; return decoder->encoding().decode(reinterpret_cast([data bytes]), [data length]); } - (NSString *)title { return nsStringNilIfEmpty([_private->dataSource _documentLoader]->title()); } - (DOMDocument *)DOMDocument { return [[_private->dataSource webFrame] DOMDocument]; } - (NSAttributedString *)attributedText { // FIXME: Implement return nil; } - (NSAttributedString *)attributedStringFrom:(DOMNode *)startNode startOffset:(int)startOffset to:(DOMNode *)endNode endOffset:(int)endOffset { return [NSAttributedString _web_attributedStringFromRange:Range::create(core(startNode)->document(), core(startNode), startOffset, core(endNode), endOffset).get()]; } static HTMLFormElement* formElementFromDOMElement(DOMElement *element) { Element* node = core(element); return node && node->hasTagName(formTag) ? static_cast(node) : 0; } - (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form { HTMLFormElement* formElement = formElementFromDOMElement(form); if (!formElement) return nil; const Vector& elements = formElement->associatedElements(); AtomicString targetName = name; for (unsigned i = 0; i < elements.size(); i++) { FormAssociatedElement* elt = elements[i]; if (elt->name() == targetName) return kit(toHTMLElement(elt)); } return nil; } static HTMLInputElement* inputElementFromDOMElement(DOMElement* element) { Element* node = core(element); return node && node->hasTagName(inputTag) ? static_cast(node) : 0; } - (BOOL)elementDoesAutoComplete:(DOMElement *)element { HTMLInputElement* inputElement = inputElementFromDOMElement(element); return inputElement && inputElement->isTextField() && !inputElement->isPasswordField() && inputElement->autoComplete(); } - (BOOL)elementIsPassword:(DOMElement *)element { HTMLInputElement* inputElement = inputElementFromDOMElement(element); return inputElement && inputElement->isPasswordField(); } - (DOMElement *)formForElement:(DOMElement *)element { HTMLInputElement* inputElement = inputElementFromDOMElement(element); return inputElement ? kit(inputElement->form()) : 0; } - (DOMElement *)currentForm { return kit(core([_private->dataSource webFrame])->selection()->currentForm()); } - (NSArray *)controlsInForm:(DOMElement *)form { HTMLFormElement* formElement = formElementFromDOMElement(form); if (!formElement) return nil; NSMutableArray *results = nil; const Vector& elements = formElement->associatedElements(); for (unsigned i = 0; i < elements.size(); i++) { if (elements[i]->isEnumeratable()) { // Skip option elements, other duds DOMElement* de = kit(toHTMLElement(elements[i])); if (!results) results = [NSMutableArray arrayWithObject:de]; else [results addObject:de]; } } return results; } - (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element { return [self searchForLabels:labels beforeElement:element resultDistance:0 resultIsInCellAbove:0]; } - (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element resultDistance:(NSUInteger*)outDistance resultIsInCellAbove:(BOOL*)outIsInCellAbove { size_t distance; bool isInCellAbove; NSString *result = core([_private->dataSource webFrame])->searchForLabelsBeforeElement(labels, core(element), &distance, &isInCellAbove); if (outDistance) { if (distance == notFound) *outDistance = NSNotFound; else *outDistance = distance; } if (outIsInCellAbove) *outIsInCellAbove = isInCellAbove; return result; } - (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element { return core([_private->dataSource webFrame])->matchLabelsAgainstElement(labels, core(element)); } @end