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