1 /* 2 * Copyright (C) 2006, 2007, 2009 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "WebKitDLL.h" 28 #include "DOMCoreClasses.h" 29 30 #include "DOMCSSClasses.h" 31 #include "DOMEventsClasses.h" 32 #include "DOMHTMLClasses.h" 33 #include "WebKitGraphics.h" 34 35 #include <WebCore/BString.h> 36 #include <WebCore/COMPtr.h> 37 #include <WebCore/DOMWindow.h> 38 #include <WebCore/Document.h> 39 #include <WebCore/Element.h> 40 #include <WebCore/Frame.h> 41 #include <WebCore/SimpleFontData.h> 42 #include <WebCore/HTMLFormElement.h> 43 #include <WebCore/HTMLInputElement.h> 44 #include <WebCore/HTMLNames.h> 45 #include <WebCore/HTMLOptionElement.h> 46 #include <WebCore/HTMLSelectElement.h> 47 #include <WebCore/HTMLTextAreaElement.h> 48 #include <WebCore/NodeList.h> 49 #include <WebCore/RenderObject.h> 50 #include <WebCore/RenderTreeAsText.h> 51 52 #include <initguid.h> 53 // {3B0C0EFF-478B-4b0b-8290-D2321E08E23E} 54 DEFINE_GUID(IID_DOMElement, 0x3b0c0eff, 0x478b, 0x4b0b, 0x82, 0x90, 0xd2, 0x32, 0x1e, 0x8, 0xe2, 0x3e); 55 56 // Our normal style is just to say "using namespace WebCore" rather than having 57 // individual using directives for each type from that namespace. But 58 // "DOMObject" exists both in the WebCore namespace and unnamespaced in this 59 // file, which leads to ambiguities if we say "using namespace WebCore". 60 using namespace WebCore::HTMLNames; 61 using WTF::AtomicString; 62 using WebCore::BString; 63 using WebCore::Element; 64 using WebCore::ExceptionCode; 65 using WebCore::FontDescription; 66 using WebCore::Frame; 67 using WebCore::IntRect; 68 using WTF::String; 69 70 // DOMObject - IUnknown ------------------------------------------------------- 71 72 HRESULT STDMETHODCALLTYPE DOMObject::QueryInterface(REFIID riid, void** ppvObject) 73 { 74 *ppvObject = 0; 75 if (IsEqualGUID(riid, IID_IDOMObject)) 76 *ppvObject = static_cast<IDOMObject*>(this); 77 else 78 return WebScriptObject::QueryInterface(riid, ppvObject); 79 80 AddRef(); 81 return S_OK; 82 } 83 84 // DOMNode - IUnknown --------------------------------------------------------- 85 86 HRESULT STDMETHODCALLTYPE DOMNode::QueryInterface(REFIID riid, void** ppvObject) 87 { 88 *ppvObject = 0; 89 if (IsEqualGUID(riid, IID_IDOMNode)) 90 *ppvObject = static_cast<IDOMNode*>(this); 91 else if (IsEqualGUID(riid, __uuidof(DOMNode))) 92 *ppvObject = static_cast<DOMNode*>(this); 93 else 94 return DOMObject::QueryInterface(riid, ppvObject); 95 96 AddRef(); 97 return S_OK; 98 } 99 100 // DOMNode -------------------------------------------------------------------- 101 102 HRESULT STDMETHODCALLTYPE DOMNode::nodeName( 103 /* [retval][out] */ BSTR* result) 104 { 105 if (!result) 106 return E_POINTER; 107 108 if (!m_node) 109 return E_FAIL; 110 111 *result = BString(m_node->nodeName()).release(); 112 return S_OK; 113 } 114 115 HRESULT STDMETHODCALLTYPE DOMNode::nodeValue( 116 /* [retval][out] */ BSTR* result) 117 { 118 if (!m_node) 119 return E_FAIL; 120 WTF::String nodeValueStr = m_node->nodeValue(); 121 *result = SysAllocStringLen(nodeValueStr.characters(), nodeValueStr.length()); 122 if (nodeValueStr.length() && !*result) 123 return E_OUTOFMEMORY; 124 return S_OK; 125 } 126 127 HRESULT STDMETHODCALLTYPE DOMNode::setNodeValue( 128 /* [in] */ BSTR /*value*/) 129 { 130 ASSERT_NOT_REACHED(); 131 return E_NOTIMPL; 132 } 133 134 HRESULT STDMETHODCALLTYPE DOMNode::nodeType( 135 /* [retval][out] */ unsigned short* /*result*/) 136 { 137 ASSERT_NOT_REACHED(); 138 return E_NOTIMPL; 139 } 140 141 HRESULT STDMETHODCALLTYPE DOMNode::parentNode( 142 /* [retval][out] */ IDOMNode** result) 143 { 144 *result = 0; 145 if (!m_node || !m_node->parentNode()) 146 return E_FAIL; 147 *result = DOMNode::createInstance(m_node->parentNode()); 148 return *result ? S_OK : E_FAIL; 149 } 150 151 HRESULT STDMETHODCALLTYPE DOMNode::childNodes( 152 /* [retval][out] */ IDOMNodeList** result) 153 { 154 if (!m_node) 155 return E_FAIL; 156 157 if (!result) 158 return E_POINTER; 159 160 *result = DOMNodeList::createInstance(m_node->childNodes().get()); 161 return *result ? S_OK : E_FAIL; 162 } 163 164 HRESULT STDMETHODCALLTYPE DOMNode::firstChild( 165 /* [retval][out] */ IDOMNode** /*result*/) 166 { 167 ASSERT_NOT_REACHED(); 168 return E_NOTIMPL; 169 } 170 171 HRESULT STDMETHODCALLTYPE DOMNode::lastChild( 172 /* [retval][out] */ IDOMNode** /*result*/) 173 { 174 ASSERT_NOT_REACHED(); 175 return E_NOTIMPL; 176 } 177 178 HRESULT STDMETHODCALLTYPE DOMNode::previousSibling( 179 /* [retval][out] */ IDOMNode** /*result*/) 180 { 181 ASSERT_NOT_REACHED(); 182 return E_NOTIMPL; 183 } 184 185 HRESULT STDMETHODCALLTYPE DOMNode::nextSibling( 186 /* [retval][out] */ IDOMNode** result) 187 { 188 if (!result) 189 return E_POINTER; 190 *result = 0; 191 if (!m_node) 192 return E_FAIL; 193 *result = DOMNode::createInstance(m_node->nextSibling()); 194 return *result ? S_OK : E_FAIL; 195 } 196 197 HRESULT STDMETHODCALLTYPE DOMNode::attributes( 198 /* [retval][out] */ IDOMNamedNodeMap** /*result*/) 199 { 200 ASSERT_NOT_REACHED(); 201 return E_NOTIMPL; 202 } 203 204 HRESULT STDMETHODCALLTYPE DOMNode::ownerDocument( 205 /* [retval][out] */ IDOMDocument** result) 206 { 207 if (!result) 208 return E_POINTER; 209 *result = 0; 210 if (!m_node) 211 return E_FAIL; 212 *result = DOMDocument::createInstance(m_node->ownerDocument()); 213 return *result ? S_OK : E_FAIL; 214 } 215 216 HRESULT STDMETHODCALLTYPE DOMNode::insertBefore( 217 /* [in] */ IDOMNode* newChild, 218 /* [in] */ IDOMNode* refChild, 219 /* [retval][out] */ IDOMNode** result) 220 { 221 if (!result) 222 return E_POINTER; 223 224 *result = 0; 225 226 if (!m_node) 227 return E_FAIL; 228 229 COMPtr<DOMNode> newChildNode(Query, newChild); 230 if (!newChildNode) 231 return E_FAIL; 232 233 COMPtr<DOMNode> refChildNode(Query, refChild); 234 235 ExceptionCode ec; 236 if (!m_node->insertBefore(newChildNode->node(), refChildNode ? refChildNode->node() : 0, ec)) 237 return E_FAIL; 238 239 *result = newChild; 240 (*result)->AddRef(); 241 return S_OK; 242 } 243 244 HRESULT STDMETHODCALLTYPE DOMNode::replaceChild( 245 /* [in] */ IDOMNode* /*newChild*/, 246 /* [in] */ IDOMNode* /*oldChild*/, 247 /* [retval][out] */ IDOMNode** /*result*/) 248 { 249 ASSERT_NOT_REACHED(); 250 return E_NOTIMPL; 251 } 252 253 HRESULT STDMETHODCALLTYPE DOMNode::removeChild( 254 /* [in] */ IDOMNode* oldChild, 255 /* [retval][out] */ IDOMNode** result) 256 { 257 if (!result) 258 return E_POINTER; 259 260 *result = 0; 261 262 if (!m_node) 263 return E_FAIL; 264 265 COMPtr<DOMNode> oldChildNode(Query, oldChild); 266 if (!oldChildNode) 267 return E_FAIL; 268 269 ExceptionCode ec; 270 if (!m_node->removeChild(oldChildNode->node(), ec)) 271 return E_FAIL; 272 273 *result = oldChild; 274 (*result)->AddRef(); 275 return S_OK; 276 } 277 278 HRESULT STDMETHODCALLTYPE DOMNode::appendChild( 279 /* [in] */ IDOMNode* /*oldChild*/, 280 /* [retval][out] */ IDOMNode** /*result*/) 281 { 282 ASSERT_NOT_REACHED(); 283 return E_NOTIMPL; 284 } 285 286 HRESULT STDMETHODCALLTYPE DOMNode::hasChildNodes( 287 /* [retval][out] */ BOOL* /*result*/) 288 { 289 ASSERT_NOT_REACHED(); 290 return E_NOTIMPL; 291 } 292 293 HRESULT STDMETHODCALLTYPE DOMNode::cloneNode( 294 /* [in] */ BOOL /*deep*/, 295 /* [retval][out] */ IDOMNode** /*result*/) 296 { 297 ASSERT_NOT_REACHED(); 298 return E_NOTIMPL; 299 } 300 301 HRESULT STDMETHODCALLTYPE DOMNode::normalize( void) 302 { 303 ASSERT_NOT_REACHED(); 304 return E_NOTIMPL; 305 } 306 307 HRESULT STDMETHODCALLTYPE DOMNode::isSupported( 308 /* [in] */ BSTR /*feature*/, 309 /* [in] */ BSTR /*version*/, 310 /* [retval][out] */ BOOL* /*result*/) 311 { 312 ASSERT_NOT_REACHED(); 313 return E_NOTIMPL; 314 } 315 316 HRESULT STDMETHODCALLTYPE DOMNode::namespaceURI( 317 /* [retval][out] */ BSTR* /*result*/) 318 { 319 ASSERT_NOT_REACHED(); 320 return E_NOTIMPL; 321 } 322 323 HRESULT STDMETHODCALLTYPE DOMNode::prefix( 324 /* [retval][out] */ BSTR* /*result*/) 325 { 326 ASSERT_NOT_REACHED(); 327 return E_NOTIMPL; 328 } 329 330 HRESULT STDMETHODCALLTYPE DOMNode::setPrefix( 331 /* [in] */ BSTR /*prefix*/) 332 { 333 ASSERT_NOT_REACHED(); 334 return E_NOTIMPL; 335 } 336 337 HRESULT STDMETHODCALLTYPE DOMNode::localName( 338 /* [retval][out] */ BSTR* /*result*/) 339 { 340 ASSERT_NOT_REACHED(); 341 return E_NOTIMPL; 342 } 343 344 HRESULT STDMETHODCALLTYPE DOMNode::hasAttributes( 345 /* [retval][out] */ BOOL* /*result*/) 346 { 347 ASSERT_NOT_REACHED(); 348 return E_NOTIMPL; 349 } 350 351 HRESULT STDMETHODCALLTYPE DOMNode::isSameNode( 352 /* [in] */ IDOMNode* other, 353 /* [retval][out] */ BOOL* result) 354 { 355 if (!result) { 356 ASSERT_NOT_REACHED(); 357 return E_POINTER; 358 } 359 360 *result = FALSE; 361 362 if (!other) 363 return E_POINTER; 364 365 COMPtr<DOMNode> domOther; 366 HRESULT hr = other->QueryInterface(__uuidof(DOMNode), (void**)&domOther); 367 if (FAILED(hr)) 368 return hr; 369 370 *result = m_node->isSameNode(domOther->node()) ? TRUE : FALSE; 371 return S_OK; 372 } 373 374 HRESULT STDMETHODCALLTYPE DOMNode::isEqualNode( 375 /* [in] */ IDOMNode* /*other*/, 376 /* [retval][out] */ BOOL* /*result*/) 377 { 378 ASSERT_NOT_REACHED(); 379 return E_NOTIMPL; 380 } 381 382 HRESULT STDMETHODCALLTYPE DOMNode::textContent( 383 /* [retval][out] */ BSTR* result) 384 { 385 if (!result) 386 return E_POINTER; 387 388 *result = BString(m_node->textContent()).release(); 389 390 return S_OK; 391 } 392 393 HRESULT STDMETHODCALLTYPE DOMNode::setTextContent( 394 /* [in] */ BSTR /*text*/) 395 { 396 ASSERT_NOT_REACHED(); 397 return E_NOTIMPL; 398 } 399 400 // DOMNode - IDOMEventTarget -------------------------------------------------- 401 402 HRESULT STDMETHODCALLTYPE DOMNode::addEventListener( 403 /* [in] */ BSTR /*type*/, 404 /* [in] */ IDOMEventListener* /*listener*/, 405 /* [in] */ BOOL /*useCapture*/) 406 { 407 return E_NOTIMPL; 408 } 409 410 HRESULT STDMETHODCALLTYPE DOMNode::removeEventListener( 411 /* [in] */ BSTR /*type*/, 412 /* [in] */ IDOMEventListener* /*listener*/, 413 /* [in] */ BOOL /*useCapture*/) 414 { 415 return E_NOTIMPL; 416 } 417 418 HRESULT STDMETHODCALLTYPE DOMNode::dispatchEvent( 419 /* [in] */ IDOMEvent* evt, 420 /* [retval][out] */ BOOL* result) 421 { 422 if (!m_node || !evt) 423 return E_FAIL; 424 425 #if 0 // FIXME - raise dom exceptions 426 if (![self _node]->isEventTargetNode()) 427 WebCore::raiseDOMException(DOM_NOT_SUPPORTED_ERR); 428 #endif 429 430 COMPtr<DOMEvent> domEvent; 431 HRESULT hr = evt->QueryInterface(IID_DOMEvent, (void**) &domEvent); 432 if (FAILED(hr)) 433 return hr; 434 435 WebCore::ExceptionCode ec = 0; 436 *result = m_node->dispatchEvent(domEvent->coreEvent(), ec) ? TRUE : FALSE; 437 #if 0 // FIXME - raise dom exceptions 438 WebCore::raiseOnDOMError(ec); 439 #endif 440 return S_OK; 441 } 442 443 // DOMNode - DOMNode ---------------------------------------------------------- 444 445 DOMNode::DOMNode(WebCore::Node* n) 446 : m_node(0) 447 { 448 if (n) 449 n->ref(); 450 451 m_node = n; 452 } 453 454 DOMNode::~DOMNode() 455 { 456 if (m_node) 457 m_node->deref(); 458 } 459 460 IDOMNode* DOMNode::createInstance(WebCore::Node* n) 461 { 462 if (!n) 463 return 0; 464 465 HRESULT hr = S_OK; 466 IDOMNode* domNode = 0; 467 WebCore::Node::NodeType nodeType = n->nodeType(); 468 469 switch (nodeType) { 470 case WebCore::Node::ELEMENT_NODE: 471 { 472 IDOMElement* newElement = DOMElement::createInstance(static_cast<WebCore::Element*>(n)); 473 if (newElement) { 474 hr = newElement->QueryInterface(IID_IDOMNode, (void**)&domNode); 475 newElement->Release(); 476 } 477 } 478 break; 479 case WebCore::Node::DOCUMENT_NODE: 480 { 481 IDOMDocument* newDocument = DOMDocument::createInstance(n->document()); 482 if (newDocument) { 483 hr = newDocument->QueryInterface(IID_IDOMNode, (void**)&domNode); 484 newDocument->Release(); 485 } 486 } 487 break; 488 default: 489 { 490 DOMNode* newNode = new DOMNode(n); 491 hr = newNode->QueryInterface(IID_IDOMNode, (void**)&domNode); 492 } 493 break; 494 } 495 496 if (FAILED(hr)) 497 return 0; 498 499 return domNode; 500 } 501 502 // DOMNodeList - IUnknown ----------------------------------------------------- 503 504 HRESULT STDMETHODCALLTYPE DOMNodeList::QueryInterface(REFIID riid, void** ppvObject) 505 { 506 *ppvObject = 0; 507 if (IsEqualGUID(riid, IID_IDOMNodeList)) 508 *ppvObject = static_cast<IDOMNodeList*>(this); 509 else 510 return DOMObject::QueryInterface(riid, ppvObject); 511 512 AddRef(); 513 return S_OK; 514 } 515 516 // IDOMNodeList --------------------------------------------------------------- 517 518 HRESULT STDMETHODCALLTYPE DOMNodeList::item( 519 /* [in] */ UINT index, 520 /* [retval][out] */ IDOMNode **result) 521 { 522 *result = 0; 523 if (!m_nodeList) 524 return E_FAIL; 525 526 WebCore::Node* itemNode = m_nodeList->item(index); 527 if (!itemNode) 528 return E_FAIL; 529 530 *result = DOMNode::createInstance(itemNode); 531 return *result ? S_OK : E_FAIL; 532 } 533 534 HRESULT STDMETHODCALLTYPE DOMNodeList::length( 535 /* [retval][out] */ UINT *result) 536 { 537 *result = 0; 538 if (!m_nodeList) 539 return E_FAIL; 540 *result = m_nodeList->length(); 541 return S_OK; 542 } 543 544 // DOMNodeList - DOMNodeList -------------------------------------------------- 545 546 DOMNodeList::DOMNodeList(WebCore::NodeList* l) 547 : m_nodeList(0) 548 { 549 if (l) 550 l->ref(); 551 552 m_nodeList = l; 553 } 554 555 DOMNodeList::~DOMNodeList() 556 { 557 if (m_nodeList) 558 m_nodeList->deref(); 559 } 560 561 IDOMNodeList* DOMNodeList::createInstance(WebCore::NodeList* l) 562 { 563 if (!l) 564 return 0; 565 566 IDOMNodeList* domNodeList = 0; 567 DOMNodeList* newNodeList = new DOMNodeList(l); 568 if (FAILED(newNodeList->QueryInterface(IID_IDOMNodeList, (void**)&domNodeList))) 569 return 0; 570 571 return domNodeList; 572 } 573 574 // DOMDocument - IUnknown ----------------------------------------------------- 575 576 HRESULT STDMETHODCALLTYPE DOMDocument::QueryInterface(REFIID riid, void** ppvObject) 577 { 578 *ppvObject = 0; 579 if (IsEqualGUID(riid, IID_IDOMDocument)) 580 *ppvObject = static_cast<IDOMDocument*>(this); 581 else if (IsEqualGUID(riid, IID_IDOMViewCSS)) 582 *ppvObject = static_cast<IDOMViewCSS*>(this); 583 else if (IsEqualGUID(riid, IID_IDOMDocumentEvent)) 584 *ppvObject = static_cast<IDOMDocumentEvent*>(this); 585 else 586 return DOMNode::QueryInterface(riid, ppvObject); 587 588 AddRef(); 589 return S_OK; 590 } 591 592 // DOMDocument ---------------------------------------------------------------- 593 594 HRESULT STDMETHODCALLTYPE DOMDocument::doctype( 595 /* [retval][out] */ IDOMDocumentType** /*result*/) 596 { 597 ASSERT_NOT_REACHED(); 598 return E_NOTIMPL; 599 } 600 601 HRESULT STDMETHODCALLTYPE DOMDocument::implementation( 602 /* [retval][out] */ IDOMImplementation** /*result*/) 603 { 604 ASSERT_NOT_REACHED(); 605 return E_NOTIMPL; 606 } 607 608 HRESULT STDMETHODCALLTYPE DOMDocument::documentElement( 609 /* [retval][out] */ IDOMElement** result) 610 { 611 *result = DOMElement::createInstance(m_document->documentElement()); 612 return *result ? S_OK : E_FAIL; 613 } 614 615 HRESULT STDMETHODCALLTYPE DOMDocument::createElement( 616 /* [in] */ BSTR tagName, 617 /* [retval][out] */ IDOMElement** result) 618 { 619 if (!m_document) 620 return E_FAIL; 621 622 String tagNameString(tagName); 623 ExceptionCode ec; 624 *result = DOMElement::createInstance(m_document->createElement(tagNameString, ec).get()); 625 return *result ? S_OK : E_FAIL; 626 } 627 628 HRESULT STDMETHODCALLTYPE DOMDocument::createDocumentFragment( 629 /* [retval][out] */ IDOMDocumentFragment** /*result*/) 630 { 631 ASSERT_NOT_REACHED(); 632 return E_NOTIMPL; 633 } 634 635 HRESULT STDMETHODCALLTYPE DOMDocument::createTextNode( 636 /* [in] */ BSTR /*data*/, 637 /* [retval][out] */ IDOMText** /*result*/) 638 { 639 ASSERT_NOT_REACHED(); 640 return E_NOTIMPL; 641 } 642 643 HRESULT STDMETHODCALLTYPE DOMDocument::createComment( 644 /* [in] */ BSTR /*data*/, 645 /* [retval][out] */ IDOMComment** /*result*/) 646 { 647 ASSERT_NOT_REACHED(); 648 return E_NOTIMPL; 649 } 650 651 HRESULT STDMETHODCALLTYPE DOMDocument::createCDATASection( 652 /* [in] */ BSTR /*data*/, 653 /* [retval][out] */ IDOMCDATASection** /*result*/) 654 { 655 ASSERT_NOT_REACHED(); 656 return E_NOTIMPL; 657 } 658 659 HRESULT STDMETHODCALLTYPE DOMDocument::createProcessingInstruction( 660 /* [in] */ BSTR /*target*/, 661 /* [in] */ BSTR /*data*/, 662 /* [retval][out] */ IDOMProcessingInstruction** /*result*/) 663 { 664 ASSERT_NOT_REACHED(); 665 return E_NOTIMPL; 666 } 667 668 HRESULT STDMETHODCALLTYPE DOMDocument::createAttribute( 669 /* [in] */ BSTR /*name*/, 670 /* [retval][out] */ IDOMAttr** /*result*/) 671 { 672 ASSERT_NOT_REACHED(); 673 return E_NOTIMPL; 674 } 675 676 HRESULT STDMETHODCALLTYPE DOMDocument::createEntityReference( 677 /* [in] */ BSTR /*name*/, 678 /* [retval][out] */ IDOMEntityReference** /*result*/) 679 { 680 ASSERT_NOT_REACHED(); 681 return E_NOTIMPL; 682 } 683 684 HRESULT STDMETHODCALLTYPE DOMDocument::getElementsByTagName( 685 /* [in] */ BSTR tagName, 686 /* [retval][out] */ IDOMNodeList** result) 687 { 688 if (!m_document) 689 return E_FAIL; 690 691 String tagNameString(tagName); 692 *result = DOMNodeList::createInstance(m_document->getElementsByTagName(tagNameString).get()); 693 return *result ? S_OK : E_FAIL; 694 } 695 696 HRESULT STDMETHODCALLTYPE DOMDocument::importNode( 697 /* [in] */ IDOMNode* /*importedNode*/, 698 /* [in] */ BOOL /*deep*/, 699 /* [retval][out] */ IDOMNode** /*result*/) 700 { 701 ASSERT_NOT_REACHED(); 702 return E_NOTIMPL; 703 } 704 705 HRESULT STDMETHODCALLTYPE DOMDocument::createElementNS( 706 /* [in] */ BSTR /*namespaceURI*/, 707 /* [in] */ BSTR /*qualifiedName*/, 708 /* [retval][out] */ IDOMElement** /*result*/) 709 { 710 ASSERT_NOT_REACHED(); 711 return E_NOTIMPL; 712 } 713 714 HRESULT STDMETHODCALLTYPE DOMDocument::createAttributeNS( 715 /* [in] */ BSTR /*namespaceURI*/, 716 /* [in] */ BSTR /*qualifiedName*/, 717 /* [retval][out] */ IDOMAttr** /*result*/) 718 { 719 ASSERT_NOT_REACHED(); 720 return E_NOTIMPL; 721 } 722 723 HRESULT STDMETHODCALLTYPE DOMDocument::getElementsByTagNameNS( 724 /* [in] */ BSTR namespaceURI, 725 /* [in] */ BSTR localName, 726 /* [retval][out] */ IDOMNodeList** result) 727 { 728 if (!m_document) 729 return E_FAIL; 730 731 String namespaceURIString(namespaceURI); 732 String localNameString(localName); 733 *result = DOMNodeList::createInstance(m_document->getElementsByTagNameNS(namespaceURIString, localNameString).get()); 734 return *result ? S_OK : E_FAIL; 735 } 736 737 HRESULT STDMETHODCALLTYPE DOMDocument::getElementById( 738 /* [in] */ BSTR elementId, 739 /* [retval][out] */ IDOMElement** result) 740 { 741 if (!m_document) 742 return E_FAIL; 743 744 String idString(elementId); 745 *result = DOMElement::createInstance(m_document->getElementById(idString)); 746 return *result ? S_OK : E_FAIL; 747 } 748 749 // DOMDocument - IDOMViewCSS -------------------------------------------------- 750 751 HRESULT STDMETHODCALLTYPE DOMDocument::getComputedStyle( 752 /* [in] */ IDOMElement* elt, 753 /* [in] */ BSTR pseudoElt, 754 /* [retval][out] */ IDOMCSSStyleDeclaration** result) 755 { 756 if (!elt || !result) 757 return E_POINTER; 758 759 COMPtr<DOMElement> domEle; 760 HRESULT hr = elt->QueryInterface(IID_DOMElement, (void**)&domEle); 761 if (FAILED(hr)) 762 return hr; 763 Element* element = domEle->element(); 764 765 WebCore::DOMWindow* dv = m_document->defaultView(); 766 String pseudoEltString(pseudoElt); 767 768 if (!dv) 769 return E_FAIL; 770 771 *result = DOMCSSStyleDeclaration::createInstance(dv->getComputedStyle(element, pseudoEltString.impl()).get()); 772 return *result ? S_OK : E_FAIL; 773 } 774 775 // DOMDocument - IDOMDocumentEvent -------------------------------------------- 776 777 HRESULT STDMETHODCALLTYPE DOMDocument::createEvent( 778 /* [in] */ BSTR eventType, 779 /* [retval][out] */ IDOMEvent **result) 780 { 781 String eventTypeString(eventType, SysStringLen(eventType)); 782 WebCore::ExceptionCode ec = 0; 783 *result = DOMEvent::createInstance(m_document->createEvent(eventTypeString, ec)); 784 return *result ? S_OK : E_FAIL; 785 } 786 787 // DOMDocument - DOMDocument -------------------------------------------------- 788 789 DOMDocument::DOMDocument(WebCore::Document* d) 790 : DOMNode(d) 791 , m_document(d) 792 { 793 } 794 795 DOMDocument::~DOMDocument() 796 { 797 } 798 799 IDOMDocument* DOMDocument::createInstance(WebCore::Document* d) 800 { 801 if (!d) 802 return 0; 803 804 HRESULT hr; 805 IDOMDocument* domDocument = 0; 806 807 if (d->isHTMLDocument()) { 808 DOMHTMLDocument* newDocument = new DOMHTMLDocument(d); 809 hr = newDocument->QueryInterface(IID_IDOMDocument, (void**)&domDocument); 810 } else { 811 DOMDocument* newDocument = new DOMDocument(d); 812 hr = newDocument->QueryInterface(IID_IDOMDocument, (void**)&domDocument); 813 } 814 815 if (FAILED(hr)) 816 return 0; 817 818 return domDocument; 819 } 820 821 // DOMElement - IUnknown ------------------------------------------------------ 822 823 HRESULT STDMETHODCALLTYPE DOMElement::QueryInterface(REFIID riid, void** ppvObject) 824 { 825 *ppvObject = 0; 826 if (IsEqualGUID(riid, IID_IDOMElement)) 827 *ppvObject = static_cast<IDOMElement*>(this); 828 else if (IsEqualGUID(riid, IID_DOMElement)) 829 *ppvObject = static_cast<DOMElement*>(this); 830 else if (IsEqualGUID(riid, IID_IDOMElementPrivate)) 831 *ppvObject = static_cast<IDOMElementPrivate*>(this); 832 else if (IsEqualGUID(riid, IID_IDOMNodeExtensions)) 833 *ppvObject = static_cast<IDOMNodeExtensions*>(this); 834 else if (IsEqualGUID(riid, IID_IDOMElementCSSInlineStyle)) 835 *ppvObject = static_cast<IDOMElementCSSInlineStyle*>(this); 836 else if (IsEqualGUID(riid, IID_IDOMElementExtensions)) 837 *ppvObject = static_cast<IDOMElementExtensions*>(this); 838 else 839 return DOMNode::QueryInterface(riid, ppvObject); 840 841 AddRef(); 842 return S_OK; 843 } 844 845 // DOMElement - IDOMNodeExtensions--------------------------------------------- 846 847 HRESULT STDMETHODCALLTYPE DOMElement::boundingBox( 848 /* [retval][out] */ LPRECT rect) 849 { 850 ::SetRectEmpty(rect); 851 852 if (!m_element) 853 return E_FAIL; 854 855 WebCore::RenderObject *renderer = m_element->renderer(); 856 if (renderer) { 857 IntRect boundsIntRect = renderer->absoluteBoundingBoxRect(); 858 rect->left = boundsIntRect.x(); 859 rect->top = boundsIntRect.y(); 860 rect->right = boundsIntRect.x() + boundsIntRect.width(); 861 rect->bottom = boundsIntRect.y() + boundsIntRect.height(); 862 } 863 864 return S_OK; 865 } 866 867 HRESULT STDMETHODCALLTYPE DOMElement::lineBoxRects( 868 /* [size_is][in] */ RECT* /*rects*/, 869 /* [in] */ int /*cRects*/) 870 { 871 return E_NOTIMPL; 872 } 873 874 // IDOMElement ---------------------------------------------------------------- 875 876 HRESULT STDMETHODCALLTYPE DOMElement::tagName( 877 /* [retval][out] */ BSTR* result) 878 { 879 if (!m_element) 880 return E_FAIL; 881 882 if (!result) 883 return E_POINTER; 884 885 *result = BString(m_element->tagName()).release(); 886 return S_OK; 887 } 888 889 HRESULT STDMETHODCALLTYPE DOMElement::getAttribute( 890 /* [in] */ BSTR name, 891 /* [retval][out] */ BSTR* result) 892 { 893 if (!m_element) 894 return E_FAIL; 895 WTF::String nameString(name, SysStringLen(name)); 896 WTF::String& attrValueString = (WTF::String&) m_element->getAttribute(nameString); 897 *result = SysAllocStringLen(attrValueString.characters(), attrValueString.length()); 898 if (attrValueString.length() && !*result) 899 return E_OUTOFMEMORY; 900 return S_OK; 901 } 902 903 HRESULT STDMETHODCALLTYPE DOMElement::setAttribute( 904 /* [in] */ BSTR name, 905 /* [in] */ BSTR value) 906 { 907 if (!m_element) 908 return E_FAIL; 909 910 WTF::String nameString(name, SysStringLen(name)); 911 WTF::String valueString(value, SysStringLen(value)); 912 WebCore::ExceptionCode ec = 0; 913 m_element->setAttribute(nameString, valueString, ec); 914 return ec ? E_FAIL : S_OK; 915 } 916 917 HRESULT STDMETHODCALLTYPE DOMElement::removeAttribute( 918 /* [in] */ BSTR /*name*/) 919 { 920 ASSERT_NOT_REACHED(); 921 return E_NOTIMPL; 922 } 923 924 HRESULT STDMETHODCALLTYPE DOMElement::getAttributeNode( 925 /* [in] */ BSTR /*name*/, 926 /* [retval][out] */ IDOMAttr** /*result*/) 927 { 928 ASSERT_NOT_REACHED(); 929 return E_NOTIMPL; 930 } 931 932 HRESULT STDMETHODCALLTYPE DOMElement::setAttributeNode( 933 /* [in] */ IDOMAttr* /*newAttr*/, 934 /* [retval][out] */ IDOMAttr** /*result*/) 935 { 936 ASSERT_NOT_REACHED(); 937 return E_NOTIMPL; 938 } 939 940 HRESULT STDMETHODCALLTYPE DOMElement::removeAttributeNode( 941 /* [in] */ IDOMAttr* /*oldAttr*/, 942 /* [retval][out] */ IDOMAttr** /*result*/) 943 { 944 ASSERT_NOT_REACHED(); 945 return E_NOTIMPL; 946 } 947 948 HRESULT STDMETHODCALLTYPE DOMElement::getElementsByTagName( 949 /* [in] */ BSTR /*name*/, 950 /* [retval][out] */ IDOMNodeList** /*result*/) 951 { 952 ASSERT_NOT_REACHED(); 953 return E_NOTIMPL; 954 } 955 956 HRESULT STDMETHODCALLTYPE DOMElement::getAttributeNS( 957 /* [in] */ BSTR /*namespaceURI*/, 958 /* [in] */ BSTR /*localName*/, 959 /* [retval][out] */ BSTR* /*result*/) 960 { 961 ASSERT_NOT_REACHED(); 962 return E_NOTIMPL; 963 } 964 965 HRESULT STDMETHODCALLTYPE DOMElement::setAttributeNS( 966 /* [in] */ BSTR /*namespaceURI*/, 967 /* [in] */ BSTR /*qualifiedName*/, 968 /* [in] */ BSTR /*value*/) 969 { 970 ASSERT_NOT_REACHED(); 971 return E_NOTIMPL; 972 } 973 974 HRESULT STDMETHODCALLTYPE DOMElement::removeAttributeNS( 975 /* [in] */ BSTR /*namespaceURI*/, 976 /* [in] */ BSTR /*localName*/) 977 { 978 ASSERT_NOT_REACHED(); 979 return E_NOTIMPL; 980 } 981 982 HRESULT STDMETHODCALLTYPE DOMElement::getAttributeNodeNS( 983 /* [in] */ BSTR /*namespaceURI*/, 984 /* [in] */ BSTR /*localName*/, 985 /* [retval][out] */ IDOMAttr** /*result*/) 986 { 987 ASSERT_NOT_REACHED(); 988 return E_NOTIMPL; 989 } 990 991 HRESULT STDMETHODCALLTYPE DOMElement::setAttributeNodeNS( 992 /* [in] */ IDOMAttr* /*newAttr*/, 993 /* [retval][out] */ IDOMAttr** /*result*/) 994 { 995 ASSERT_NOT_REACHED(); 996 return E_NOTIMPL; 997 } 998 999 HRESULT STDMETHODCALLTYPE DOMElement::getElementsByTagNameNS( 1000 /* [in] */ BSTR /*namespaceURI*/, 1001 /* [in] */ BSTR /*localName*/, 1002 /* [retval][out] */ IDOMNodeList** /*result*/) 1003 { 1004 ASSERT_NOT_REACHED(); 1005 return E_NOTIMPL; 1006 } 1007 1008 HRESULT STDMETHODCALLTYPE DOMElement::hasAttribute( 1009 /* [in] */ BSTR /*name*/, 1010 /* [retval][out] */ BOOL* /*result*/) 1011 { 1012 ASSERT_NOT_REACHED(); 1013 return E_NOTIMPL; 1014 } 1015 1016 HRESULT STDMETHODCALLTYPE DOMElement::hasAttributeNS( 1017 /* [in] */ BSTR /*namespaceURI*/, 1018 /* [in] */ BSTR /*localName*/, 1019 /* [retval][out] */ BOOL* /*result*/) 1020 { 1021 ASSERT_NOT_REACHED(); 1022 return E_NOTIMPL; 1023 } 1024 1025 HRESULT STDMETHODCALLTYPE DOMElement::focus( void) 1026 { 1027 if (!m_element) 1028 return E_FAIL; 1029 m_element->focus(); 1030 return S_OK; 1031 } 1032 1033 HRESULT STDMETHODCALLTYPE DOMElement::blur( void) 1034 { 1035 if (!m_element) 1036 return E_FAIL; 1037 m_element->blur(); 1038 return S_OK; 1039 } 1040 1041 // IDOMElementPrivate --------------------------------------------------------- 1042 1043 HRESULT DOMElement::coreElement(void **element) 1044 { 1045 if (!m_element) 1046 return E_FAIL; 1047 *element = (void*) m_element; 1048 return S_OK; 1049 } 1050 1051 HRESULT STDMETHODCALLTYPE DOMElement::isEqual( 1052 /* [in] */ IDOMElement *other, 1053 /* [retval][out] */ BOOL *result) 1054 { 1055 *result = FALSE; 1056 1057 if (!other || !result) 1058 return E_POINTER; 1059 1060 IDOMElementPrivate* otherPriv; 1061 HRESULT hr = other->QueryInterface(IID_IDOMElementPrivate, (void**) &otherPriv); 1062 if (FAILED(hr)) 1063 return hr; 1064 1065 void* otherCoreEle; 1066 hr = otherPriv->coreElement(&otherCoreEle); 1067 otherPriv->Release(); 1068 if (FAILED(hr)) 1069 return hr; 1070 1071 *result = (otherCoreEle == (void*)m_element) ? TRUE : FALSE; 1072 return S_OK; 1073 } 1074 1075 HRESULT STDMETHODCALLTYPE DOMElement::isFocused( 1076 /* [retval][out] */ BOOL *result) 1077 { 1078 if (!m_element) 1079 return E_FAIL; 1080 1081 if (m_element->document()->focusedNode() == m_element) 1082 *result = TRUE; 1083 else 1084 *result = FALSE; 1085 1086 return S_OK; 1087 } 1088 1089 HRESULT STDMETHODCALLTYPE DOMElement::innerText( 1090 /* [retval][out] */ BSTR* result) 1091 { 1092 if (!result) { 1093 ASSERT_NOT_REACHED(); 1094 return E_POINTER; 1095 } 1096 1097 if (!m_element) { 1098 ASSERT_NOT_REACHED(); 1099 return E_FAIL; 1100 } 1101 1102 *result = BString(m_element->innerText()).release(); 1103 return S_OK; 1104 } 1105 1106 HRESULT STDMETHODCALLTYPE DOMElement::font(WebFontDescription* webFontDescription) 1107 { 1108 if (!webFontDescription) { 1109 ASSERT_NOT_REACHED(); 1110 return E_POINTER; 1111 } 1112 1113 ASSERT(m_element); 1114 1115 WebCore::RenderObject* renderer = m_element->renderer(); 1116 if (!renderer) 1117 return E_FAIL; 1118 1119 FontDescription fontDescription = renderer->style()->font().fontDescription(); 1120 AtomicString family = fontDescription.family().family(); 1121 webFontDescription->family = family.characters(); 1122 webFontDescription->familyLength = family.length(); 1123 webFontDescription->size = fontDescription.computedSize(); 1124 webFontDescription->bold = fontDescription.weight() >= WebCore::FontWeight600; 1125 webFontDescription->italic = fontDescription.italic(); 1126 1127 return S_OK; 1128 } 1129 1130 HRESULT STDMETHODCALLTYPE DOMElement::renderedImage(HBITMAP* image) 1131 { 1132 if (!image) { 1133 ASSERT_NOT_REACHED(); 1134 return E_POINTER; 1135 } 1136 *image = 0; 1137 1138 ASSERT(m_element); 1139 1140 Frame* frame = m_element->document()->frame(); 1141 if (!frame) 1142 return E_FAIL; 1143 1144 *image = frame->nodeImage(m_element); 1145 if (!*image) 1146 return E_FAIL; 1147 1148 return S_OK; 1149 } 1150 1151 HRESULT STDMETHODCALLTYPE DOMElement::markerTextForListItem( 1152 /* [retval][out] */ BSTR* markerText) 1153 { 1154 if (!markerText) 1155 return E_POINTER; 1156 1157 ASSERT(m_element); 1158 1159 *markerText = BString(WebCore::markerTextForListItem(m_element)).release(); 1160 return S_OK; 1161 } 1162 1163 // IDOMElementCSSInlineStyle -------------------------------------------------- 1164 1165 HRESULT STDMETHODCALLTYPE DOMElement::style( 1166 /* [retval][out] */ IDOMCSSStyleDeclaration** result) 1167 { 1168 if (!result) 1169 return E_POINTER; 1170 if (!m_element) 1171 return E_FAIL; 1172 1173 WebCore::CSSStyleDeclaration* style = m_element->style(); 1174 if (!style) 1175 return E_FAIL; 1176 1177 *result = DOMCSSStyleDeclaration::createInstance(style); 1178 return *result ? S_OK : E_FAIL; 1179 } 1180 1181 // IDOMElementExtensions ------------------------------------------------------ 1182 1183 HRESULT STDMETHODCALLTYPE DOMElement::offsetLeft( 1184 /* [retval][out] */ int* result) 1185 { 1186 if (!m_element) 1187 return E_FAIL; 1188 1189 *result = m_element->offsetLeft(); 1190 return S_OK; 1191 } 1192 1193 HRESULT STDMETHODCALLTYPE DOMElement::offsetTop( 1194 /* [retval][out] */ int* result) 1195 { 1196 if (!m_element) 1197 return E_FAIL; 1198 1199 *result = m_element->offsetTop(); 1200 return S_OK; 1201 } 1202 1203 HRESULT STDMETHODCALLTYPE DOMElement::offsetWidth( 1204 /* [retval][out] */ int* result) 1205 { 1206 if (!m_element) 1207 return E_FAIL; 1208 1209 *result = m_element->offsetWidth(); 1210 return S_OK; 1211 } 1212 1213 HRESULT STDMETHODCALLTYPE DOMElement::offsetHeight( 1214 /* [retval][out] */ int* result) 1215 { 1216 if (!m_element) 1217 return E_FAIL; 1218 1219 *result = m_element->offsetHeight(); 1220 return S_OK; 1221 } 1222 1223 HRESULT STDMETHODCALLTYPE DOMElement::offsetParent( 1224 /* [retval][out] */ IDOMElement** /*result*/) 1225 { 1226 // FIXME 1227 ASSERT_NOT_REACHED(); 1228 return E_NOTIMPL; 1229 } 1230 1231 HRESULT STDMETHODCALLTYPE DOMElement::clientWidth( 1232 /* [retval][out] */ int* result) 1233 { 1234 if (!m_element) 1235 return E_FAIL; 1236 1237 *result = m_element->clientWidth(); 1238 return S_OK; 1239 } 1240 1241 HRESULT STDMETHODCALLTYPE DOMElement::clientHeight( 1242 /* [retval][out] */ int* result) 1243 { 1244 if (!m_element) 1245 return E_FAIL; 1246 1247 *result = m_element->clientHeight(); 1248 return S_OK; 1249 } 1250 1251 HRESULT STDMETHODCALLTYPE DOMElement::scrollLeft( 1252 /* [retval][out] */ int* result) 1253 { 1254 if (!m_element) 1255 return E_FAIL; 1256 1257 *result = m_element->scrollLeft(); 1258 return S_OK; 1259 } 1260 1261 HRESULT STDMETHODCALLTYPE DOMElement::setScrollLeft( 1262 /* [in] */ int /*newScrollLeft*/) 1263 { 1264 // FIXME 1265 ASSERT_NOT_REACHED(); 1266 return E_NOTIMPL; 1267 } 1268 1269 HRESULT STDMETHODCALLTYPE DOMElement::scrollTop( 1270 /* [retval][out] */ int* result) 1271 { 1272 if (!m_element) 1273 return E_FAIL; 1274 1275 *result = m_element->scrollTop(); 1276 return S_OK; 1277 } 1278 1279 HRESULT STDMETHODCALLTYPE DOMElement::setScrollTop( 1280 /* [in] */ int /*newScrollTop*/) 1281 { 1282 // FIXME 1283 ASSERT_NOT_REACHED(); 1284 return E_NOTIMPL; 1285 } 1286 1287 HRESULT STDMETHODCALLTYPE DOMElement::scrollWidth( 1288 /* [retval][out] */ int* result) 1289 { 1290 if (!m_element) 1291 return E_FAIL; 1292 1293 *result = m_element->scrollWidth(); 1294 return S_OK; 1295 } 1296 1297 HRESULT STDMETHODCALLTYPE DOMElement::scrollHeight( 1298 /* [retval][out] */ int* result) 1299 { 1300 if (!m_element) 1301 return E_FAIL; 1302 1303 *result = m_element->scrollHeight(); 1304 return S_OK; 1305 } 1306 1307 HRESULT STDMETHODCALLTYPE DOMElement::scrollIntoView( 1308 /* [in] */ BOOL alignWithTop) 1309 { 1310 if (!m_element) 1311 return E_FAIL; 1312 1313 m_element->scrollIntoView(!!alignWithTop); 1314 return S_OK; 1315 } 1316 1317 HRESULT STDMETHODCALLTYPE DOMElement::scrollIntoViewIfNeeded( 1318 /* [in] */ BOOL centerIfNeeded) 1319 { 1320 if (!m_element) 1321 return E_FAIL; 1322 1323 m_element->scrollIntoViewIfNeeded(!!centerIfNeeded); 1324 return S_OK; 1325 } 1326 1327 // DOMElement ----------------------------------------------------------------- 1328 1329 DOMElement::DOMElement(WebCore::Element* e) 1330 : DOMNode(e) 1331 , m_element(e) 1332 { 1333 } 1334 1335 DOMElement::~DOMElement() 1336 { 1337 } 1338 1339 IDOMElement* DOMElement::createInstance(WebCore::Element* e) 1340 { 1341 if (!e) 1342 return 0; 1343 1344 HRESULT hr; 1345 IDOMElement* domElement = 0; 1346 1347 if (e->hasTagName(formTag)) { 1348 DOMHTMLFormElement* newElement = new DOMHTMLFormElement(e); 1349 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1350 } else if (e->hasTagName(iframeTag)) { 1351 DOMHTMLIFrameElement* newElement = new DOMHTMLIFrameElement(e); 1352 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1353 } else if (e->hasTagName(inputTag)) { 1354 DOMHTMLInputElement* newElement = new DOMHTMLInputElement(e); 1355 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1356 } else if (e->hasTagName(optionTag)) { 1357 DOMHTMLOptionElement* newElement = new DOMHTMLOptionElement(e); 1358 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1359 } else if (e->hasTagName(selectTag)) { 1360 DOMHTMLSelectElement* newElement = new DOMHTMLSelectElement(e); 1361 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1362 } else if (e->hasTagName(textareaTag)) { 1363 DOMHTMLTextAreaElement* newElement = new DOMHTMLTextAreaElement(e); 1364 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1365 } else if (e->isHTMLElement()) { 1366 DOMHTMLElement* newElement = new DOMHTMLElement(e); 1367 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1368 } else { 1369 DOMElement* newElement = new DOMElement(e); 1370 hr = newElement->QueryInterface(IID_IDOMElement, (void**)&domElement); 1371 } 1372 1373 if (FAILED(hr)) 1374 return 0; 1375 1376 return domElement; 1377 } 1378