Foo::s_info should be Foo::info(), so that you can change how the s_info is actually...
[WebKit-https.git] / Source / WebCore / bindings / objc / DOM.mm
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 James G. Speth (speth@end.com)
4  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #import "config.h"
29 #import "DOMInternal.h" // import first to make the private/public trick work
30 #import "DOM.h"
31
32 #import "CachedImage.h"
33 #import "DOMElementInternal.h"
34 #import "DOMHTMLCanvasElement.h"
35 #import "DOMHTMLTableCellElementInternal.h"
36 #import "DOMNodeInternal.h"
37 #import "DOMPrivate.h"
38 #import "DOMRangeInternal.h"
39 #import "Font.h"
40 #import "Frame.h"
41 #import "FrameSnapshottingMac.h"
42 #import "HTMLElement.h"
43 #import "HTMLNames.h"
44 #import "HTMLParserIdioms.h"
45 #import "HTMLTableCellElement.h"
46 #import "Image.h"
47 #import "JSNode.h"
48 #import "NodeFilter.h"
49 #import "Range.h"
50 #import "RenderImage.h"
51 #import "ScriptController.h"
52 #import "WebScriptObjectPrivate.h"
53 #import <JavaScriptCore/APICast.h>
54 #import <wtf/HashMap.h>
55
56 using namespace JSC;
57 using namespace WebCore;
58
59 // FIXME: Would be nice to break this up into separate files to match how other WebKit
60 // code is organized.
61
62 //------------------------------------------------------------------------------------------
63 // DOMNode
64
65 namespace WebCore {
66
67 typedef HashMap<const QualifiedName::QualifiedNameImpl*, Class> ObjCClassMap;
68 static ObjCClassMap* elementClassMap;
69
70 static void addElementClass(const QualifiedName& tag, Class objCClass)
71 {
72     elementClassMap->set(tag.impl(), objCClass);
73 }
74
75 static void createElementClassMap()
76 {
77     // Create the table.
78     elementClassMap = new ObjCClassMap;
79
80     // FIXME: Reflect marquee once the API has been determined.
81
82     // Populate it with HTML and SVG element classes.
83     addElementClass(HTMLNames::aTag, [DOMHTMLAnchorElement class]);
84     addElementClass(HTMLNames::appletTag, [DOMHTMLAppletElement class]);
85     addElementClass(HTMLNames::areaTag, [DOMHTMLAreaElement class]);
86     addElementClass(HTMLNames::baseTag, [DOMHTMLBaseElement class]);
87     addElementClass(HTMLNames::basefontTag, [DOMHTMLBaseFontElement class]);
88     addElementClass(HTMLNames::bodyTag, [DOMHTMLBodyElement class]);
89     addElementClass(HTMLNames::brTag, [DOMHTMLBRElement class]);
90     addElementClass(HTMLNames::buttonTag, [DOMHTMLButtonElement class]);
91     addElementClass(HTMLNames::canvasTag, [DOMHTMLCanvasElement class]);
92     addElementClass(HTMLNames::captionTag, [DOMHTMLTableCaptionElement class]);
93     addElementClass(HTMLNames::colTag, [DOMHTMLTableColElement class]);
94     addElementClass(HTMLNames::colgroupTag, [DOMHTMLTableColElement class]);
95     addElementClass(HTMLNames::delTag, [DOMHTMLModElement class]);
96     addElementClass(HTMLNames::dirTag, [DOMHTMLDirectoryElement class]);
97     addElementClass(HTMLNames::divTag, [DOMHTMLDivElement class]);
98     addElementClass(HTMLNames::dlTag, [DOMHTMLDListElement class]);
99     addElementClass(HTMLNames::embedTag, [DOMHTMLEmbedElement class]);
100     addElementClass(HTMLNames::fieldsetTag, [DOMHTMLFieldSetElement class]);
101     addElementClass(HTMLNames::fontTag, [DOMHTMLFontElement class]);
102     addElementClass(HTMLNames::formTag, [DOMHTMLFormElement class]);
103     addElementClass(HTMLNames::frameTag, [DOMHTMLFrameElement class]);
104     addElementClass(HTMLNames::framesetTag, [DOMHTMLFrameSetElement class]);
105     addElementClass(HTMLNames::h1Tag, [DOMHTMLHeadingElement class]);
106     addElementClass(HTMLNames::h2Tag, [DOMHTMLHeadingElement class]);
107     addElementClass(HTMLNames::h3Tag, [DOMHTMLHeadingElement class]);
108     addElementClass(HTMLNames::h4Tag, [DOMHTMLHeadingElement class]);
109     addElementClass(HTMLNames::h5Tag, [DOMHTMLHeadingElement class]);
110     addElementClass(HTMLNames::h6Tag, [DOMHTMLHeadingElement class]);
111     addElementClass(HTMLNames::headTag, [DOMHTMLHeadElement class]);
112     addElementClass(HTMLNames::hrTag, [DOMHTMLHRElement class]);
113     addElementClass(HTMLNames::htmlTag, [DOMHTMLHtmlElement class]);
114     addElementClass(HTMLNames::iframeTag, [DOMHTMLIFrameElement class]);
115     addElementClass(HTMLNames::imgTag, [DOMHTMLImageElement class]);
116     addElementClass(HTMLNames::inputTag, [DOMHTMLInputElement class]);
117     addElementClass(HTMLNames::insTag, [DOMHTMLModElement class]);
118     addElementClass(HTMLNames::labelTag, [DOMHTMLLabelElement class]);
119     addElementClass(HTMLNames::legendTag, [DOMHTMLLegendElement class]);
120     addElementClass(HTMLNames::liTag, [DOMHTMLLIElement class]);
121     addElementClass(HTMLNames::linkTag, [DOMHTMLLinkElement class]);
122     addElementClass(HTMLNames::listingTag, [DOMHTMLPreElement class]);
123     addElementClass(HTMLNames::mapTag, [DOMHTMLMapElement class]);
124     addElementClass(HTMLNames::marqueeTag, [DOMHTMLMarqueeElement class]);
125     addElementClass(HTMLNames::menuTag, [DOMHTMLMenuElement class]);
126     addElementClass(HTMLNames::metaTag, [DOMHTMLMetaElement class]);
127     addElementClass(HTMLNames::objectTag, [DOMHTMLObjectElement class]);
128     addElementClass(HTMLNames::olTag, [DOMHTMLOListElement class]);
129     addElementClass(HTMLNames::optgroupTag, [DOMHTMLOptGroupElement class]);
130     addElementClass(HTMLNames::optionTag, [DOMHTMLOptionElement class]);
131     addElementClass(HTMLNames::pTag, [DOMHTMLParagraphElement class]);
132     addElementClass(HTMLNames::paramTag, [DOMHTMLParamElement class]);
133     addElementClass(HTMLNames::preTag, [DOMHTMLPreElement class]);
134     addElementClass(HTMLNames::qTag, [DOMHTMLQuoteElement class]);
135     addElementClass(HTMLNames::scriptTag, [DOMHTMLScriptElement class]);
136     addElementClass(HTMLNames::selectTag, [DOMHTMLSelectElement class]);
137     addElementClass(HTMLNames::styleTag, [DOMHTMLStyleElement class]);
138     addElementClass(HTMLNames::tableTag, [DOMHTMLTableElement class]);
139     addElementClass(HTMLNames::tbodyTag, [DOMHTMLTableSectionElement class]);
140     addElementClass(HTMLNames::tdTag, [DOMHTMLTableCellElement class]);
141     addElementClass(HTMLNames::textareaTag, [DOMHTMLTextAreaElement class]);
142     addElementClass(HTMLNames::tfootTag, [DOMHTMLTableSectionElement class]);
143     addElementClass(HTMLNames::thTag, [DOMHTMLTableCellElement class]);
144     addElementClass(HTMLNames::theadTag, [DOMHTMLTableSectionElement class]);
145     addElementClass(HTMLNames::titleTag, [DOMHTMLTitleElement class]);
146     addElementClass(HTMLNames::trTag, [DOMHTMLTableRowElement class]);
147     addElementClass(HTMLNames::ulTag, [DOMHTMLUListElement class]);
148     addElementClass(HTMLNames::xmpTag, [DOMHTMLPreElement class]);
149 }
150
151 static Class lookupElementClass(const QualifiedName& tag)
152 {
153     // Do a special lookup to ignore element prefixes
154     if (tag.hasPrefix())
155         return elementClassMap->get(QualifiedName(nullAtom, tag.localName(), tag.namespaceURI()).impl());
156     
157     return elementClassMap->get(tag.impl());
158 }
159
160 static Class elementClass(const QualifiedName& tag, Class defaultClass)
161 {
162     if (!elementClassMap)
163         createElementClassMap();
164     Class objcClass = lookupElementClass(tag);
165     if (!objcClass)
166         objcClass = defaultClass;
167     return objcClass;
168 }
169
170 static NSArray *kit(const Vector<IntRect>& rects)
171 {
172     size_t size = rects.size();
173     NSMutableArray *array = [NSMutableArray arrayWithCapacity:size];
174     for (size_t i = 0; i < size; ++i)
175         [array addObject:[NSValue valueWithRect:rects[i]]];
176     return array;
177 }
178
179 } // namespace WebCore
180
181 @implementation DOMNode (WebCoreInternal)
182
183 - (NSString *)description
184 {
185     if (!_internal)
186         return [NSString stringWithFormat:@"<%@: null>", [[self class] description]];
187
188     NSString *value = [self nodeValue];
189     if (value)
190         return [NSString stringWithFormat:@"<%@ [%@]: %p '%@'>",
191             [[self class] description], [self nodeName], _internal, value];
192
193     return [NSString stringWithFormat:@"<%@ [%@]: %p>", [[self class] description], [self nodeName], _internal];
194 }
195
196 - (JSC::Bindings::RootObject*)_rootObject
197 {
198     WebCore::Frame* frame = core(self)->document()->frame();
199     if (!frame)
200         return 0;
201     return frame->script()->bindingRootObject();
202 }
203
204 @end
205
206 Class kitClass(WebCore::Node* impl)
207 {
208     switch (impl->nodeType()) {
209         case WebCore::Node::ELEMENT_NODE:
210             if (impl->isHTMLElement())
211                 return WebCore::elementClass(toHTMLElement(impl)->tagQName(), [DOMHTMLElement class]);
212             return [DOMElement class];
213         case WebCore::Node::ATTRIBUTE_NODE:
214             return [DOMAttr class];
215         case WebCore::Node::TEXT_NODE:
216             return [DOMText class];
217         case WebCore::Node::CDATA_SECTION_NODE:
218             return [DOMCDATASection class];
219         case WebCore::Node::ENTITY_REFERENCE_NODE:
220             return [DOMEntityReference class];
221         case WebCore::Node::ENTITY_NODE:
222             return [DOMEntity class];
223         case WebCore::Node::PROCESSING_INSTRUCTION_NODE:
224             return [DOMProcessingInstruction class];
225         case WebCore::Node::COMMENT_NODE:
226             return [DOMComment class];
227         case WebCore::Node::DOCUMENT_NODE:
228             if (static_cast<WebCore::Document*>(impl)->isHTMLDocument())
229                 return [DOMHTMLDocument class];
230             return [DOMDocument class];
231         case WebCore::Node::DOCUMENT_TYPE_NODE:
232             return [DOMDocumentType class];
233         case WebCore::Node::DOCUMENT_FRAGMENT_NODE:
234             return [DOMDocumentFragment class];
235         case WebCore::Node::NOTATION_NODE:
236             return [DOMNotation class];
237         case WebCore::Node::XPATH_NAMESPACE_NODE:
238             // FIXME: Create an XPath objective C wrapper
239             // See http://bugs.webkit.org/show_bug.cgi?id=8755
240             return nil;
241     }
242     ASSERT_NOT_REACHED();
243     return nil;
244 }
245
246 id <DOMEventTarget> kit(WebCore::EventTarget* eventTarget)
247 {
248     if (!eventTarget)
249         return nil;
250
251     if (WebCore::Node* node = eventTarget->toNode())
252         return kit(node);
253
254     // We don't have an ObjC binding for XMLHttpRequest.
255
256     return nil;
257 }
258
259 @implementation DOMNode (DOMNodeExtensions)
260
261 - (NSRect)boundingBox
262 {
263     // FIXME: Could we move this function to WebCore::Node and autogenerate?
264     core(self)->document()->updateLayoutIgnorePendingStylesheets();
265     WebCore::RenderObject* renderer = core(self)->renderer();
266     if (!renderer)
267         return NSZeroRect;
268     return renderer->absoluteBoundingBoxRect();
269 }
270
271 - (NSArray *)lineBoxRects
272 {
273     return [self textRects];
274 }
275
276 @end
277
278 @implementation DOMNode (DOMNodeExtensionsPendingPublic)
279
280 - (NSImage *)renderedImage
281 {
282     // FIXME: Could we move this function to WebCore::Node and autogenerate?
283     WebCore::Node* node = core(self);
284     WebCore::Frame* frame = node->document()->frame();
285     if (!frame)
286         return nil;
287     return frame->nodeImage(node).get();
288 }
289
290 - (NSArray *)textRects
291 {
292     core(self)->document()->updateLayoutIgnorePendingStylesheets();
293     if (!core(self)->renderer())
294         return nil;
295     Vector<WebCore::IntRect> rects;
296     core(self)->textRects(rects);
297     return kit(rects);
298 }
299
300 @end
301
302 @implementation DOMNode (WebPrivate)
303
304 + (id)_nodeFromJSWrapper:(JSObjectRef)jsWrapper
305 {
306     JSObject* object = toJS(jsWrapper);
307
308     if (!object->inherits(JSNode::info()))
309         return nil;
310
311     WebCore::Node* node = jsCast<JSNode*>(object)->impl();
312     return kit(node);
313 }
314
315 @end
316
317 @implementation DOMRange (DOMRangeExtensions)
318
319 - (NSRect)boundingBox
320 {
321     // FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
322     core(self)->ownerDocument()->updateLayoutIgnorePendingStylesheets();
323     return core(self)->boundingBox();
324 }
325
326 - (NSImage *)renderedImageForcingBlackText:(BOOL)forceBlackText
327 {
328     WebCore::Range* range = core(self);
329     WebCore::Frame* frame = range->ownerDocument()->frame();
330     if (!frame)
331         return nil;
332
333     return WebCore::rangeImage(frame, range, forceBlackText);
334 }
335
336 - (NSArray *)textRects
337 {
338     // FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
339     Vector<WebCore::IntRect> rects;
340     core(self)->ownerDocument()->updateLayoutIgnorePendingStylesheets();
341     core(self)->textRects(rects);
342     return kit(rects);
343 }
344
345 - (NSArray *)lineBoxRects
346 {
347     // FIXME: Remove this once all clients stop using it and we drop Leopard support.
348     return [self textRects];
349 }
350
351 @end
352
353 //------------------------------------------------------------------------------------------
354 // DOMElement
355
356 @implementation DOMElement (DOMElementAppKitExtensions)
357
358 - (NSImage*)image
359 {
360     // FIXME: Could we move this function to WebCore::Node and autogenerate?
361     WebCore::RenderObject* renderer = core(self)->renderer();
362     if (!renderer || !renderer->isImage())
363         return nil;
364     WebCore::CachedImage* cachedImage = static_cast<WebCore::RenderImage*>(renderer)->cachedImage();
365     if (!cachedImage || cachedImage->errorOccurred())
366         return nil;
367     return cachedImage->imageForRenderer(renderer)->getNSImage();
368 }
369
370 @end
371
372 @implementation DOMElement (WebPrivate)
373
374 - (NSFont *)_font
375 {
376     // FIXME: Could we move this function to WebCore::Element and autogenerate?
377     WebCore::RenderObject* renderer = core(self)->renderer();
378     if (!renderer)
379         return nil;
380     return renderer->style()->font().primaryFont()->getNSFont();
381 }
382
383 - (NSData *)_imageTIFFRepresentation
384 {
385     // FIXME: Could we move this function to WebCore::Element and autogenerate?
386     WebCore::RenderObject* renderer = core(self)->renderer();
387     if (!renderer || !renderer->isImage())
388         return nil;
389     WebCore::CachedImage* cachedImage = static_cast<WebCore::RenderImage*>(renderer)->cachedImage();
390     if (!cachedImage || cachedImage->errorOccurred())
391         return nil;
392     return (NSData *)cachedImage->imageForRenderer(renderer)->getTIFFRepresentation();
393 }
394
395 - (NSURL *)_getURLAttribute:(NSString *)name
396 {
397     // FIXME: Could we move this function to WebCore::Element and autogenerate?
398     ASSERT(name);
399     WebCore::Element* element = core(self);
400     ASSERT(element);
401     return element->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(element->getAttribute(name)));
402 }
403
404 - (BOOL)isFocused
405 {
406     // FIXME: Could we move this function to WebCore::Element and autogenerate?
407     WebCore::Element* element = core(self);
408     return element->document()->focusedElement() == element;
409 }
410
411 @end
412
413 //------------------------------------------------------------------------------------------
414 // DOMRange
415
416 @implementation DOMRange (WebPrivate)
417
418 - (NSString *)description
419 {
420     if (!_internal)
421         return @"<DOMRange: null>";
422     return [NSString stringWithFormat:@"<DOMRange: %@ %d %@ %d>",
423                [self startContainer], [self startOffset], [self endContainer], [self endOffset]];
424 }
425
426 // FIXME: This should be removed as soon as all internal Apple uses of it have been replaced with
427 // calls to the public method - (NSString *)text.
428 - (NSString *)_text
429 {
430     return [self text];
431 }
432
433 @end
434
435 //------------------------------------------------------------------------------------------
436 // DOMRGBColor
437
438 @implementation DOMRGBColor (WebPrivate)
439
440 // FIXME: This should be removed as soon as all internal Apple uses of it have been replaced with
441 // calls to the public method - (NSColor *)color.
442 - (NSColor *)_color
443 {
444     return [self color];
445 }
446
447 @end
448
449
450 @implementation DOMHTMLTableCellElement (WebPrivate)
451
452 - (DOMHTMLTableCellElement *)_cellAbove
453 {
454     return kit(core(self)->cellAbove());
455 }
456
457 @end
458
459 //------------------------------------------------------------------------------------------
460 // DOMNodeFilter
461
462 DOMNodeFilter *kit(WebCore::NodeFilter* impl)
463 {
464     if (!impl)
465         return nil;
466     
467     if (DOMNodeFilter *wrapper = getDOMWrapper(impl))
468         return [[wrapper retain] autorelease];
469     
470     DOMNodeFilter *wrapper = [[DOMNodeFilter alloc] _init];
471     wrapper->_internal = reinterpret_cast<DOMObjectInternal*>(impl);
472     impl->ref();
473     addDOMWrapper(wrapper, impl);
474     return [wrapper autorelease];
475 }
476
477 WebCore::NodeFilter* core(DOMNodeFilter *wrapper)
478 {
479     return wrapper ? reinterpret_cast<WebCore::NodeFilter*>(wrapper->_internal) : 0;
480 }
481
482 @implementation DOMNodeFilter
483
484 - (void)dealloc
485 {
486     if (_internal)
487         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
488     [super dealloc];
489 }
490
491 - (void)finalize
492 {
493     if (_internal)
494         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
495     [super finalize];
496 }
497
498 - (short)acceptNode:(DOMNode *)node
499 {
500     return core(self)->acceptNode(core(node));
501 }
502
503 @end