DOM.mm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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. #import "config.h"
  28. #import "DOMInternal.h" // import first to make the private/public trick work
  29. #import "DOM.h"
  30. #import "CachedImage.h"
  31. #import "DOMElementInternal.h"
  32. #import "DOMHTMLCanvasElement.h"
  33. #import "DOMHTMLTableCellElementInternal.h"
  34. #import "DOMNodeInternal.h"
  35. #import "DOMPrivate.h"
  36. #import "DOMRangeInternal.h"
  37. #import "Font.h"
  38. #import "Frame.h"
  39. #import "FrameSnapshottingMac.h"
  40. #import "HTMLElement.h"
  41. #import "HTMLNames.h"
  42. #import "HTMLParserIdioms.h"
  43. #import "HTMLTableCellElement.h"
  44. #import "Image.h"
  45. #import "JSNode.h"
  46. #import "NodeFilter.h"
  47. #import "Range.h"
  48. #import "RenderImage.h"
  49. #import "ScriptController.h"
  50. #import "WebScriptObjectPrivate.h"
  51. #import <JavaScriptCore/APICast.h>
  52. #import <wtf/HashMap.h>
  53. using namespace JSC;
  54. using namespace WebCore;
  55. // FIXME: Would be nice to break this up into separate files to match how other WebKit
  56. // code is organized.
  57. //------------------------------------------------------------------------------------------
  58. // DOMNode
  59. namespace WebCore {
  60. typedef HashMap<const QualifiedName::QualifiedNameImpl*, Class> ObjCClassMap;
  61. static ObjCClassMap* elementClassMap;
  62. static void addElementClass(const QualifiedName& tag, Class objCClass)
  63. {
  64. elementClassMap->set(tag.impl(), objCClass);
  65. }
  66. static void createElementClassMap()
  67. {
  68. // Create the table.
  69. elementClassMap = new ObjCClassMap;
  70. // FIXME: Reflect marquee once the API has been determined.
  71. // Populate it with HTML and SVG element classes.
  72. addElementClass(HTMLNames::aTag, [DOMHTMLAnchorElement class]);
  73. addElementClass(HTMLNames::appletTag, [DOMHTMLAppletElement class]);
  74. addElementClass(HTMLNames::areaTag, [DOMHTMLAreaElement class]);
  75. addElementClass(HTMLNames::baseTag, [DOMHTMLBaseElement class]);
  76. addElementClass(HTMLNames::basefontTag, [DOMHTMLBaseFontElement class]);
  77. addElementClass(HTMLNames::bodyTag, [DOMHTMLBodyElement class]);
  78. addElementClass(HTMLNames::brTag, [DOMHTMLBRElement class]);
  79. addElementClass(HTMLNames::buttonTag, [DOMHTMLButtonElement class]);
  80. addElementClass(HTMLNames::canvasTag, [DOMHTMLCanvasElement class]);
  81. addElementClass(HTMLNames::captionTag, [DOMHTMLTableCaptionElement class]);
  82. addElementClass(HTMLNames::colTag, [DOMHTMLTableColElement class]);
  83. addElementClass(HTMLNames::colgroupTag, [DOMHTMLTableColElement class]);
  84. addElementClass(HTMLNames::delTag, [DOMHTMLModElement class]);
  85. addElementClass(HTMLNames::dirTag, [DOMHTMLDirectoryElement class]);
  86. addElementClass(HTMLNames::divTag, [DOMHTMLDivElement class]);
  87. addElementClass(HTMLNames::dlTag, [DOMHTMLDListElement class]);
  88. addElementClass(HTMLNames::embedTag, [DOMHTMLEmbedElement class]);
  89. addElementClass(HTMLNames::fieldsetTag, [DOMHTMLFieldSetElement class]);
  90. addElementClass(HTMLNames::fontTag, [DOMHTMLFontElement class]);
  91. addElementClass(HTMLNames::formTag, [DOMHTMLFormElement class]);
  92. addElementClass(HTMLNames::frameTag, [DOMHTMLFrameElement class]);
  93. addElementClass(HTMLNames::framesetTag, [DOMHTMLFrameSetElement class]);
  94. addElementClass(HTMLNames::h1Tag, [DOMHTMLHeadingElement class]);
  95. addElementClass(HTMLNames::h2Tag, [DOMHTMLHeadingElement class]);
  96. addElementClass(HTMLNames::h3Tag, [DOMHTMLHeadingElement class]);
  97. addElementClass(HTMLNames::h4Tag, [DOMHTMLHeadingElement class]);
  98. addElementClass(HTMLNames::h5Tag, [DOMHTMLHeadingElement class]);
  99. addElementClass(HTMLNames::h6Tag, [DOMHTMLHeadingElement class]);
  100. addElementClass(HTMLNames::headTag, [DOMHTMLHeadElement class]);
  101. addElementClass(HTMLNames::hrTag, [DOMHTMLHRElement class]);
  102. addElementClass(HTMLNames::htmlTag, [DOMHTMLHtmlElement class]);
  103. addElementClass(HTMLNames::iframeTag, [DOMHTMLIFrameElement class]);
  104. addElementClass(HTMLNames::imgTag, [DOMHTMLImageElement class]);
  105. addElementClass(HTMLNames::inputTag, [DOMHTMLInputElement class]);
  106. addElementClass(HTMLNames::insTag, [DOMHTMLModElement class]);
  107. addElementClass(HTMLNames::labelTag, [DOMHTMLLabelElement class]);
  108. addElementClass(HTMLNames::legendTag, [DOMHTMLLegendElement class]);
  109. addElementClass(HTMLNames::liTag, [DOMHTMLLIElement class]);
  110. addElementClass(HTMLNames::linkTag, [DOMHTMLLinkElement class]);
  111. addElementClass(HTMLNames::listingTag, [DOMHTMLPreElement class]);
  112. addElementClass(HTMLNames::mapTag, [DOMHTMLMapElement class]);
  113. addElementClass(HTMLNames::marqueeTag, [DOMHTMLMarqueeElement class]);
  114. addElementClass(HTMLNames::menuTag, [DOMHTMLMenuElement class]);
  115. addElementClass(HTMLNames::metaTag, [DOMHTMLMetaElement class]);
  116. addElementClass(HTMLNames::objectTag, [DOMHTMLObjectElement class]);
  117. addElementClass(HTMLNames::olTag, [DOMHTMLOListElement class]);
  118. addElementClass(HTMLNames::optgroupTag, [DOMHTMLOptGroupElement class]);
  119. addElementClass(HTMLNames::optionTag, [DOMHTMLOptionElement class]);
  120. addElementClass(HTMLNames::pTag, [DOMHTMLParagraphElement class]);
  121. addElementClass(HTMLNames::paramTag, [DOMHTMLParamElement class]);
  122. addElementClass(HTMLNames::preTag, [DOMHTMLPreElement class]);
  123. addElementClass(HTMLNames::qTag, [DOMHTMLQuoteElement class]);
  124. addElementClass(HTMLNames::scriptTag, [DOMHTMLScriptElement class]);
  125. addElementClass(HTMLNames::selectTag, [DOMHTMLSelectElement class]);
  126. addElementClass(HTMLNames::styleTag, [DOMHTMLStyleElement class]);
  127. addElementClass(HTMLNames::tableTag, [DOMHTMLTableElement class]);
  128. addElementClass(HTMLNames::tbodyTag, [DOMHTMLTableSectionElement class]);
  129. addElementClass(HTMLNames::tdTag, [DOMHTMLTableCellElement class]);
  130. addElementClass(HTMLNames::textareaTag, [DOMHTMLTextAreaElement class]);
  131. addElementClass(HTMLNames::tfootTag, [DOMHTMLTableSectionElement class]);
  132. addElementClass(HTMLNames::thTag, [DOMHTMLTableCellElement class]);
  133. addElementClass(HTMLNames::theadTag, [DOMHTMLTableSectionElement class]);
  134. addElementClass(HTMLNames::titleTag, [DOMHTMLTitleElement class]);
  135. addElementClass(HTMLNames::trTag, [DOMHTMLTableRowElement class]);
  136. addElementClass(HTMLNames::ulTag, [DOMHTMLUListElement class]);
  137. addElementClass(HTMLNames::xmpTag, [DOMHTMLPreElement class]);
  138. }
  139. static Class lookupElementClass(const QualifiedName& tag)
  140. {
  141. // Do a special lookup to ignore element prefixes
  142. if (tag.hasPrefix())
  143. return elementClassMap->get(QualifiedName(nullAtom, tag.localName(), tag.namespaceURI()).impl());
  144. return elementClassMap->get(tag.impl());
  145. }
  146. static Class elementClass(const QualifiedName& tag, Class defaultClass)
  147. {
  148. if (!elementClassMap)
  149. createElementClassMap();
  150. Class objcClass = lookupElementClass(tag);
  151. if (!objcClass)
  152. objcClass = defaultClass;
  153. return objcClass;
  154. }
  155. static NSArray *kit(const Vector<IntRect>& rects)
  156. {
  157. size_t size = rects.size();
  158. NSMutableArray *array = [NSMutableArray arrayWithCapacity:size];
  159. for (size_t i = 0; i < size; ++i)
  160. [array addObject:[NSValue valueWithRect:rects[i]]];
  161. return array;
  162. }
  163. } // namespace WebCore
  164. @implementation DOMNode (WebCoreInternal)
  165. - (NSString *)description
  166. {
  167. if (!_internal)
  168. return [NSString stringWithFormat:@"<%@: null>", [[self class] description]];
  169. NSString *value = [self nodeValue];
  170. if (value)
  171. return [NSString stringWithFormat:@"<%@ [%@]: %p '%@'>",
  172. [[self class] description], [self nodeName], _internal, value];
  173. return [NSString stringWithFormat:@"<%@ [%@]: %p>", [[self class] description], [self nodeName], _internal];
  174. }
  175. - (JSC::Bindings::RootObject*)_rootObject
  176. {
  177. WebCore::Frame* frame = core(self)->document()->frame();
  178. if (!frame)
  179. return 0;
  180. return frame->script()->bindingRootObject();
  181. }
  182. @end
  183. Class kitClass(WebCore::Node* impl)
  184. {
  185. switch (impl->nodeType()) {
  186. case WebCore::Node::ELEMENT_NODE:
  187. if (impl->isHTMLElement())
  188. return WebCore::elementClass(toHTMLElement(impl)->tagQName(), [DOMHTMLElement class]);
  189. return [DOMElement class];
  190. case WebCore::Node::ATTRIBUTE_NODE:
  191. return [DOMAttr class];
  192. case WebCore::Node::TEXT_NODE:
  193. return [DOMText class];
  194. case WebCore::Node::CDATA_SECTION_NODE:
  195. return [DOMCDATASection class];
  196. case WebCore::Node::ENTITY_REFERENCE_NODE:
  197. return [DOMEntityReference class];
  198. case WebCore::Node::ENTITY_NODE:
  199. return [DOMEntity class];
  200. case WebCore::Node::PROCESSING_INSTRUCTION_NODE:
  201. return [DOMProcessingInstruction class];
  202. case WebCore::Node::COMMENT_NODE:
  203. return [DOMComment class];
  204. case WebCore::Node::DOCUMENT_NODE:
  205. if (static_cast<WebCore::Document*>(impl)->isHTMLDocument())
  206. return [DOMHTMLDocument class];
  207. return [DOMDocument class];
  208. case WebCore::Node::DOCUMENT_TYPE_NODE:
  209. return [DOMDocumentType class];
  210. case WebCore::Node::DOCUMENT_FRAGMENT_NODE:
  211. return [DOMDocumentFragment class];
  212. case WebCore::Node::NOTATION_NODE:
  213. return [DOMNotation class];
  214. case WebCore::Node::XPATH_NAMESPACE_NODE:
  215. // FIXME: Create an XPath objective C wrapper
  216. // See http://bugs.webkit.org/show_bug.cgi?id=8755
  217. return nil;
  218. }
  219. ASSERT_NOT_REACHED();
  220. return nil;
  221. }
  222. id <DOMEventTarget> kit(WebCore::EventTarget* eventTarget)
  223. {
  224. if (!eventTarget)
  225. return nil;
  226. if (WebCore::Node* node = eventTarget->toNode())
  227. return kit(node);
  228. // We don't have an ObjC binding for XMLHttpRequest.
  229. return nil;
  230. }
  231. @implementation DOMNode (DOMNodeExtensions)
  232. - (NSRect)boundingBox
  233. {
  234. // FIXME: Could we move this function to WebCore::Node and autogenerate?
  235. core(self)->document()->updateLayoutIgnorePendingStylesheets();
  236. WebCore::RenderObject* renderer = core(self)->renderer();
  237. if (!renderer)
  238. return NSZeroRect;
  239. return renderer->absoluteBoundingBoxRect();
  240. }
  241. - (NSArray *)lineBoxRects
  242. {
  243. return [self textRects];
  244. }
  245. @end
  246. @implementation DOMNode (DOMNodeExtensionsPendingPublic)
  247. - (NSImage *)renderedImage
  248. {
  249. // FIXME: Could we move this function to WebCore::Node and autogenerate?
  250. WebCore::Node* node = core(self);
  251. WebCore::Frame* frame = node->document()->frame();
  252. if (!frame)
  253. return nil;
  254. return frame->nodeImage(node).get();
  255. }
  256. - (NSArray *)textRects
  257. {
  258. core(self)->document()->updateLayoutIgnorePendingStylesheets();
  259. if (!core(self)->renderer())
  260. return nil;
  261. Vector<WebCore::IntRect> rects;
  262. core(self)->textRects(rects);
  263. return kit(rects);
  264. }
  265. @end
  266. @implementation DOMNode (WebPrivate)
  267. + (id)_nodeFromJSWrapper:(JSObjectRef)jsWrapper
  268. {
  269. JSObject* object = toJS(jsWrapper);
  270. if (!object->inherits(&JSNode::s_info))
  271. return nil;
  272. WebCore::Node* node = jsCast<JSNode*>(object)->impl();
  273. return kit(node);
  274. }
  275. @end
  276. @implementation DOMRange (DOMRangeExtensions)
  277. - (NSRect)boundingBox
  278. {
  279. // FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
  280. core(self)->ownerDocument()->updateLayoutIgnorePendingStylesheets();
  281. return core(self)->boundingBox();
  282. }
  283. - (NSImage *)renderedImageForcingBlackText:(BOOL)forceBlackText
  284. {
  285. WebCore::Range* range = core(self);
  286. WebCore::Frame* frame = range->ownerDocument()->frame();
  287. if (!frame)
  288. return nil;
  289. return WebCore::rangeImage(frame, range, forceBlackText);
  290. }
  291. - (NSArray *)textRects
  292. {
  293. // FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
  294. Vector<WebCore::IntRect> rects;
  295. core(self)->ownerDocument()->updateLayoutIgnorePendingStylesheets();
  296. core(self)->textRects(rects);
  297. return kit(rects);
  298. }
  299. - (NSArray *)lineBoxRects
  300. {
  301. // FIXME: Remove this once all clients stop using it and we drop Leopard support.
  302. return [self textRects];
  303. }
  304. @end
  305. //------------------------------------------------------------------------------------------
  306. // DOMElement
  307. @implementation DOMElement (DOMElementAppKitExtensions)
  308. - (NSImage*)image
  309. {
  310. // FIXME: Could we move this function to WebCore::Node and autogenerate?
  311. WebCore::RenderObject* renderer = core(self)->renderer();
  312. if (!renderer || !renderer->isRenderImage())
  313. return nil;
  314. WebCore::CachedImage* cachedImage = static_cast<WebCore::RenderImage*>(renderer)->cachedImage();
  315. if (!cachedImage || cachedImage->errorOccurred())
  316. return nil;
  317. return cachedImage->imageForRenderer(renderer)->getNSImage();
  318. }
  319. @end
  320. @implementation DOMElement (WebPrivate)
  321. - (NSFont *)_font
  322. {
  323. // FIXME: Could we move this function to WebCore::Element and autogenerate?
  324. WebCore::RenderObject* renderer = core(self)->renderer();
  325. if (!renderer)
  326. return nil;
  327. return renderer->style()->font().primaryFont()->getNSFont();
  328. }
  329. - (NSData *)_imageTIFFRepresentation
  330. {
  331. // FIXME: Could we move this function to WebCore::Element and autogenerate?
  332. WebCore::RenderObject* renderer = core(self)->renderer();
  333. if (!renderer || !renderer->isRenderImage())
  334. return nil;
  335. WebCore::CachedImage* cachedImage = toRenderImage(renderer)->cachedImage();
  336. if (!cachedImage || cachedImage->errorOccurred())
  337. return nil;
  338. return (NSData *)cachedImage->imageForRenderer(renderer)->getTIFFRepresentation();
  339. }
  340. - (NSURL *)_getURLAttribute:(NSString *)name
  341. {
  342. // FIXME: Could we move this function to WebCore::Element and autogenerate?
  343. ASSERT(name);
  344. WebCore::Element* element = core(self);
  345. ASSERT(element);
  346. return element->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(element->getAttribute(name)));
  347. }
  348. - (BOOL)isFocused
  349. {
  350. // FIXME: Could we move this function to WebCore::Element and autogenerate?
  351. WebCore::Element* element = core(self);
  352. return element->document()->focusedElement() == element;
  353. }
  354. @end
  355. //------------------------------------------------------------------------------------------
  356. // DOMRange
  357. @implementation DOMRange (WebPrivate)
  358. - (NSString *)description
  359. {
  360. if (!_internal)
  361. return @"<DOMRange: null>";
  362. return [NSString stringWithFormat:@"<DOMRange: %@ %d %@ %d>",
  363. [self startContainer], [self startOffset], [self endContainer], [self endOffset]];
  364. }
  365. // FIXME: This should be removed as soon as all internal Apple uses of it have been replaced with
  366. // calls to the public method - (NSString *)text.
  367. - (NSString *)_text
  368. {
  369. return [self text];
  370. }
  371. @end
  372. //------------------------------------------------------------------------------------------
  373. // DOMRGBColor
  374. @implementation DOMRGBColor (WebPrivate)
  375. // FIXME: This should be removed as soon as all internal Apple uses of it have been replaced with
  376. // calls to the public method - (NSColor *)color.
  377. - (NSColor *)_color
  378. {
  379. return [self color];
  380. }
  381. @end
  382. @implementation DOMHTMLTableCellElement (WebPrivate)
  383. - (DOMHTMLTableCellElement *)_cellAbove
  384. {
  385. return kit(core(self)->cellAbove());
  386. }
  387. @end
  388. //------------------------------------------------------------------------------------------
  389. // DOMNodeFilter
  390. DOMNodeFilter *kit(WebCore::NodeFilter* impl)
  391. {
  392. if (!impl)
  393. return nil;
  394. if (DOMNodeFilter *wrapper = getDOMWrapper(impl))
  395. return [[wrapper retain] autorelease];
  396. DOMNodeFilter *wrapper = [[DOMNodeFilter alloc] _init];
  397. wrapper->_internal = reinterpret_cast<DOMObjectInternal*>(impl);
  398. impl->ref();
  399. addDOMWrapper(wrapper, impl);
  400. return [wrapper autorelease];
  401. }
  402. WebCore::NodeFilter* core(DOMNodeFilter *wrapper)
  403. {
  404. return wrapper ? reinterpret_cast<WebCore::NodeFilter*>(wrapper->_internal) : 0;
  405. }
  406. @implementation DOMNodeFilter
  407. - (void)dealloc
  408. {
  409. if (_internal)
  410. reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
  411. [super dealloc];
  412. }
  413. - (void)finalize
  414. {
  415. if (_internal)
  416. reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
  417. [super finalize];
  418. }
  419. - (short)acceptNode:(DOMNode *)node
  420. {
  421. return core(self)->acceptNode(core(node));
  422. }
  423. @end