• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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