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 56using namespace JSC; 57using 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 65namespace WebCore { 66 67typedef HashMap<const QualifiedName::QualifiedNameImpl*, Class> ObjCClassMap; 68static ObjCClassMap* elementClassMap; 69 70static void addElementClass(const QualifiedName& tag, Class objCClass) 71{ 72 elementClassMap->set(tag.impl(), objCClass); 73} 74 75static 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 151static 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 160static 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 170static 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 206Class 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 246id <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::s_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->isRenderImage()) 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->isRenderImage()) 388 return nil; 389 WebCore::CachedImage* cachedImage = toRenderImage(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 462DOMNodeFilter *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 477WebCore::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 504