WebCore:
[WebKit-https.git] / 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 "DOMNodeInternal.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 "WebResourcePrivate.h"
43 #import "WebView.h"
44 #import <Foundation/NSURLResponse.h>
45 #import <JavaScriptCore/Assertions.h>
46 #import <WebCore/Document.h>
47 #import <WebCore/DocumentLoader.h>
48 #import <WebCore/Frame.h>
49 #import <WebCore/FrameLoader.h>
50 #import <WebCore/MIMETypeRegistry.h>
51 #import <WebCore/Range.h>
52
53 using namespace WebCore;
54
55 @interface WebHTMLRepresentationPrivate : NSObject {
56 @public
57     WebDataSource *dataSource;
58     NSData *parsedArchiveData;
59     
60     BOOL hasSentResponseToPlugin;
61     id <WebPluginManualLoader> manualLoader;
62     NSView *pluginView;
63 }
64 @end
65
66 @implementation WebHTMLRepresentationPrivate
67
68 - (void)dealloc
69 {
70     [parsedArchiveData release];
71     [super dealloc];
72 }
73
74 @end
75
76 @implementation WebHTMLRepresentation
77
78 static 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
87 static 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     static RetainPtr<NSArray> staticSupportedMIMETypes =
97         concatenateArrays([self supportedNonImageMIMETypes], [self supportedImageMIMETypes]);
98     return staticSupportedMIMETypes.get();
99 }
100
101 + (NSArray *)supportedNonImageMIMETypes
102 {
103     static RetainPtr<NSArray> staticSupportedNonImageMIMETypes =
104         stringArray(MIMETypeRegistry::getSupportedNonImageMIMETypes());
105     return staticSupportedNonImageMIMETypes.get();
106 }
107
108 + (NSArray *)supportedImageMIMETypes
109 {
110     static RetainPtr<NSArray> staticSupportedImageMIMETypes =
111         stringArray(MIMETypeRegistry::getSupportedImageMIMETypes());
112     return staticSupportedImageMIMETypes.get();
113 }
114
115 - init
116 {
117     self = [super init];
118     if (!self)
119         return nil;
120     
121     _private = [[WebHTMLRepresentationPrivate alloc] init];
122     
123     ++WebHTMLRepresentationCount;
124     
125     return self;
126 }
127
128 - (void)dealloc
129 {
130     --WebHTMLRepresentationCount;
131     
132     [_private release];
133
134     [super dealloc];
135 }
136
137 - (void)finalize
138 {
139     --WebHTMLRepresentationCount;
140
141     [super finalize];
142 }
143
144 - (void)_redirectDataToManualLoader:(id<WebPluginManualLoader>)manualLoader forPluginView:(NSView *)pluginView;
145 {
146     _private->manualLoader = manualLoader;
147     _private->pluginView = pluginView;
148 }
149
150 - (void)setDataSource:(WebDataSource *)dataSource
151 {
152     _private->dataSource = dataSource;
153 }
154
155 - (BOOL)_isDisplayingWebArchive
156 {
157     return [[[_private->dataSource response] MIMEType] _webkit_isCaseInsensitiveEqualToString:@"application/x-webarchive"];
158 }
159
160 - (void)receivedData:(NSData *)data withDataSource:(WebDataSource *)dataSource
161 {
162     WebFrame *frame = [dataSource webFrame];
163     if (frame && ![self _isDisplayingWebArchive]) {
164         if (!_private->pluginView)
165             [frame _receivedData:data textEncodingName:[[_private->dataSource response] textEncodingName]];
166
167         if (_private->pluginView) {
168             if (!_private->hasSentResponseToPlugin) {
169                 [_private->manualLoader pluginView:_private->pluginView receivedResponse:[dataSource response]];
170                 _private->hasSentResponseToPlugin = YES;
171             }
172             
173             [_private->manualLoader pluginView:_private->pluginView receivedData:data];
174         }
175     }
176 }
177
178 - (void)receivedError:(NSError *)error withDataSource:(WebDataSource *)dataSource
179 {
180     if (_private->pluginView) {
181         [_private->manualLoader pluginView:_private->pluginView receivedError:error];
182     }
183 }
184
185 - (void)_loadDataSourceAsWebArchive
186 {
187     WebArchive *archive = [[WebArchive alloc] initWithData:[_private->dataSource data]];
188     WebResource *mainResource = [archive mainResource];
189     if (!mainResource) {
190         [archive release];
191         return;
192     }
193     
194     NSData *data = [mainResource data];
195     [data retain];
196     [_private->parsedArchiveData release];
197     _private->parsedArchiveData = data;
198     
199     [_private->dataSource _addToUnarchiveState:archive];
200     [archive release];
201     
202     WebFrame *webFrame = [_private->dataSource webFrame];
203     
204     if (!webFrame)
205         return;
206     
207     core(webFrame)->loader()->continueLoadWithData(SharedBuffer::wrapNSData(data).get(), [mainResource MIMEType], [mainResource textEncodingName], [mainResource URL]);
208 }
209
210 - (void)finishedLoadingWithDataSource:(WebDataSource *)dataSource
211 {
212     WebFrame *frame = [dataSource webFrame];
213
214     if (_private->pluginView) {
215         [_private->manualLoader pluginViewFinishedLoading:_private->pluginView];
216         return;
217     }
218
219     if (frame) {
220         if ([self _isDisplayingWebArchive])
221             [self _loadDataSourceAsWebArchive];
222         else {
223             // Telling the frame we received some data and passing nil as the data is our
224             // way to get work done that is normally done when the first bit of data is
225             // received, even for the case of a document with no data (like about:blank).
226             [frame _receivedData:nil textEncodingName:[[_private->dataSource response] textEncodingName]];
227         }
228         
229         WebView *webView = [frame webView];
230         if ([webView isEditable])
231             core(frame)->applyEditingStyleToBodyElement();
232     }
233 }
234
235 - (BOOL)canProvideDocumentSource
236 {
237     return [[_private->dataSource webFrame] _canProvideDocumentSource];
238 }
239
240 - (BOOL)canSaveAsWebArchive
241 {
242     return [[_private->dataSource webFrame] _canSaveAsWebArchive];
243 }
244
245 - (NSString *)documentSource
246 {
247     if ([self _isDisplayingWebArchive])
248         return [[[NSString alloc] initWithData:_private->parsedArchiveData encoding:NSUTF8StringEncoding] autorelease]; 
249
250     return [[_private->dataSource webFrame] _stringWithData:[_private->dataSource data]];
251 }
252
253 - (NSString *)title
254 {
255     return nsStringNilIfEmpty([_private->dataSource _documentLoader]->title());
256 }
257
258 - (DOMDocument *)DOMDocument
259 {
260     return [[_private->dataSource webFrame] DOMDocument];
261 }
262
263 - (NSAttributedString *)attributedText
264 {
265     // FIXME: Implement
266     return nil;
267 }
268
269 - (NSAttributedString *)attributedStringFrom:(DOMNode *)startNode startOffset:(int)startOffset to:(DOMNode *)endNode endOffset:(int)endOffset
270 {
271     return [NSAttributedString _web_attributedStringFromRange:Range::create([startNode _node]->document(), [startNode _node], startOffset, [endNode _node], endOffset).get()];
272 }
273
274 - (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form
275 {
276     return [[_private->dataSource webFrame] _elementWithName:name inForm:form];
277 }
278
279 - (BOOL)elementDoesAutoComplete:(DOMElement *)element
280 {
281     return [[_private->dataSource webFrame] _elementDoesAutoComplete:element];
282 }
283
284 - (BOOL)elementIsPassword:(DOMElement *)element
285 {
286     return [[_private->dataSource webFrame] _elementIsPassword:element];
287 }
288
289 - (DOMElement *)formForElement:(DOMElement *)element
290 {
291     return [[_private->dataSource webFrame] _formForElement:element];
292 }
293
294 - (DOMElement *)currentForm
295 {
296     return [[_private->dataSource webFrame] _currentForm];
297 }
298
299 - (NSArray *)controlsInForm:(DOMElement *)form
300 {
301     return [[_private->dataSource webFrame] _controlsInForm:form];
302 }
303
304 - (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element
305 {
306     return [[_private->dataSource webFrame] _searchForLabels:labels beforeElement:element];
307 }
308
309 - (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element
310 {
311     return [[_private->dataSource webFrame] _matchLabels:labels againstElement:element];
312 }
313
314 @end