1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Peter Kelly (pmk (at) post.com) 5 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 6 * (C) 2007 David Smith (catfish.man (at) gmail.com) 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 8 * (C) 2007 Eric Seidel (eric (at) webkit.org) 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public License 21 * along with this library; see the file COPYING.LIB. If not, write to 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 * Boston, MA 02110-1301, USA. 24 */ 25 26 #include "config.h" 27 #include "Element.h" 28 29 #include "AXObjectCache.h" 30 #include "Attr.h" 31 #include "CSSParser.h" 32 #include "CSSSelectorList.h" 33 #include "CSSStyleSelector.h" 34 #include "CString.h" 35 #include "ClientRect.h" 36 #include "ClientRectList.h" 37 #include "Document.h" 38 #include "ElementRareData.h" 39 #include "ExceptionCode.h" 40 #include "FocusController.h" 41 #include "Frame.h" 42 #include "FrameView.h" 43 #include "HTMLElement.h" 44 #include "HTMLNames.h" 45 #include "InspectorController.h" 46 #include "NamedNodeMap.h" 47 #include "NodeList.h" 48 #include "NodeRenderStyle.h" 49 #include "Page.h" 50 #include "RenderView.h" 51 #include "RenderWidget.h" 52 #include "TextIterator.h" 53 #include "XMLNames.h" 54 55 #if ENABLE(SVG) 56 #include "SVGNames.h" 57 #endif 58 59 namespace WebCore { 60 61 using namespace HTMLNames; 62 using namespace XMLNames; 63 64 Element::Element(const QualifiedName& tagName, Document* document, ConstructionType type) 65 : ContainerNode(document, type) 66 , m_tagName(tagName) 67 { 68 } 69 70 PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document) 71 { 72 return adoptRef(new Element(tagName, document, CreateElement)); 73 } 74 75 Element::~Element() 76 { 77 if (namedAttrMap) 78 namedAttrMap->detachFromElement(); 79 } 80 81 inline ElementRareData* Element::rareData() const 82 { 83 ASSERT(hasRareData()); 84 return static_cast<ElementRareData*>(NodeRareData::rareDataFromMap(this)); 85 } 86 87 inline ElementRareData* Element::ensureRareData() 88 { 89 return static_cast<ElementRareData*>(Node::ensureRareData()); 90 } 91 92 NodeRareData* Element::createRareData() 93 { 94 return new ElementRareData; 95 } 96 97 PassRefPtr<Node> Element::cloneNode(bool deep) 98 { 99 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren(); 100 } 101 102 PassRefPtr<Element> Element::cloneElementWithChildren() 103 { 104 RefPtr<Element> clone = cloneElementWithoutChildren(); 105 cloneChildNodes(clone.get()); 106 return clone.release(); 107 } 108 109 PassRefPtr<Element> Element::cloneElementWithoutChildren() 110 { 111 RefPtr<Element> clone = document()->createElement(tagQName(), false); 112 // This will catch HTML elements in the wrong namespace that are not correctly copied. 113 // This is a sanity check as HTML overloads some of the DOM methods. 114 ASSERT(isHTMLElement() == clone->isHTMLElement()); 115 116 clone->copyNonAttributeProperties(this); 117 118 // Clone attributes. 119 if (namedAttrMap) 120 clone->attributes()->setAttributes(*attributes(true)); // Call attributes(true) to force attribute synchronization to occur (for svg and style) before cloning happens. 121 122 return clone.release(); 123 } 124 125 void Element::removeAttribute(const QualifiedName& name, ExceptionCode& ec) 126 { 127 if (namedAttrMap) { 128 ec = 0; 129 namedAttrMap->removeNamedItem(name, ec); 130 if (ec == NOT_FOUND_ERR) 131 ec = 0; 132 } 133 } 134 135 void Element::setAttribute(const QualifiedName& name, const AtomicString& value) 136 { 137 ExceptionCode ec; 138 setAttribute(name, value, ec); 139 } 140 141 void Element::setCStringAttribute(const QualifiedName& name, const char* cStringValue) 142 { 143 ExceptionCode ec; 144 setAttribute(name, AtomicString(cStringValue), ec); 145 } 146 147 void Element::setBooleanAttribute(const QualifiedName& name, bool b) 148 { 149 if (b) 150 setAttribute(name, name.localName()); 151 else { 152 ExceptionCode ex; 153 removeAttribute(name, ex); 154 } 155 } 156 157 // Virtual function, defined in base class. 158 NamedNodeMap* Element::attributes() const 159 { 160 return attributes(false); 161 } 162 163 Node::NodeType Element::nodeType() const 164 { 165 return ELEMENT_NODE; 166 } 167 168 const AtomicString& Element::getIDAttribute() const 169 { 170 return namedAttrMap ? namedAttrMap->id() : nullAtom; 171 } 172 173 bool Element::hasAttribute(const QualifiedName& name) const 174 { 175 return hasAttributeNS(name.namespaceURI(), name.localName()); 176 } 177 178 const AtomicString& Element::getAttribute(const QualifiedName& name) const 179 { 180 if (name == styleAttr && !m_isStyleAttributeValid) 181 updateStyleAttribute(); 182 183 #if ENABLE(SVG) 184 if (!m_areSVGAttributesValid) 185 updateAnimatedSVGAttribute(name); 186 #endif 187 188 if (namedAttrMap) 189 if (Attribute* a = namedAttrMap->getAttributeItem(name)) 190 return a->value(); 191 192 return nullAtom; 193 } 194 195 void Element::scrollIntoView(bool alignToTop) 196 { 197 document()->updateLayoutIgnorePendingStylesheets(); 198 IntRect bounds = getRect(); 199 if (renderer()) { 200 // Align to the top / bottom and to the closest edge. 201 if (alignToTop) 202 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); 203 else 204 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways); 205 } 206 } 207 208 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded) 209 { 210 document()->updateLayoutIgnorePendingStylesheets(); 211 IntRect bounds = getRect(); 212 if (renderer()) { 213 if (centerIfNeeded) 214 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded); 215 else 216 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); 217 } 218 } 219 220 void Element::scrollByUnits(int units, ScrollGranularity granularity) 221 { 222 document()->updateLayoutIgnorePendingStylesheets(); 223 if (RenderObject *rend = renderer()) { 224 if (rend->hasOverflowClip()) { 225 ScrollDirection direction = ScrollDown; 226 if (units < 0) { 227 direction = ScrollUp; 228 units = -units; 229 } 230 toRenderBox(rend)->layer()->scroll(direction, granularity, units); 231 } 232 } 233 } 234 235 void Element::scrollByLines(int lines) 236 { 237 scrollByUnits(lines, ScrollByLine); 238 } 239 240 void Element::scrollByPages(int pages) 241 { 242 scrollByUnits(pages, ScrollByPage); 243 } 244 245 static float localZoomForRenderer(RenderObject* renderer) 246 { 247 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each 248 // other out, but the alternative is that we'd have to crawl up the whole render tree every 249 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified). 250 float zoomFactor = 1.0f; 251 if (renderer->style()->effectiveZoom() != 1.0f) { 252 // Need to find the nearest enclosing RenderObject that set up 253 // a differing zoom, and then we divide our result by it to eliminate the zoom. 254 RenderObject* prev = renderer; 255 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) { 256 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) { 257 zoomFactor = prev->style()->zoom(); 258 break; 259 } 260 prev = curr; 261 } 262 if (prev->isRenderView()) 263 zoomFactor = prev->style()->zoom(); 264 } 265 return zoomFactor; 266 } 267 268 static int adjustForLocalZoom(int value, RenderObject* renderer) 269 { 270 float zoomFactor = localZoomForRenderer(renderer); 271 if (zoomFactor == 1) 272 return value; 273 // Needed because computeLengthInt truncates (rather than rounds) when scaling up. 274 if (zoomFactor > 1) 275 value++; 276 return static_cast<int>(value / zoomFactor); 277 } 278 279 int Element::offsetLeft() 280 { 281 document()->updateLayoutIgnorePendingStylesheets(); 282 if (RenderBoxModelObject* rend = renderBoxModelObject()) 283 return adjustForLocalZoom(rend->offsetLeft(), rend); 284 return 0; 285 } 286 287 int Element::offsetTop() 288 { 289 document()->updateLayoutIgnorePendingStylesheets(); 290 if (RenderBoxModelObject* rend = renderBoxModelObject()) 291 return adjustForLocalZoom(rend->offsetTop(), rend); 292 return 0; 293 } 294 295 int Element::offsetWidth() 296 { 297 document()->updateLayoutIgnorePendingStylesheets(); 298 if (RenderBoxModelObject* rend = renderBoxModelObject()) 299 return adjustForAbsoluteZoom(rend->offsetWidth(), rend); 300 return 0; 301 } 302 303 int Element::offsetHeight() 304 { 305 document()->updateLayoutIgnorePendingStylesheets(); 306 if (RenderBoxModelObject* rend = renderBoxModelObject()) 307 return adjustForAbsoluteZoom(rend->offsetHeight(), rend); 308 return 0; 309 } 310 311 Element* Element::offsetParent() 312 { 313 document()->updateLayoutIgnorePendingStylesheets(); 314 if (RenderObject* rend = renderer()) 315 if (RenderObject* offsetParent = rend->offsetParent()) 316 return static_cast<Element*>(offsetParent->node()); 317 return 0; 318 } 319 320 int Element::clientLeft() 321 { 322 document()->updateLayoutIgnorePendingStylesheets(); 323 324 if (RenderBox* rend = renderBox()) 325 return adjustForAbsoluteZoom(rend->clientLeft(), rend); 326 return 0; 327 } 328 329 int Element::clientTop() 330 { 331 document()->updateLayoutIgnorePendingStylesheets(); 332 333 if (RenderBox* rend = renderBox()) 334 return adjustForAbsoluteZoom(rend->clientTop(), rend); 335 return 0; 336 } 337 338 int Element::clientWidth() 339 { 340 document()->updateLayoutIgnorePendingStylesheets(); 341 342 // When in strict mode, clientWidth for the document element should return the width of the containing frame. 343 // When in quirks mode, clientWidth for the body element should return the width of the containing frame. 344 bool inCompatMode = document()->inCompatMode(); 345 if ((!inCompatMode && document()->documentElement() == this) || 346 (inCompatMode && isHTMLElement() && document()->body() == this)) { 347 if (FrameView* view = document()->view()) { 348 if (RenderView* renderView = document()->renderView()) 349 return adjustForAbsoluteZoom(view->layoutWidth(), renderView); 350 } 351 } 352 353 if (RenderBox* rend = renderBox()) 354 return adjustForAbsoluteZoom(rend->clientWidth(), rend); 355 return 0; 356 } 357 358 int Element::clientHeight() 359 { 360 document()->updateLayoutIgnorePendingStylesheets(); 361 362 // When in strict mode, clientHeight for the document element should return the height of the containing frame. 363 // When in quirks mode, clientHeight for the body element should return the height of the containing frame. 364 bool inCompatMode = document()->inCompatMode(); 365 366 if ((!inCompatMode && document()->documentElement() == this) || 367 (inCompatMode && isHTMLElement() && document()->body() == this)) { 368 if (FrameView* view = document()->view()) { 369 if (RenderView* renderView = document()->renderView()) 370 return adjustForAbsoluteZoom(view->layoutHeight(), renderView); 371 } 372 } 373 374 if (RenderBox* rend = renderBox()) 375 return adjustForAbsoluteZoom(rend->clientHeight(), rend); 376 return 0; 377 } 378 379 int Element::scrollLeft() const 380 { 381 document()->updateLayoutIgnorePendingStylesheets(); 382 if (RenderBox* rend = renderBox()) 383 return adjustForAbsoluteZoom(rend->scrollLeft(), rend); 384 return 0; 385 } 386 387 int Element::scrollTop() const 388 { 389 document()->updateLayoutIgnorePendingStylesheets(); 390 if (RenderBox* rend = renderBox()) 391 return adjustForAbsoluteZoom(rend->scrollTop(), rend); 392 return 0; 393 } 394 395 void Element::setScrollLeft(int newLeft) 396 { 397 document()->updateLayoutIgnorePendingStylesheets(); 398 if (RenderBox* rend = renderBox()) 399 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom())); 400 } 401 402 void Element::setScrollTop(int newTop) 403 { 404 document()->updateLayoutIgnorePendingStylesheets(); 405 if (RenderBox* rend = renderBox()) 406 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom())); 407 } 408 409 int Element::scrollWidth() const 410 { 411 document()->updateLayoutIgnorePendingStylesheets(); 412 if (RenderBox* rend = renderBox()) 413 return adjustForAbsoluteZoom(rend->scrollWidth(), rend); 414 return 0; 415 } 416 417 int Element::scrollHeight() const 418 { 419 document()->updateLayoutIgnorePendingStylesheets(); 420 if (RenderBox* rend = renderBox()) 421 return adjustForAbsoluteZoom(rend->scrollHeight(), rend); 422 return 0; 423 } 424 425 PassRefPtr<ClientRectList> Element::getClientRects() const 426 { 427 document()->updateLayoutIgnorePendingStylesheets(); 428 429 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject(); 430 if (!renderBoxModelObject) 431 return ClientRectList::create(); 432 433 // FIXME: Handle SVG elements. 434 // FIXME: Handle table/inline-table with a caption. 435 436 Vector<FloatQuad> quads; 437 renderBoxModelObject->absoluteQuads(quads); 438 439 if (FrameView* view = document()->view()) { 440 IntRect visibleContentRect = view->visibleContentRect(); 441 for (size_t i = 0; i < quads.size(); ++i) { 442 quads[i].move(-visibleContentRect.x(), -visibleContentRect.y()); 443 adjustFloatQuadForAbsoluteZoom(quads[i], renderBoxModelObject); 444 } 445 } 446 447 return ClientRectList::create(quads); 448 } 449 450 PassRefPtr<ClientRect> Element::getBoundingClientRect() const 451 { 452 document()->updateLayoutIgnorePendingStylesheets(); 453 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject(); 454 if (!renderBoxModelObject) 455 return ClientRect::create(); 456 457 Vector<FloatQuad> quads; 458 renderBoxModelObject->absoluteQuads(quads); 459 460 if (quads.isEmpty()) 461 return ClientRect::create(); 462 463 IntRect result = quads[0].enclosingBoundingBox(); 464 for (size_t i = 1; i < quads.size(); ++i) 465 result.unite(quads[i].enclosingBoundingBox()); 466 467 if (FrameView* view = document()->view()) { 468 IntRect visibleContentRect = view->visibleContentRect(); 469 result.move(-visibleContentRect.x(), -visibleContentRect.y()); 470 } 471 472 adjustIntRectForAbsoluteZoom(result, renderBoxModelObject); 473 474 return ClientRect::create(result); 475 } 476 477 static inline bool shouldIgnoreAttributeCase(const Element* e) 478 { 479 return e && e->document()->isHTMLDocument() && e->isHTMLElement(); 480 } 481 482 const AtomicString& Element::getAttribute(const String& name) const 483 { 484 bool ignoreCase = shouldIgnoreAttributeCase(this); 485 486 // Update the 'style' attribute if it's invalid and being requested: 487 if (!m_isStyleAttributeValid && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase)) 488 updateStyleAttribute(); 489 490 #if ENABLE(SVG) 491 if (!m_areSVGAttributesValid) { 492 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well. 493 updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom)); 494 } 495 #endif 496 497 if (namedAttrMap) 498 if (Attribute* attribute = namedAttrMap->getAttributeItem(name, ignoreCase)) 499 return attribute->value(); 500 501 return nullAtom; 502 } 503 504 const AtomicString& Element::getAttributeNS(const String& namespaceURI, const String& localName) const 505 { 506 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI)); 507 } 508 509 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec) 510 { 511 if (!Document::isValidName(name)) { 512 ec = INVALID_CHARACTER_ERR; 513 return; 514 } 515 516 const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 517 518 // allocate attributemap if necessary 519 Attribute* old = attributes(false)->getAttributeItem(localName, false); 520 521 document()->incDOMTreeVersion(); 522 523 if (localName == idAttributeName().localName()) 524 updateId(old ? old->value() : nullAtom, value); 525 526 if (old && value.isNull()) 527 namedAttrMap->removeAttribute(old->name()); 528 else if (!old && !value.isNull()) 529 namedAttrMap->addAttribute(createAttribute(QualifiedName(nullAtom, localName, nullAtom), value)); 530 else if (old && !value.isNull()) { 531 old->setValue(value); 532 attributeChanged(old); 533 } 534 535 #if ENABLE(INSPECTOR) 536 if (Page* page = document()->page()) { 537 if (InspectorController* inspectorController = page->inspectorController()) { 538 if (!m_synchronizingStyleAttribute) 539 inspectorController->didModifyDOMAttr(this); 540 } 541 } 542 #endif 543 } 544 545 void Element::setAttribute(const QualifiedName& name, const AtomicString& value, ExceptionCode&) 546 { 547 document()->incDOMTreeVersion(); 548 549 // allocate attributemap if necessary 550 Attribute* old = attributes(false)->getAttributeItem(name); 551 552 if (name == idAttributeName()) 553 updateId(old ? old->value() : nullAtom, value); 554 555 if (old && value.isNull()) 556 namedAttrMap->removeAttribute(name); 557 else if (!old && !value.isNull()) 558 namedAttrMap->addAttribute(createAttribute(name, value)); 559 else if (old) { 560 old->setValue(value); 561 attributeChanged(old); 562 } 563 564 #if ENABLE(INSPECTOR) 565 if (Page* page = document()->page()) { 566 if (InspectorController* inspectorController = page->inspectorController()) { 567 if (!m_synchronizingStyleAttribute) 568 inspectorController->didModifyDOMAttr(this); 569 } 570 } 571 #endif 572 } 573 574 PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const AtomicString& value) 575 { 576 return Attribute::create(name, value); 577 } 578 579 void Element::attributeChanged(Attribute* attr, bool) 580 { 581 recalcStyleIfNeededAfterAttributeChanged(attr); 582 updateAfterAttributeChanged(attr); 583 } 584 585 void Element::updateAfterAttributeChanged(Attribute* attr) 586 { 587 if (!AXObjectCache::accessibilityEnabled()) 588 return; 589 590 const QualifiedName& attrName = attr->name(); 591 if (attrName == aria_activedescendantAttr) { 592 // any change to aria-activedescendant attribute triggers accessibility focus change, but document focus remains intact 593 document()->axObjectCache()->handleActiveDescendantChanged(renderer()); 594 } else if (attrName == roleAttr) { 595 // the role attribute can change at any time, and the AccessibilityObject must pick up these changes 596 document()->axObjectCache()->handleAriaRoleChanged(renderer()); 597 } else if (attrName == aria_valuenowAttr) { 598 // If the valuenow attribute changes, AX clients need to be notified. 599 document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXValueChanged, true); 600 } else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == altAttr || attrName == titleAttr) { 601 // If the content of an element changes due to an attribute change, notify accessibility. 602 document()->axObjectCache()->contentChanged(renderer()); 603 } 604 } 605 606 void Element::recalcStyleIfNeededAfterAttributeChanged(Attribute* attr) 607 { 608 if (document()->attached() && document()->styleSelector()->hasSelectorForAttribute(attr->name().localName())) 609 setNeedsStyleRecalc(); 610 } 611 612 // Returns true is the given attribute is an event handler. 613 // We consider an event handler any attribute that begins with "on". 614 // It is a simple solution that has the advantage of not requiring any 615 // code or configuration change if a new event handler is defined. 616 617 static bool isEventHandlerAttribute(const QualifiedName& name) 618 { 619 return name.namespaceURI().isNull() && name.localName().startsWith("on"); 620 } 621 622 static bool isAttributeToRemove(const QualifiedName& name, const AtomicString& value) 623 { 624 return (name.localName().endsWith(hrefAttr.localName()) || name == srcAttr || name == actionAttr) && protocolIsJavaScript(deprecatedParseURL(value)); 625 } 626 627 void Element::setAttributeMap(PassRefPtr<NamedNodeMap> list, FragmentScriptingPermission scriptingPermission) 628 { 629 document()->incDOMTreeVersion(); 630 631 // If setting the whole map changes the id attribute, we need to call updateId. 632 633 const QualifiedName& idName = idAttributeName(); 634 Attribute* oldId = namedAttrMap ? namedAttrMap->getAttributeItem(idName) : 0; 635 Attribute* newId = list ? list->getAttributeItem(idName) : 0; 636 637 if (oldId || newId) 638 updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom); 639 640 if (namedAttrMap) 641 namedAttrMap->m_element = 0; 642 643 namedAttrMap = list; 644 645 if (namedAttrMap) { 646 namedAttrMap->m_element = this; 647 // If the element is created as result of a paste or drag-n-drop operation 648 // we want to remove all the script and event handlers. 649 if (scriptingPermission == FragmentScriptingNotAllowed) { 650 unsigned i = 0; 651 while (i < namedAttrMap->length()) { 652 const QualifiedName& attributeName = namedAttrMap->m_attributes[i]->name(); 653 if (isEventHandlerAttribute(attributeName)) { 654 namedAttrMap->m_attributes.remove(i); 655 continue; 656 } 657 658 if (isAttributeToRemove(attributeName, namedAttrMap->m_attributes[i]->value())) 659 namedAttrMap->m_attributes[i]->setValue(nullAtom); 660 i++; 661 } 662 } 663 unsigned len = namedAttrMap->length(); 664 for (unsigned i = 0; i < len; i++) 665 attributeChanged(namedAttrMap->m_attributes[i].get()); 666 // FIXME: What about attributes that were in the old map that are not in the new map? 667 } 668 } 669 670 bool Element::hasAttributes() const 671 { 672 if (!m_isStyleAttributeValid) 673 updateStyleAttribute(); 674 675 #if ENABLE(SVG) 676 if (!m_areSVGAttributesValid) 677 updateAnimatedSVGAttribute(anyQName()); 678 #endif 679 680 return namedAttrMap && namedAttrMap->length() > 0; 681 } 682 683 String Element::nodeName() const 684 { 685 return m_tagName.toString(); 686 } 687 688 String Element::nodeNamePreservingCase() const 689 { 690 return m_tagName.toString(); 691 } 692 693 void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec) 694 { 695 ec = 0; 696 checkSetPrefix(prefix, ec); 697 if (ec) 698 return; 699 700 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix); 701 } 702 703 KURL Element::baseURI() const 704 { 705 const AtomicString& baseAttribute = getAttribute(baseAttr); 706 KURL base(KURL(), baseAttribute); 707 if (!base.protocol().isEmpty()) 708 return base; 709 710 Node* parent = parentNode(); 711 if (!parent) 712 return base; 713 714 const KURL& parentBase = parent->baseURI(); 715 if (parentBase.isNull()) 716 return base; 717 718 return KURL(parentBase, baseAttribute); 719 } 720 721 void Element::createAttributeMap() const 722 { 723 namedAttrMap = NamedNodeMap::create(const_cast<Element*>(this)); 724 } 725 726 bool Element::isURLAttribute(Attribute*) const 727 { 728 return false; 729 } 730 731 const QualifiedName& Element::imageSourceAttributeName() const 732 { 733 return srcAttr; 734 } 735 736 RenderObject* Element::createRenderer(RenderArena* arena, RenderStyle* style) 737 { 738 if (document()->documentElement() == this && style->display() == NONE) { 739 // Ignore display: none on root elements. Force a display of block in that case. 740 RenderBlock* result = new (arena) RenderBlock(this); 741 if (result) 742 result->setAnimatableStyle(style); 743 return result; 744 } 745 return RenderObject::createObject(this, style); 746 } 747 748 749 void Element::insertedIntoDocument() 750 { 751 // need to do superclass processing first so inDocument() is true 752 // by the time we reach updateId 753 ContainerNode::insertedIntoDocument(); 754 755 if (hasID()) { 756 if (NamedNodeMap* attrs = namedAttrMap.get()) { 757 Attribute* idItem = attrs->getAttributeItem(idAttributeName()); 758 if (idItem && !idItem->isNull()) 759 updateId(nullAtom, idItem->value()); 760 } 761 } 762 } 763 764 void Element::removedFromDocument() 765 { 766 if (hasID()) { 767 if (NamedNodeMap* attrs = namedAttrMap.get()) { 768 Attribute* idItem = attrs->getAttributeItem(idAttributeName()); 769 if (idItem && !idItem->isNull()) 770 updateId(idItem->value(), nullAtom); 771 } 772 } 773 774 ContainerNode::removedFromDocument(); 775 } 776 777 void Element::attach() 778 { 779 suspendPostAttachCallbacks(); 780 RenderWidget::suspendWidgetHierarchyUpdates(); 781 782 createRendererIfNeeded(); 783 ContainerNode::attach(); 784 if (hasRareData()) { 785 ElementRareData* data = rareData(); 786 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) { 787 if (isFocusable() && document()->focusedNode() == this) 788 document()->updateFocusAppearanceSoon(false /* don't restore selection */); 789 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false); 790 } 791 } 792 793 RenderWidget::resumeWidgetHierarchyUpdates(); 794 resumePostAttachCallbacks(); 795 } 796 797 void Element::detach() 798 { 799 RenderWidget::suspendWidgetHierarchyUpdates(); 800 801 cancelFocusAppearanceUpdate(); 802 if (hasRareData()) 803 rareData()->resetComputedStyle(); 804 ContainerNode::detach(); 805 806 RenderWidget::resumeWidgetHierarchyUpdates(); 807 } 808 809 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle) 810 { 811 ASSERT(currentStyle == renderStyle()); 812 813 if (!renderer() || !currentStyle) 814 return false; 815 816 RenderStyle::PseudoStyleCache pseudoStyleCache; 817 currentStyle->getPseudoStyleCache(pseudoStyleCache); 818 size_t cacheSize = pseudoStyleCache.size(); 819 for (size_t i = 0; i < cacheSize; ++i) { 820 RefPtr<RenderStyle> newPseudoStyle; 821 PseudoId pseudoId = pseudoStyleCache[i]->styleType(); 822 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) 823 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle); 824 else 825 newPseudoStyle = renderer()->getUncachedPseudoStyle(pseudoId, newStyle, newStyle); 826 827 if (*newPseudoStyle != *pseudoStyleCache[i]) { 828 if (pseudoId < FIRST_INTERNAL_PSEUDOID) 829 newStyle->setHasPseudoStyle(pseudoId); 830 newStyle->addCachedPseudoStyle(newPseudoStyle); 831 return true; 832 } 833 } 834 return false; 835 } 836 837 void Element::recalcStyle(StyleChange change) 838 { 839 // Ref currentStyle in case it would otherwise be deleted when setRenderStyle() is called. 840 RefPtr<RenderStyle> currentStyle(renderStyle()); 841 bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false; 842 bool hasPositionalRules = needsStyleRecalc() && currentStyle && currentStyle->childrenAffectedByPositionalRules(); 843 bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules(); 844 845 #if ENABLE(SVG) 846 if (!hasParentStyle && isShadowNode() && isSVGElement()) 847 hasParentStyle = true; 848 #endif 849 850 if ((change > NoChange || needsStyleRecalc())) { 851 if (hasRareData()) 852 rareData()->resetComputedStyle(); 853 } 854 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) { 855 RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this); 856 StyleChange ch = diff(currentStyle.get(), newStyle.get()); 857 if (ch == Detach || !currentStyle) { 858 if (attached()) 859 detach(); 860 attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along. 861 // attach recalulates the style for all children. No need to do it twice. 862 setNeedsStyleRecalc(NoStyleChange); 863 setChildNeedsStyleRecalc(false); 864 return; 865 } 866 867 if (currentStyle) { 868 // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full 869 // style change (e.g., only inline style changed). 870 if (currentStyle->affectedByHoverRules()) 871 newStyle->setAffectedByHoverRules(true); 872 if (currentStyle->affectedByActiveRules()) 873 newStyle->setAffectedByActiveRules(true); 874 if (currentStyle->affectedByDragRules()) 875 newStyle->setAffectedByDragRules(true); 876 if (currentStyle->childrenAffectedByForwardPositionalRules()) 877 newStyle->setChildrenAffectedByForwardPositionalRules(); 878 if (currentStyle->childrenAffectedByBackwardPositionalRules()) 879 newStyle->setChildrenAffectedByBackwardPositionalRules(); 880 if (currentStyle->childrenAffectedByFirstChildRules()) 881 newStyle->setChildrenAffectedByFirstChildRules(); 882 if (currentStyle->childrenAffectedByLastChildRules()) 883 newStyle->setChildrenAffectedByLastChildRules(); 884 if (currentStyle->childrenAffectedByDirectAdjacentRules()) 885 newStyle->setChildrenAffectedByDirectAdjacentRules(); 886 } 887 888 if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get())) { 889 setRenderStyle(newStyle); 890 } else if (needsStyleRecalc() && (styleChangeType() != SyntheticStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) { 891 // Although no change occurred, we use the new style so that the cousin style sharing code won't get 892 // fooled into believing this style is the same. This is only necessary if the document actually uses 893 // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of 894 // descendants. 895 if (renderer()) 896 renderer()->setStyleInternal(newStyle.get()); 897 else 898 setRenderStyle(newStyle); 899 } else if (styleChangeType() == SyntheticStyleChange) 900 setRenderStyle(newStyle); 901 902 if (change != Force) { 903 // If "rem" units are used anywhere in the document, and if the document element's font size changes, then go ahead and force font updating 904 // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway). 905 if (document()->usesRemUnits() && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize() && document()->documentElement() == this) 906 change = Force; 907 else if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange) 908 change = Force; 909 else 910 change = ch; 911 } 912 } 913 914 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar. 915 // For now we will just worry about the common case, since it's a lot trickier to get the second case right 916 // without doing way too much re-resolution. 917 bool forceCheckOfNextElementSibling = false; 918 for (Node *n = firstChild(); n; n = n->nextSibling()) { 919 bool childRulesChanged = n->needsStyleRecalc() && n->styleChangeType() == FullStyleChange; 920 if (forceCheckOfNextElementSibling && n->isElementNode()) 921 n->setNeedsStyleRecalc(); 922 if (change >= Inherit || n->isTextNode() || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) 923 n->recalcStyle(change); 924 if (n->isElementNode()) 925 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules; 926 } 927 928 setNeedsStyleRecalc(NoStyleChange); 929 setChildNeedsStyleRecalc(false); 930 } 931 932 bool Element::childTypeAllowed(NodeType type) 933 { 934 switch (type) { 935 case ELEMENT_NODE: 936 case TEXT_NODE: 937 case COMMENT_NODE: 938 case PROCESSING_INSTRUCTION_NODE: 939 case CDATA_SECTION_NODE: 940 case ENTITY_REFERENCE_NODE: 941 return true; 942 break; 943 default: 944 return false; 945 } 946 } 947 948 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback, 949 Node* beforeChange, Node* afterChange, int childCountDelta) 950 { 951 if (!style || (e->needsStyleRecalc() && style->childrenAffectedByPositionalRules())) 952 return; 953 954 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time. 955 // In the DOM case, we only need to do something if |afterChange| is not 0. 956 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block. 957 if (style->childrenAffectedByFirstChildRules() && afterChange) { 958 // Find our new first child. 959 Node* newFirstChild = 0; 960 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {}; 961 962 // Find the first element node following |afterChange| 963 Node* firstElementAfterInsertion = 0; 964 for (firstElementAfterInsertion = afterChange; 965 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); 966 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; 967 968 // This is the insert/append case. 969 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() && 970 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState()) 971 firstElementAfterInsertion->setNeedsStyleRecalc(); 972 973 // We also have to handle node removal. 974 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState()) 975 newFirstChild->setNeedsStyleRecalc(); 976 } 977 978 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time. 979 // In the DOM case, we only need to do something if |afterChange| is not 0. 980 if (style->childrenAffectedByLastChildRules() && beforeChange) { 981 // Find our new last child. 982 Node* newLastChild = 0; 983 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {}; 984 985 // Find the last element node going backwards from |beforeChange| 986 Node* lastElementBeforeInsertion = 0; 987 for (lastElementBeforeInsertion = beforeChange; 988 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode(); 989 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {}; 990 991 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() && 992 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState()) 993 lastElementBeforeInsertion->setNeedsStyleRecalc(); 994 995 // We also have to handle node removal. The parser callback case is similar to node removal as well in that we need to change the last child 996 // to match now. 997 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState()) 998 newLastChild->setNeedsStyleRecalc(); 999 } 1000 1001 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element 1002 // that could be affected by this DOM change. 1003 if (style->childrenAffectedByDirectAdjacentRules() && afterChange) { 1004 Node* firstElementAfterInsertion = 0; 1005 for (firstElementAfterInsertion = afterChange; 1006 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); 1007 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; 1008 if (firstElementAfterInsertion && firstElementAfterInsertion->attached()) 1009 firstElementAfterInsertion->setNeedsStyleRecalc(); 1010 } 1011 1012 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type. 1013 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type. 1014 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the 1015 // backward case. 1016 // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to. 1017 // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids 1018 // here. recalcStyle will then force a walk of the children when it sees that this has happened. 1019 if ((style->childrenAffectedByForwardPositionalRules() && afterChange) || 1020 (style->childrenAffectedByBackwardPositionalRules() && beforeChange)) 1021 e->setNeedsStyleRecalc(); 1022 1023 // :empty selector. 1024 if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes())) 1025 e->setNeedsStyleRecalc(); 1026 } 1027 1028 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 1029 { 1030 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 1031 if (!changedByParser) 1032 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta); 1033 } 1034 1035 void Element::finishParsingChildren() 1036 { 1037 ContainerNode::finishParsingChildren(); 1038 m_parsingChildrenFinished = true; 1039 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0); 1040 } 1041 1042 void Element::dispatchAttrRemovalEvent(Attribute*) 1043 { 1044 ASSERT(!eventDispatchForbidden()); 1045 1046 #if 0 1047 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER)) 1048 return; 1049 ExceptionCode ec = 0; 1050 dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(), 1051 attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec); 1052 #endif 1053 } 1054 1055 void Element::dispatchAttrAdditionEvent(Attribute*) 1056 { 1057 ASSERT(!eventDispatchForbidden()); 1058 1059 #if 0 1060 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER)) 1061 return; 1062 ExceptionCode ec = 0; 1063 dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(), 1064 attr->value(), document()->attrName(attr->id()), MutationEvent::ADDITION), ec); 1065 #endif 1066 } 1067 1068 String Element::openTagStartToString() const 1069 { 1070 String result = "<" + nodeName(); 1071 1072 NamedNodeMap* attrMap = attributes(true); 1073 1074 if (attrMap) { 1075 unsigned numAttrs = attrMap->length(); 1076 for (unsigned i = 0; i < numAttrs; i++) { 1077 result += " "; 1078 1079 Attribute *attribute = attrMap->attributeItem(i); 1080 result += attribute->name().toString(); 1081 if (!attribute->value().isNull()) { 1082 result += "=\""; 1083 // FIXME: substitute entities for any instances of " or ' 1084 result += attribute->value(); 1085 result += "\""; 1086 } 1087 } 1088 } 1089 1090 return result; 1091 } 1092 1093 #ifndef NDEBUG 1094 void Element::formatForDebugger(char* buffer, unsigned length) const 1095 { 1096 String result; 1097 String s; 1098 1099 s = nodeName(); 1100 if (s.length() > 0) { 1101 result += s; 1102 } 1103 1104 s = getAttribute(idAttributeName()); 1105 if (s.length() > 0) { 1106 if (result.length() > 0) 1107 result += "; "; 1108 result += "id="; 1109 result += s; 1110 } 1111 1112 s = getAttribute(classAttr); 1113 if (s.length() > 0) { 1114 if (result.length() > 0) 1115 result += "; "; 1116 result += "class="; 1117 result += s; 1118 } 1119 1120 strncpy(buffer, result.utf8().data(), length - 1); 1121 } 1122 #endif 1123 1124 PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec) 1125 { 1126 if (!attr) { 1127 ec = TYPE_MISMATCH_ERR; 1128 return 0; 1129 } 1130 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec)); 1131 } 1132 1133 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec) 1134 { 1135 if (!attr) { 1136 ec = TYPE_MISMATCH_ERR; 1137 return 0; 1138 } 1139 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec)); 1140 } 1141 1142 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec) 1143 { 1144 if (!attr) { 1145 ec = TYPE_MISMATCH_ERR; 1146 return 0; 1147 } 1148 if (attr->ownerElement() != this) { 1149 ec = NOT_FOUND_ERR; 1150 return 0; 1151 } 1152 if (document() != attr->document()) { 1153 ec = WRONG_DOCUMENT_ERR; 1154 return 0; 1155 } 1156 1157 NamedNodeMap* attrs = attributes(true); 1158 if (!attrs) 1159 return 0; 1160 1161 return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec)); 1162 } 1163 1164 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec, FragmentScriptingPermission scriptingPermission) 1165 { 1166 String prefix, localName; 1167 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec)) 1168 return; 1169 1170 QualifiedName qName(prefix, localName, namespaceURI); 1171 1172 if (scriptingPermission == FragmentScriptingNotAllowed && (isEventHandlerAttribute(qName) || isAttributeToRemove(qName, value))) 1173 return; 1174 1175 setAttribute(qName, value, ec); 1176 } 1177 1178 void Element::removeAttribute(const String& name, ExceptionCode& ec) 1179 { 1180 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 1181 1182 if (namedAttrMap) { 1183 namedAttrMap->removeNamedItem(localName, ec); 1184 if (ec == NOT_FOUND_ERR) 1185 ec = 0; 1186 } 1187 1188 #if ENABLE(INSPECTOR) 1189 if (Page* page = document()->page()) { 1190 if (InspectorController* inspectorController = page->inspectorController()) 1191 inspectorController->didModifyDOMAttr(this); 1192 } 1193 #endif 1194 1195 } 1196 1197 void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec) 1198 { 1199 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec); 1200 } 1201 1202 PassRefPtr<Attr> Element::getAttributeNode(const String& name) 1203 { 1204 NamedNodeMap* attrs = attributes(true); 1205 if (!attrs) 1206 return 0; 1207 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 1208 return static_pointer_cast<Attr>(attrs->getNamedItem(localName)); 1209 } 1210 1211 PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName) 1212 { 1213 NamedNodeMap* attrs = attributes(true); 1214 if (!attrs) 1215 return 0; 1216 return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI))); 1217 } 1218 1219 bool Element::hasAttribute(const String& name) const 1220 { 1221 NamedNodeMap* attrs = attributes(true); 1222 if (!attrs) 1223 return false; 1224 1225 // This call to String::lower() seems to be required but 1226 // there may be a way to remove it. 1227 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 1228 return attrs->getAttributeItem(localName, false); 1229 } 1230 1231 bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const 1232 { 1233 NamedNodeMap* attrs = attributes(true); 1234 if (!attrs) 1235 return false; 1236 return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI)); 1237 } 1238 1239 CSSStyleDeclaration *Element::style() 1240 { 1241 return 0; 1242 } 1243 1244 void Element::focus(bool restorePreviousSelection) 1245 { 1246 Document* doc = document(); 1247 if (doc->focusedNode() == this) 1248 return; 1249 1250 if (!supportsFocus()) 1251 return; 1252 1253 // If the stylesheets have already been loaded we can reliably check isFocusable. 1254 // If not, we continue and set the focused node on the focus controller below so 1255 // that it can be updated soon after attach. 1256 if (doc->haveStylesheetsLoaded()) { 1257 doc->updateLayoutIgnorePendingStylesheets(); 1258 if (!isFocusable()) 1259 return; 1260 } 1261 1262 if (Page* page = doc->page()) 1263 page->focusController()->setFocusedNode(this, doc->frame()); 1264 1265 // Setting the focused node above might have invalidated the layout due to scripts. 1266 doc->updateLayoutIgnorePendingStylesheets(); 1267 1268 if (!isFocusable()) { 1269 ensureRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true); 1270 return; 1271 } 1272 1273 cancelFocusAppearanceUpdate(); 1274 updateFocusAppearance(restorePreviousSelection); 1275 } 1276 1277 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/) 1278 { 1279 if (this == rootEditableElement()) { 1280 Frame* frame = document()->frame(); 1281 if (!frame) 1282 return; 1283 1284 // FIXME: We should restore the previous selection if there is one. 1285 VisibleSelection newSelection = hasTagName(htmlTag) || hasTagName(bodyTag) ? VisibleSelection(Position(this, 0), DOWNSTREAM) : VisibleSelection::selectionFromContentsOfNode(this); 1286 1287 if (frame->shouldChangeSelection(newSelection)) { 1288 frame->selection()->setSelection(newSelection); 1289 frame->revealSelection(); 1290 } 1291 } 1292 // FIXME: I'm not sure all devices will want this off, but this is 1293 // currently turned off for Android. 1294 #if !ENABLE(DIRECTIONAL_PAD_NAVIGATION) 1295 else if (renderer() && !renderer()->isWidget()) 1296 renderer()->enclosingLayer()->scrollRectToVisible(getRect()); 1297 #endif 1298 } 1299 1300 void Element::blur() 1301 { 1302 cancelFocusAppearanceUpdate(); 1303 Document* doc = document(); 1304 if (doc->focusedNode() == this) { 1305 if (doc->frame()) 1306 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame()); 1307 else 1308 doc->setFocusedNode(0); 1309 } 1310 } 1311 1312 String Element::innerText() const 1313 { 1314 // We need to update layout, since plainText uses line boxes in the render tree. 1315 document()->updateLayoutIgnorePendingStylesheets(); 1316 1317 if (!renderer()) 1318 return textContent(true); 1319 1320 return plainText(rangeOfContents(const_cast<Element*>(this)).get()); 1321 } 1322 1323 String Element::outerText() const 1324 { 1325 // Getting outerText is the same as getting innerText, only 1326 // setting is different. You would think this should get the plain 1327 // text for the outer range, but this is wrong, <br> for instance 1328 // would return different values for inner and outer text by such 1329 // a rule, but it doesn't in WinIE, and we want to match that. 1330 return innerText(); 1331 } 1332 1333 String Element::title() const 1334 { 1335 return String(); 1336 } 1337 1338 IntSize Element::minimumSizeForResizing() const 1339 { 1340 return hasRareData() ? rareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing(); 1341 } 1342 1343 void Element::setMinimumSizeForResizing(const IntSize& size) 1344 { 1345 if (size == defaultMinimumSizeForResizing() && !hasRareData()) 1346 return; 1347 ensureRareData()->m_minimumSizeForResizing = size; 1348 } 1349 1350 RenderStyle* Element::computedStyle() 1351 { 1352 if (RenderStyle* usedStyle = renderStyle()) 1353 return usedStyle; 1354 1355 if (!attached()) 1356 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the 1357 // document tree and figure out when to destroy the computed style for such elements. 1358 return 0; 1359 1360 ElementRareData* data = ensureRareData(); 1361 if (!data->m_computedStyle) 1362 data->m_computedStyle = document()->styleSelector()->styleForElement(this, parent() ? parent()->computedStyle() : 0); 1363 return data->m_computedStyle.get(); 1364 } 1365 1366 void Element::cancelFocusAppearanceUpdate() 1367 { 1368 if (hasRareData()) 1369 rareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false); 1370 if (document()->focusedNode() == this) 1371 document()->cancelFocusAppearanceUpdate(); 1372 } 1373 1374 void Element::normalizeAttributes() 1375 { 1376 // Normalize attributes. 1377 NamedNodeMap* attrs = attributes(true); 1378 if (!attrs) 1379 return; 1380 unsigned numAttrs = attrs->length(); 1381 for (unsigned i = 0; i < numAttrs; i++) { 1382 if (Attr* attr = attrs->attributeItem(i)->attr()) 1383 attr->normalize(); 1384 } 1385 } 1386 1387 // ElementTraversal API 1388 Element* Element::firstElementChild() const 1389 { 1390 Node* n = firstChild(); 1391 while (n && !n->isElementNode()) 1392 n = n->nextSibling(); 1393 return static_cast<Element*>(n); 1394 } 1395 1396 Element* Element::lastElementChild() const 1397 { 1398 Node* n = lastChild(); 1399 while (n && !n->isElementNode()) 1400 n = n->previousSibling(); 1401 return static_cast<Element*>(n); 1402 } 1403 1404 Element* Element::previousElementSibling() const 1405 { 1406 Node* n = previousSibling(); 1407 while (n && !n->isElementNode()) 1408 n = n->previousSibling(); 1409 return static_cast<Element*>(n); 1410 } 1411 1412 Element* Element::nextElementSibling() const 1413 { 1414 Node* n = nextSibling(); 1415 while (n && !n->isElementNode()) 1416 n = n->nextSibling(); 1417 return static_cast<Element*>(n); 1418 } 1419 1420 unsigned Element::childElementCount() const 1421 { 1422 unsigned count = 0; 1423 Node* n = firstChild(); 1424 while (n) { 1425 count += n->isElementNode(); 1426 n = n->nextSibling(); 1427 } 1428 return count; 1429 } 1430 1431 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec) 1432 { 1433 if (selector.isEmpty()) { 1434 ec = SYNTAX_ERR; 1435 return false; 1436 } 1437 1438 bool strictParsing = !document()->inCompatMode(); 1439 CSSParser p(strictParsing); 1440 1441 CSSSelectorList selectorList; 1442 p.parseSelector(selector, document(), selectorList); 1443 1444 if (!selectorList.first()) { 1445 ec = SYNTAX_ERR; 1446 return false; 1447 } 1448 1449 // Throw a NAMESPACE_ERR if the selector includes any namespace prefixes. 1450 if (selectorList.selectorsNeedNamespaceResolution()) { 1451 ec = NAMESPACE_ERR; 1452 return false; 1453 } 1454 1455 CSSStyleSelector::SelectorChecker selectorChecker(document(), strictParsing); 1456 for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) { 1457 if (selectorChecker.checkSelector(selector, this)) 1458 return true; 1459 } 1460 1461 return false; 1462 } 1463 1464 KURL Element::getURLAttribute(const QualifiedName& name) const 1465 { 1466 #if !ASSERT_DISABLED 1467 if (namedAttrMap) { 1468 if (Attribute* attribute = namedAttrMap->getAttributeItem(name)) 1469 ASSERT(isURLAttribute(attribute)); 1470 } 1471 #endif 1472 return document()->completeURL(deprecatedParseURL(getAttribute(name))); 1473 } 1474 1475 const QualifiedName& Element::rareIDAttributeName() const 1476 { 1477 return rareData()->m_idAttributeName; 1478 } 1479 1480 } // namespace WebCore 1481