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 if (Attr* attrNode = old->attr()) 532 attrNode->setValue(value); 533 else 534 old->setValue(value); 535 attributeChanged(old); 536 } 537 538 #if ENABLE(INSPECTOR) 539 if (Page* page = document()->page()) { 540 if (InspectorController* inspectorController = page->inspectorController()) { 541 if (!m_synchronizingStyleAttribute) 542 inspectorController->didModifyDOMAttr(this); 543 } 544 } 545 #endif 546 } 547 548 void Element::setAttribute(const QualifiedName& name, const AtomicString& value, ExceptionCode&) 549 { 550 document()->incDOMTreeVersion(); 551 552 // allocate attributemap if necessary 553 Attribute* old = attributes(false)->getAttributeItem(name); 554 555 if (name == idAttributeName()) 556 updateId(old ? old->value() : nullAtom, value); 557 558 if (old && value.isNull()) 559 namedAttrMap->removeAttribute(name); 560 else if (!old && !value.isNull()) 561 namedAttrMap->addAttribute(createAttribute(name, value)); 562 else if (old) { 563 if (Attr* attrNode = old->attr()) 564 attrNode->setValue(value); 565 else 566 old->setValue(value); 567 attributeChanged(old); 568 } 569 570 #if ENABLE(INSPECTOR) 571 if (Page* page = document()->page()) { 572 if (InspectorController* inspectorController = page->inspectorController()) { 573 if (!m_synchronizingStyleAttribute) 574 inspectorController->didModifyDOMAttr(this); 575 } 576 } 577 #endif 578 } 579 580 PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const AtomicString& value) 581 { 582 return Attribute::create(name, value); 583 } 584 585 void Element::attributeChanged(Attribute* attr, bool) 586 { 587 recalcStyleIfNeededAfterAttributeChanged(attr); 588 updateAfterAttributeChanged(attr); 589 } 590 591 void Element::updateAfterAttributeChanged(Attribute* attr) 592 { 593 if (!AXObjectCache::accessibilityEnabled()) 594 return; 595 596 const QualifiedName& attrName = attr->name(); 597 if (attrName == aria_activedescendantAttr) { 598 // any change to aria-activedescendant attribute triggers accessibility focus change, but document focus remains intact 599 document()->axObjectCache()->handleActiveDescendantChanged(renderer()); 600 } else if (attrName == roleAttr) { 601 // the role attribute can change at any time, and the AccessibilityObject must pick up these changes 602 document()->axObjectCache()->handleAriaRoleChanged(renderer()); 603 } else if (attrName == aria_valuenowAttr) { 604 // If the valuenow attribute changes, AX clients need to be notified. 605 document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXValueChanged, true); 606 } else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == altAttr || attrName == titleAttr) { 607 // If the content of an element changes due to an attribute change, notify accessibility. 608 document()->axObjectCache()->contentChanged(renderer()); 609 } 610 } 611 612 void Element::recalcStyleIfNeededAfterAttributeChanged(Attribute* attr) 613 { 614 if (document()->attached() && document()->styleSelector()->hasSelectorForAttribute(attr->name().localName())) 615 setNeedsStyleRecalc(); 616 } 617 618 // Returns true is the given attribute is an event handler. 619 // We consider an event handler any attribute that begins with "on". 620 // It is a simple solution that has the advantage of not requiring any 621 // code or configuration change if a new event handler is defined. 622 623 static bool isEventHandlerAttribute(const QualifiedName& name) 624 { 625 return name.namespaceURI().isNull() && name.localName().startsWith("on"); 626 } 627 628 static bool isAttributeToRemove(const QualifiedName& name, const AtomicString& value) 629 { 630 return (name.localName().endsWith(hrefAttr.localName()) || name == srcAttr || name == actionAttr) && protocolIsJavaScript(deprecatedParseURL(value)); 631 } 632 633 void Element::setAttributeMap(PassRefPtr<NamedNodeMap> list, FragmentScriptingPermission scriptingPermission) 634 { 635 document()->incDOMTreeVersion(); 636 637 // If setting the whole map changes the id attribute, we need to call updateId. 638 639 const QualifiedName& idName = idAttributeName(); 640 Attribute* oldId = namedAttrMap ? namedAttrMap->getAttributeItem(idName) : 0; 641 Attribute* newId = list ? list->getAttributeItem(idName) : 0; 642 643 if (oldId || newId) 644 updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom); 645 646 if (namedAttrMap) 647 namedAttrMap->m_element = 0; 648 649 namedAttrMap = list; 650 651 if (namedAttrMap) { 652 namedAttrMap->m_element = this; 653 // If the element is created as result of a paste or drag-n-drop operation 654 // we want to remove all the script and event handlers. 655 if (scriptingPermission == FragmentScriptingNotAllowed) { 656 unsigned i = 0; 657 while (i < namedAttrMap->length()) { 658 const QualifiedName& attributeName = namedAttrMap->m_attributes[i]->name(); 659 if (isEventHandlerAttribute(attributeName)) { 660 namedAttrMap->m_attributes.remove(i); 661 continue; 662 } 663 664 if (isAttributeToRemove(attributeName, namedAttrMap->m_attributes[i]->value())) 665 namedAttrMap->m_attributes[i]->setValue(nullAtom); 666 i++; 667 } 668 } 669 unsigned len = namedAttrMap->length(); 670 for (unsigned i = 0; i < len; i++) 671 attributeChanged(namedAttrMap->m_attributes[i].get()); 672 // FIXME: What about attributes that were in the old map that are not in the new map? 673 } 674 } 675 676 bool Element::hasAttributes() const 677 { 678 if (!m_isStyleAttributeValid) 679 updateStyleAttribute(); 680 681 #if ENABLE(SVG) 682 if (!m_areSVGAttributesValid) 683 updateAnimatedSVGAttribute(anyQName()); 684 #endif 685 686 return namedAttrMap && namedAttrMap->length() > 0; 687 } 688 689 String Element::nodeName() const 690 { 691 return m_tagName.toString(); 692 } 693 694 String Element::nodeNamePreservingCase() const 695 { 696 return m_tagName.toString(); 697 } 698 699 void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec) 700 { 701 ec = 0; 702 checkSetPrefix(prefix, ec); 703 if (ec) 704 return; 705 706 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix); 707 } 708 709 KURL Element::baseURI() const 710 { 711 const AtomicString& baseAttribute = getAttribute(baseAttr); 712 KURL base(KURL(), baseAttribute); 713 if (!base.protocol().isEmpty()) 714 return base; 715 716 Node* parent = parentNode(); 717 if (!parent) 718 return base; 719 720 const KURL& parentBase = parent->baseURI(); 721 if (parentBase.isNull()) 722 return base; 723 724 return KURL(parentBase, baseAttribute); 725 } 726 727 void Element::createAttributeMap() const 728 { 729 namedAttrMap = NamedNodeMap::create(const_cast<Element*>(this)); 730 } 731 732 bool Element::isURLAttribute(Attribute*) const 733 { 734 return false; 735 } 736 737 const QualifiedName& Element::imageSourceAttributeName() const 738 { 739 return srcAttr; 740 } 741 742 RenderObject* Element::createRenderer(RenderArena* arena, RenderStyle* style) 743 { 744 if (document()->documentElement() == this && style->display() == NONE) { 745 // Ignore display: none on root elements. Force a display of block in that case. 746 RenderBlock* result = new (arena) RenderBlock(this); 747 if (result) 748 result->setAnimatableStyle(style); 749 return result; 750 } 751 return RenderObject::createObject(this, style); 752 } 753 754 755 void Element::insertedIntoDocument() 756 { 757 // need to do superclass processing first so inDocument() is true 758 // by the time we reach updateId 759 ContainerNode::insertedIntoDocument(); 760 761 if (hasID()) { 762 if (NamedNodeMap* attrs = namedAttrMap.get()) { 763 Attribute* idItem = attrs->getAttributeItem(idAttributeName()); 764 if (idItem && !idItem->isNull()) 765 updateId(nullAtom, idItem->value()); 766 } 767 } 768 } 769 770 void Element::removedFromDocument() 771 { 772 if (hasID()) { 773 if (NamedNodeMap* attrs = namedAttrMap.get()) { 774 Attribute* idItem = attrs->getAttributeItem(idAttributeName()); 775 if (idItem && !idItem->isNull()) 776 updateId(idItem->value(), nullAtom); 777 } 778 } 779 780 ContainerNode::removedFromDocument(); 781 } 782 783 void Element::attach() 784 { 785 suspendPostAttachCallbacks(); 786 RenderWidget::suspendWidgetHierarchyUpdates(); 787 788 createRendererIfNeeded(); 789 ContainerNode::attach(); 790 if (hasRareData()) { 791 ElementRareData* data = rareData(); 792 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) { 793 if (isFocusable() && document()->focusedNode() == this) 794 document()->updateFocusAppearanceSoon(false /* don't restore selection */); 795 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false); 796 } 797 } 798 799 RenderWidget::resumeWidgetHierarchyUpdates(); 800 resumePostAttachCallbacks(); 801 } 802 803 void Element::detach() 804 { 805 RenderWidget::suspendWidgetHierarchyUpdates(); 806 807 cancelFocusAppearanceUpdate(); 808 if (hasRareData()) 809 rareData()->resetComputedStyle(); 810 ContainerNode::detach(); 811 812 RenderWidget::resumeWidgetHierarchyUpdates(); 813 } 814 815 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle) 816 { 817 ASSERT(currentStyle == renderStyle()); 818 819 if (!renderer() || !currentStyle) 820 return false; 821 822 RenderStyle::PseudoStyleCache pseudoStyleCache; 823 currentStyle->getPseudoStyleCache(pseudoStyleCache); 824 size_t cacheSize = pseudoStyleCache.size(); 825 for (size_t i = 0; i < cacheSize; ++i) { 826 RefPtr<RenderStyle> newPseudoStyle; 827 PseudoId pseudoId = pseudoStyleCache[i]->styleType(); 828 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) 829 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle); 830 else 831 newPseudoStyle = renderer()->getUncachedPseudoStyle(pseudoId, newStyle, newStyle); 832 833 if (*newPseudoStyle != *pseudoStyleCache[i]) { 834 if (pseudoId < FIRST_INTERNAL_PSEUDOID) 835 newStyle->setHasPseudoStyle(pseudoId); 836 newStyle->addCachedPseudoStyle(newPseudoStyle); 837 return true; 838 } 839 } 840 return false; 841 } 842 843 void Element::recalcStyle(StyleChange change) 844 { 845 // Ref currentStyle in case it would otherwise be deleted when setRenderStyle() is called. 846 RefPtr<RenderStyle> currentStyle(renderStyle()); 847 bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false; 848 bool hasPositionalRules = needsStyleRecalc() && currentStyle && currentStyle->childrenAffectedByPositionalRules(); 849 bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules(); 850 851 #if ENABLE(SVG) 852 if (!hasParentStyle && isShadowNode() && isSVGElement()) 853 hasParentStyle = true; 854 #endif 855 856 if ((change > NoChange || needsStyleRecalc())) { 857 if (hasRareData()) 858 rareData()->resetComputedStyle(); 859 } 860 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) { 861 RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this); 862 StyleChange ch = diff(currentStyle.get(), newStyle.get()); 863 if (ch == Detach || !currentStyle) { 864 if (attached()) 865 detach(); 866 attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along. 867 // attach recalulates the style for all children. No need to do it twice. 868 setNeedsStyleRecalc(NoStyleChange); 869 setChildNeedsStyleRecalc(false); 870 return; 871 } 872 873 if (currentStyle) { 874 // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full 875 // style change (e.g., only inline style changed). 876 if (currentStyle->affectedByHoverRules()) 877 newStyle->setAffectedByHoverRules(true); 878 if (currentStyle->affectedByActiveRules()) 879 newStyle->setAffectedByActiveRules(true); 880 if (currentStyle->affectedByDragRules()) 881 newStyle->setAffectedByDragRules(true); 882 if (currentStyle->childrenAffectedByForwardPositionalRules()) 883 newStyle->setChildrenAffectedByForwardPositionalRules(); 884 if (currentStyle->childrenAffectedByBackwardPositionalRules()) 885 newStyle->setChildrenAffectedByBackwardPositionalRules(); 886 if (currentStyle->childrenAffectedByFirstChildRules()) 887 newStyle->setChildrenAffectedByFirstChildRules(); 888 if (currentStyle->childrenAffectedByLastChildRules()) 889 newStyle->setChildrenAffectedByLastChildRules(); 890 if (currentStyle->childrenAffectedByDirectAdjacentRules()) 891 newStyle->setChildrenAffectedByDirectAdjacentRules(); 892 } 893 894 if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get())) { 895 setRenderStyle(newStyle); 896 } else if (needsStyleRecalc() && (styleChangeType() != SyntheticStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) { 897 // Although no change occurred, we use the new style so that the cousin style sharing code won't get 898 // fooled into believing this style is the same. This is only necessary if the document actually uses 899 // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of 900 // descendants. 901 if (renderer()) 902 renderer()->setStyleInternal(newStyle.get()); 903 else 904 setRenderStyle(newStyle); 905 } else if (styleChangeType() == SyntheticStyleChange) 906 setRenderStyle(newStyle); 907 908 if (change != Force) { 909 // 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 910 // 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). 911 if (document()->usesRemUnits() && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize() && document()->documentElement() == this) 912 change = Force; 913 else if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange) 914 change = Force; 915 else 916 change = ch; 917 } 918 } 919 920 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar. 921 // For now we will just worry about the common case, since it's a lot trickier to get the second case right 922 // without doing way too much re-resolution. 923 bool forceCheckOfNextElementSibling = false; 924 for (Node *n = firstChild(); n; n = n->nextSibling()) { 925 bool childRulesChanged = n->needsStyleRecalc() && n->styleChangeType() == FullStyleChange; 926 if (forceCheckOfNextElementSibling && n->isElementNode()) 927 n->setNeedsStyleRecalc(); 928 if (change >= Inherit || n->isTextNode() || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) 929 n->recalcStyle(change); 930 if (n->isElementNode()) 931 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules; 932 } 933 934 setNeedsStyleRecalc(NoStyleChange); 935 setChildNeedsStyleRecalc(false); 936 } 937 938 bool Element::childTypeAllowed(NodeType type) 939 { 940 switch (type) { 941 case ELEMENT_NODE: 942 case TEXT_NODE: 943 case COMMENT_NODE: 944 case PROCESSING_INSTRUCTION_NODE: 945 case CDATA_SECTION_NODE: 946 case ENTITY_REFERENCE_NODE: 947 return true; 948 break; 949 default: 950 return false; 951 } 952 } 953 954 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback, 955 Node* beforeChange, Node* afterChange, int childCountDelta) 956 { 957 if (!style || (e->needsStyleRecalc() && style->childrenAffectedByPositionalRules())) 958 return; 959 960 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time. 961 // In the DOM case, we only need to do something if |afterChange| is not 0. 962 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block. 963 if (style->childrenAffectedByFirstChildRules() && afterChange) { 964 // Find our new first child. 965 Node* newFirstChild = 0; 966 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {}; 967 968 // Find the first element node following |afterChange| 969 Node* firstElementAfterInsertion = 0; 970 for (firstElementAfterInsertion = afterChange; 971 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); 972 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; 973 974 // This is the insert/append case. 975 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() && 976 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState()) 977 firstElementAfterInsertion->setNeedsStyleRecalc(); 978 979 // We also have to handle node removal. 980 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState()) 981 newFirstChild->setNeedsStyleRecalc(); 982 } 983 984 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time. 985 // In the DOM case, we only need to do something if |afterChange| is not 0. 986 if (style->childrenAffectedByLastChildRules() && beforeChange) { 987 // Find our new last child. 988 Node* newLastChild = 0; 989 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {}; 990 991 // Find the last element node going backwards from |beforeChange| 992 Node* lastElementBeforeInsertion = 0; 993 for (lastElementBeforeInsertion = beforeChange; 994 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode(); 995 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {}; 996 997 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() && 998 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState()) 999 lastElementBeforeInsertion->setNeedsStyleRecalc(); 1000 1001 // 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 1002 // to match now. 1003 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState()) 1004 newLastChild->setNeedsStyleRecalc(); 1005 } 1006 1007 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element 1008 // that could be affected by this DOM change. 1009 if (style->childrenAffectedByDirectAdjacentRules() && afterChange) { 1010 Node* firstElementAfterInsertion = 0; 1011 for (firstElementAfterInsertion = afterChange; 1012 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); 1013 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; 1014 if (firstElementAfterInsertion && firstElementAfterInsertion->attached()) 1015 firstElementAfterInsertion->setNeedsStyleRecalc(); 1016 } 1017 1018 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type. 1019 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type. 1020 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the 1021 // backward case. 1022 // |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. 1023 // 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 1024 // here. recalcStyle will then force a walk of the children when it sees that this has happened. 1025 if ((style->childrenAffectedByForwardPositionalRules() && afterChange) || 1026 (style->childrenAffectedByBackwardPositionalRules() && beforeChange)) 1027 e->setNeedsStyleRecalc(); 1028 1029 // :empty selector. 1030 if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes())) 1031 e->setNeedsStyleRecalc(); 1032 } 1033 1034 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 1035 { 1036 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 1037 if (!changedByParser) 1038 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta); 1039 } 1040 1041 void Element::finishParsingChildren() 1042 { 1043 ContainerNode::finishParsingChildren(); 1044 m_parsingChildrenFinished = true; 1045 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0); 1046 } 1047 1048 void Element::dispatchAttrRemovalEvent(Attribute*) 1049 { 1050 ASSERT(!eventDispatchForbidden()); 1051 1052 #if 0 1053 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER)) 1054 return; 1055 ExceptionCode ec = 0; 1056 dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(), 1057 attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec); 1058 #endif 1059 } 1060 1061 void Element::dispatchAttrAdditionEvent(Attribute*) 1062 { 1063 ASSERT(!eventDispatchForbidden()); 1064 1065 #if 0 1066 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER)) 1067 return; 1068 ExceptionCode ec = 0; 1069 dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(), 1070 attr->value(), document()->attrName(attr->id()), MutationEvent::ADDITION), ec); 1071 #endif 1072 } 1073 1074 String Element::openTagStartToString() const 1075 { 1076 String result = "<" + nodeName(); 1077 1078 NamedNodeMap* attrMap = attributes(true); 1079 1080 if (attrMap) { 1081 unsigned numAttrs = attrMap->length(); 1082 for (unsigned i = 0; i < numAttrs; i++) { 1083 result += " "; 1084 1085 Attribute *attribute = attrMap->attributeItem(i); 1086 result += attribute->name().toString(); 1087 if (!attribute->value().isNull()) { 1088 result += "=\""; 1089 // FIXME: substitute entities for any instances of " or ' 1090 result += attribute->value(); 1091 result += "\""; 1092 } 1093 } 1094 } 1095 1096 return result; 1097 } 1098 1099 #ifndef NDEBUG 1100 void Element::formatForDebugger(char* buffer, unsigned length) const 1101 { 1102 String result; 1103 String s; 1104 1105 s = nodeName(); 1106 if (s.length() > 0) { 1107 result += s; 1108 } 1109 1110 s = getAttribute(idAttributeName()); 1111 if (s.length() > 0) { 1112 if (result.length() > 0) 1113 result += "; "; 1114 result += "id="; 1115 result += s; 1116 } 1117 1118 s = getAttribute(classAttr); 1119 if (s.length() > 0) { 1120 if (result.length() > 0) 1121 result += "; "; 1122 result += "class="; 1123 result += s; 1124 } 1125 1126 strncpy(buffer, result.utf8().data(), length - 1); 1127 } 1128 #endif 1129 1130 PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec) 1131 { 1132 if (!attr) { 1133 ec = TYPE_MISMATCH_ERR; 1134 return 0; 1135 } 1136 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec)); 1137 } 1138 1139 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec) 1140 { 1141 if (!attr) { 1142 ec = TYPE_MISMATCH_ERR; 1143 return 0; 1144 } 1145 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec)); 1146 } 1147 1148 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec) 1149 { 1150 if (!attr) { 1151 ec = TYPE_MISMATCH_ERR; 1152 return 0; 1153 } 1154 if (attr->ownerElement() != this) { 1155 ec = NOT_FOUND_ERR; 1156 return 0; 1157 } 1158 if (document() != attr->document()) { 1159 ec = WRONG_DOCUMENT_ERR; 1160 return 0; 1161 } 1162 1163 NamedNodeMap* attrs = attributes(true); 1164 if (!attrs) 1165 return 0; 1166 1167 return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec)); 1168 } 1169 1170 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec, FragmentScriptingPermission scriptingPermission) 1171 { 1172 String prefix, localName; 1173 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec)) 1174 return; 1175 1176 QualifiedName qName(prefix, localName, namespaceURI); 1177 1178 if (scriptingPermission == FragmentScriptingNotAllowed && (isEventHandlerAttribute(qName) || isAttributeToRemove(qName, value))) 1179 return; 1180 1181 setAttribute(qName, value, ec); 1182 } 1183 1184 void Element::removeAttribute(const String& name, ExceptionCode& ec) 1185 { 1186 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 1187 1188 if (namedAttrMap) { 1189 namedAttrMap->removeNamedItem(localName, ec); 1190 if (ec == NOT_FOUND_ERR) 1191 ec = 0; 1192 } 1193 1194 #if ENABLE(INSPECTOR) 1195 if (Page* page = document()->page()) { 1196 if (InspectorController* inspectorController = page->inspectorController()) 1197 inspectorController->didModifyDOMAttr(this); 1198 } 1199 #endif 1200 1201 } 1202 1203 void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec) 1204 { 1205 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec); 1206 } 1207 1208 PassRefPtr<Attr> Element::getAttributeNode(const String& name) 1209 { 1210 NamedNodeMap* attrs = attributes(true); 1211 if (!attrs) 1212 return 0; 1213 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 1214 return static_pointer_cast<Attr>(attrs->getNamedItem(localName)); 1215 } 1216 1217 PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName) 1218 { 1219 NamedNodeMap* attrs = attributes(true); 1220 if (!attrs) 1221 return 0; 1222 return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI))); 1223 } 1224 1225 bool Element::hasAttribute(const String& name) const 1226 { 1227 NamedNodeMap* attrs = attributes(true); 1228 if (!attrs) 1229 return false; 1230 1231 // This call to String::lower() seems to be required but 1232 // there may be a way to remove it. 1233 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 1234 return attrs->getAttributeItem(localName, false); 1235 } 1236 1237 bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const 1238 { 1239 NamedNodeMap* attrs = attributes(true); 1240 if (!attrs) 1241 return false; 1242 return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI)); 1243 } 1244 1245 CSSStyleDeclaration *Element::style() 1246 { 1247 return 0; 1248 } 1249 1250 void Element::focus(bool restorePreviousSelection) 1251 { 1252 Document* doc = document(); 1253 if (doc->focusedNode() == this) 1254 return; 1255 1256 if (!supportsFocus()) 1257 return; 1258 1259 // If the stylesheets have already been loaded we can reliably check isFocusable. 1260 // If not, we continue and set the focused node on the focus controller below so 1261 // that it can be updated soon after attach. 1262 if (doc->haveStylesheetsLoaded()) { 1263 doc->updateLayoutIgnorePendingStylesheets(); 1264 if (!isFocusable()) 1265 return; 1266 } 1267 1268 RefPtr<Node> protect; 1269 if (Page* page = doc->page()) { 1270 // Focus and change event handlers can cause us to lose our last ref. 1271 protect = this; 1272 page->focusController()->setFocusedNode(this, doc->frame()); 1273 } 1274 1275 // Setting the focused node above might have invalidated the layout due to scripts. 1276 doc->updateLayoutIgnorePendingStylesheets(); 1277 1278 if (!isFocusable()) { 1279 ensureRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true); 1280 return; 1281 } 1282 1283 cancelFocusAppearanceUpdate(); 1284 updateFocusAppearance(restorePreviousSelection); 1285 } 1286 1287 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/) 1288 { 1289 if (this == rootEditableElement()) { 1290 Frame* frame = document()->frame(); 1291 if (!frame) 1292 return; 1293 1294 // FIXME: We should restore the previous selection if there is one. 1295 VisibleSelection newSelection = hasTagName(htmlTag) || hasTagName(bodyTag) ? VisibleSelection(Position(this, 0), DOWNSTREAM) : VisibleSelection::selectionFromContentsOfNode(this); 1296 1297 if (frame->shouldChangeSelection(newSelection)) { 1298 frame->selection()->setSelection(newSelection); 1299 frame->revealSelection(); 1300 } 1301 } 1302 // FIXME: I'm not sure all devices will want this off, but this is 1303 // currently turned off for Android. 1304 #if !ENABLE(DIRECTIONAL_PAD_NAVIGATION) 1305 else if (renderer() && !renderer()->isWidget()) 1306 renderer()->enclosingLayer()->scrollRectToVisible(getRect()); 1307 #endif 1308 } 1309 1310 void Element::blur() 1311 { 1312 cancelFocusAppearanceUpdate(); 1313 Document* doc = document(); 1314 if (doc->focusedNode() == this) { 1315 if (doc->frame()) 1316 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame()); 1317 else 1318 doc->setFocusedNode(0); 1319 } 1320 } 1321 1322 String Element::innerText() const 1323 { 1324 // We need to update layout, since plainText uses line boxes in the render tree. 1325 document()->updateLayoutIgnorePendingStylesheets(); 1326 1327 if (!renderer()) 1328 return textContent(true); 1329 1330 return plainText(rangeOfContents(const_cast<Element*>(this)).get()); 1331 } 1332 1333 String Element::outerText() const 1334 { 1335 // Getting outerText is the same as getting innerText, only 1336 // setting is different. You would think this should get the plain 1337 // text for the outer range, but this is wrong, <br> for instance 1338 // would return different values for inner and outer text by such 1339 // a rule, but it doesn't in WinIE, and we want to match that. 1340 return innerText(); 1341 } 1342 1343 String Element::title() const 1344 { 1345 return String(); 1346 } 1347 1348 IntSize Element::minimumSizeForResizing() const 1349 { 1350 return hasRareData() ? rareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing(); 1351 } 1352 1353 void Element::setMinimumSizeForResizing(const IntSize& size) 1354 { 1355 if (size == defaultMinimumSizeForResizing() && !hasRareData()) 1356 return; 1357 ensureRareData()->m_minimumSizeForResizing = size; 1358 } 1359 1360 RenderStyle* Element::computedStyle() 1361 { 1362 if (RenderStyle* usedStyle = renderStyle()) 1363 return usedStyle; 1364 1365 if (!attached()) 1366 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the 1367 // document tree and figure out when to destroy the computed style for such elements. 1368 return 0; 1369 1370 ElementRareData* data = ensureRareData(); 1371 if (!data->m_computedStyle) 1372 data->m_computedStyle = document()->styleSelector()->styleForElement(this, parent() ? parent()->computedStyle() : 0); 1373 return data->m_computedStyle.get(); 1374 } 1375 1376 void Element::cancelFocusAppearanceUpdate() 1377 { 1378 if (hasRareData()) 1379 rareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false); 1380 if (document()->focusedNode() == this) 1381 document()->cancelFocusAppearanceUpdate(); 1382 } 1383 1384 void Element::normalizeAttributes() 1385 { 1386 // Normalize attributes. 1387 NamedNodeMap* attrs = attributes(true); 1388 if (!attrs) 1389 return; 1390 unsigned numAttrs = attrs->length(); 1391 for (unsigned i = 0; i < numAttrs; i++) { 1392 if (Attr* attr = attrs->attributeItem(i)->attr()) 1393 attr->normalize(); 1394 } 1395 } 1396 1397 // ElementTraversal API 1398 Element* Element::firstElementChild() const 1399 { 1400 Node* n = firstChild(); 1401 while (n && !n->isElementNode()) 1402 n = n->nextSibling(); 1403 return static_cast<Element*>(n); 1404 } 1405 1406 Element* Element::lastElementChild() const 1407 { 1408 Node* n = lastChild(); 1409 while (n && !n->isElementNode()) 1410 n = n->previousSibling(); 1411 return static_cast<Element*>(n); 1412 } 1413 1414 Element* Element::previousElementSibling() const 1415 { 1416 Node* n = previousSibling(); 1417 while (n && !n->isElementNode()) 1418 n = n->previousSibling(); 1419 return static_cast<Element*>(n); 1420 } 1421 1422 Element* Element::nextElementSibling() const 1423 { 1424 Node* n = nextSibling(); 1425 while (n && !n->isElementNode()) 1426 n = n->nextSibling(); 1427 return static_cast<Element*>(n); 1428 } 1429 1430 unsigned Element::childElementCount() const 1431 { 1432 unsigned count = 0; 1433 Node* n = firstChild(); 1434 while (n) { 1435 count += n->isElementNode(); 1436 n = n->nextSibling(); 1437 } 1438 return count; 1439 } 1440 1441 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec) 1442 { 1443 if (selector.isEmpty()) { 1444 ec = SYNTAX_ERR; 1445 return false; 1446 } 1447 1448 bool strictParsing = !document()->inCompatMode(); 1449 CSSParser p(strictParsing); 1450 1451 CSSSelectorList selectorList; 1452 p.parseSelector(selector, document(), selectorList); 1453 1454 if (!selectorList.first()) { 1455 ec = SYNTAX_ERR; 1456 return false; 1457 } 1458 1459 // Throw a NAMESPACE_ERR if the selector includes any namespace prefixes. 1460 if (selectorList.selectorsNeedNamespaceResolution()) { 1461 ec = NAMESPACE_ERR; 1462 return false; 1463 } 1464 1465 CSSStyleSelector::SelectorChecker selectorChecker(document(), strictParsing); 1466 for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) { 1467 if (selectorChecker.checkSelector(selector, this)) 1468 return true; 1469 } 1470 1471 return false; 1472 } 1473 1474 KURL Element::getURLAttribute(const QualifiedName& name) const 1475 { 1476 #if !ASSERT_DISABLED 1477 if (namedAttrMap) { 1478 if (Attribute* attribute = namedAttrMap->getAttributeItem(name)) 1479 ASSERT(isURLAttribute(attribute)); 1480 } 1481 #endif 1482 return document()->completeURL(deprecatedParseURL(getAttribute(name))); 1483 } 1484 1485 const QualifiedName& Element::rareIDAttributeName() const 1486 { 1487 return rareData()->m_idAttributeName; 1488 } 1489 1490 } // namespace WebCore 1491