initial import
[vuplus_webkit] / Source / WebKit / mac / WebView / WebHTMLRepresentation.mm
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
62 using namespace WebCore;
63 using 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
82 static 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
91 static 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 mainFrame] == webFrame && [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
283 static 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
304 static 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->shouldAutocomplete();
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