1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Peter Kelly (pmk@post.com) 5 * (C) 2001 Dirk Mueller (mueller@kde.org) 6 * (C) 2007 David Smith (catfish.man@gmail.com) 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. 8 * (C) 2007 Eric Seidel (eric@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 "Chrome.h" 34#include "ChromeClient.h" 35#include "ClassList.h" 36#include "ClientRect.h" 37#include "ClientRectList.h" 38#include "CustomElementRegistry.h" 39#include "DOMTokenList.h" 40#include "DatasetDOMStringMap.h" 41#include "Document.h" 42#include "DocumentFragment.h" 43#include "DocumentSharedObjectPool.h" 44#include "ElementRareData.h" 45#include "EventDispatcher.h" 46#include "ExceptionCode.h" 47#include "FlowThreadController.h" 48#include "FocusController.h" 49#include "FocusEvent.h" 50#include "Frame.h" 51#include "FrameSelection.h" 52#include "FrameView.h" 53#include "HTMLCollection.h" 54#include "HTMLDocument.h" 55#include "HTMLElement.h" 56#include "HTMLFormControlsCollection.h" 57#include "HTMLFrameOwnerElement.h" 58#include "HTMLLabelElement.h" 59#include "HTMLNameCollection.h" 60#include "HTMLNames.h" 61#include "HTMLOptionsCollection.h" 62#include "HTMLParserIdioms.h" 63#include "HTMLTableRowsCollection.h" 64#include "InsertionPoint.h" 65#include "InspectorInstrumentation.h" 66#include "MutationObserverInterestGroup.h" 67#include "MutationRecord.h" 68#include "NamedNodeMap.h" 69#include "NodeList.h" 70#include "NodeRenderStyle.h" 71#include "NodeRenderingContext.h" 72#include "NodeTraversal.h" 73#include "Page.h" 74#include "PointerLockController.h" 75#include "PseudoElement.h" 76#include "RenderRegion.h" 77#include "RenderTheme.h" 78#include "RenderView.h" 79#include "RenderWidget.h" 80#include "SelectorQuery.h" 81#include "Settings.h" 82#include "ShadowRoot.h" 83#include "StylePropertySet.h" 84#include "StyleResolver.h" 85#include "Text.h" 86#include "TextIterator.h" 87#include "VoidCallback.h" 88#include "XMLNSNames.h" 89#include "XMLNames.h" 90#include "htmlediting.h" 91#include <wtf/BitVector.h> 92#include <wtf/CurrentTime.h> 93#include <wtf/text/CString.h> 94 95#if ENABLE(SVG) 96#include "SVGDocumentExtensions.h" 97#include "SVGElement.h" 98#include "SVGNames.h" 99#endif 100 101namespace WebCore { 102 103using namespace HTMLNames; 104using namespace XMLNames; 105 106static inline bool shouldIgnoreAttributeCase(const Element* e) 107{ 108 return e && e->document()->isHTMLDocument() && e->isHTMLElement(); 109} 110 111class StyleResolverParentPusher { 112public: 113 StyleResolverParentPusher(Element* parent) 114 : m_parent(parent) 115 , m_pushedStyleResolver(0) 116 { 117 } 118 void push() 119 { 120 if (m_pushedStyleResolver) 121 return; 122 m_pushedStyleResolver = m_parent->document()->ensureStyleResolver(); 123 m_pushedStyleResolver->pushParentElement(m_parent); 124 } 125 ~StyleResolverParentPusher() 126 { 127 128 if (!m_pushedStyleResolver) 129 return; 130 131 // This tells us that our pushed style selector is in a bad state, 132 // so we should just bail out in that scenario. 133 ASSERT(m_pushedStyleResolver == m_parent->document()->ensureStyleResolver()); 134 if (m_pushedStyleResolver != m_parent->document()->ensureStyleResolver()) 135 return; 136 137 m_pushedStyleResolver->popParentElement(m_parent); 138 } 139 140private: 141 Element* m_parent; 142 StyleResolver* m_pushedStyleResolver; 143}; 144 145typedef Vector<RefPtr<Attr> > AttrNodeList; 146typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap; 147 148static AttrNodeListMap& attrNodeListMap() 149{ 150 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ()); 151 return map; 152} 153 154static AttrNodeList* attrNodeListForElement(Element* element) 155{ 156 if (!element->hasSyntheticAttrChildNodes()) 157 return 0; 158 ASSERT(attrNodeListMap().contains(element)); 159 return attrNodeListMap().get(element); 160} 161 162static AttrNodeList* ensureAttrNodeListForElement(Element* element) 163{ 164 if (element->hasSyntheticAttrChildNodes()) { 165 ASSERT(attrNodeListMap().contains(element)); 166 return attrNodeListMap().get(element); 167 } 168 ASSERT(!attrNodeListMap().contains(element)); 169 element->setHasSyntheticAttrChildNodes(true); 170 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList)); 171 return result.iterator->value.get(); 172} 173 174static void removeAttrNodeListForElement(Element* element) 175{ 176 ASSERT(element->hasSyntheticAttrChildNodes()); 177 ASSERT(attrNodeListMap().contains(element)); 178 attrNodeListMap().remove(element); 179 element->setHasSyntheticAttrChildNodes(false); 180} 181 182static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name) 183{ 184 for (unsigned i = 0; i < attrNodeList->size(); ++i) { 185 if (attrNodeList->at(i)->qualifiedName() == name) 186 return attrNodeList->at(i).get(); 187 } 188 return 0; 189} 190 191PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document) 192{ 193 return adoptRef(new Element(tagName, document, CreateElement)); 194} 195 196Element::~Element() 197{ 198#ifndef NDEBUG 199 if (document() && document()->renderer()) { 200 // When the document is not destroyed, an element that was part of a named flow 201 // content nodes should have been removed from the content nodes collection 202 // and the inNamedFlow flag reset. 203 ASSERT(!inNamedFlow()); 204 } 205#endif 206 207 if (hasRareData()) { 208 ElementRareData* data = elementRareData(); 209 data->setPseudoElement(BEFORE, 0); 210 data->setPseudoElement(AFTER, 0); 211 data->clearShadow(); 212 } 213 214 if (hasSyntheticAttrChildNodes()) 215 detachAllAttrNodesFromElement(); 216 217#if ENABLE(SVG) 218 if (hasPendingResources()) { 219 document()->accessSVGExtensions()->removeElementFromPendingResources(this); 220 ASSERT(!hasPendingResources()); 221 } 222#endif 223} 224 225inline ElementRareData* Element::elementRareData() const 226{ 227 ASSERT(hasRareData()); 228 return static_cast<ElementRareData*>(rareData()); 229} 230 231inline ElementRareData* Element::ensureElementRareData() 232{ 233 return static_cast<ElementRareData*>(ensureRareData()); 234} 235 236void Element::clearTabIndexExplicitlyIfNeeded() 237{ 238 if (hasRareData()) 239 elementRareData()->clearTabIndexExplicitly(); 240} 241 242void Element::setTabIndexExplicitly(short tabIndex) 243{ 244 ensureElementRareData()->setTabIndexExplicitly(tabIndex); 245} 246 247bool Element::supportsFocus() const 248{ 249 return hasRareData() && elementRareData()->tabIndexSetExplicitly(); 250} 251 252Element* Element::focusDelegate() 253{ 254 return this; 255} 256 257short Element::tabIndex() const 258{ 259 return hasRareData() ? elementRareData()->tabIndex() : 0; 260} 261 262bool Element::isKeyboardFocusable(KeyboardEvent*) const 263{ 264 return isFocusable() && tabIndex() >= 0; 265} 266 267bool Element::isMouseFocusable() const 268{ 269 return isFocusable(); 270} 271 272bool Element::shouldUseInputMethod() 273{ 274 return isContentEditable(UserSelectAllIsAlwaysNonEditable); 275} 276 277void Element::dispatchSimulatedClick(Event* underlyingEvent, SimulatedClickMouseEventOptions eventOptions, SimulatedClickVisualOptions visualOptions) 278{ 279 EventDispatcher::dispatchSimulatedClick(this, underlyingEvent, eventOptions, visualOptions); 280} 281 282DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur); 283DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error); 284DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus); 285DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load); 286 287PassRefPtr<Node> Element::cloneNode(bool deep) 288{ 289 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren(); 290} 291 292PassRefPtr<Element> Element::cloneElementWithChildren() 293{ 294 RefPtr<Element> clone = cloneElementWithoutChildren(); 295 cloneChildNodes(clone.get()); 296 return clone.release(); 297} 298 299PassRefPtr<Element> Element::cloneElementWithoutChildren() 300{ 301 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren(); 302 // This will catch HTML elements in the wrong namespace that are not correctly copied. 303 // This is a sanity check as HTML overloads some of the DOM methods. 304 ASSERT(isHTMLElement() == clone->isHTMLElement()); 305 306 clone->cloneDataFromElement(*this); 307 return clone.release(); 308} 309 310PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren() 311{ 312 return document()->createElement(tagQName(), false); 313} 314 315PassRefPtr<Attr> Element::detachAttribute(unsigned index) 316{ 317 ASSERT(elementData()); 318 319 const Attribute* attribute = elementData()->attributeItem(index); 320 ASSERT(attribute); 321 322 RefPtr<Attr> attrNode = attrIfExists(attribute->name()); 323 if (attrNode) 324 detachAttrNodeFromElementWithValue(attrNode.get(), attribute->value()); 325 else 326 attrNode = Attr::create(document(), attribute->name(), attribute->value()); 327 328 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute); 329 return attrNode.release(); 330} 331 332void Element::removeAttribute(const QualifiedName& name) 333{ 334 if (!elementData()) 335 return; 336 337 unsigned index = elementData()->getAttributeItemIndex(name); 338 if (index == ElementData::attributeNotFound) 339 return; 340 341 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute); 342} 343 344void Element::setBooleanAttribute(const QualifiedName& name, bool value) 345{ 346 if (value) 347 setAttribute(name, emptyAtom); 348 else 349 removeAttribute(name); 350} 351 352NamedNodeMap* Element::attributes() const 353{ 354 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData(); 355 if (NamedNodeMap* attributeMap = rareData->attributeMap()) 356 return attributeMap; 357 358 rareData->setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this))); 359 return rareData->attributeMap(); 360} 361 362Node::NodeType Element::nodeType() const 363{ 364 return ELEMENT_NODE; 365} 366 367bool Element::hasAttribute(const QualifiedName& name) const 368{ 369 return hasAttributeNS(name.namespaceURI(), name.localName()); 370} 371 372void Element::synchronizeAllAttributes() const 373{ 374 if (!elementData()) 375 return; 376 if (elementData()->m_styleAttributeIsDirty) { 377 ASSERT(isStyledElement()); 378 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal(); 379 } 380#if ENABLE(SVG) 381 if (elementData()->m_animatedSVGAttributesAreDirty) { 382 ASSERT(isSVGElement()); 383 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName()); 384 } 385#endif 386} 387 388inline void Element::synchronizeAttribute(const QualifiedName& name) const 389{ 390 if (!elementData()) 391 return; 392 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) { 393 ASSERT(isStyledElement()); 394 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal(); 395 return; 396 } 397#if ENABLE(SVG) 398 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) { 399 ASSERT(isSVGElement()); 400 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name); 401 } 402#endif 403} 404 405inline void Element::synchronizeAttribute(const AtomicString& localName) const 406{ 407 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName, 408 // e.g when called from DOM API. 409 if (!elementData()) 410 return; 411 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase(this))) { 412 ASSERT(isStyledElement()); 413 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal(); 414 return; 415 } 416#if ENABLE(SVG) 417 if (elementData()->m_animatedSVGAttributesAreDirty) { 418 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well. 419 ASSERT(isSVGElement()); 420 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom)); 421 } 422#endif 423} 424 425const AtomicString& Element::getAttribute(const QualifiedName& name) const 426{ 427 if (!elementData()) 428 return nullAtom; 429 synchronizeAttribute(name); 430 if (const Attribute* attribute = getAttributeItem(name)) 431 return attribute->value(); 432 return nullAtom; 433} 434 435bool Element::isFocusable() const 436{ 437 if (!inDocument() || !supportsFocus()) 438 return false; 439 440 // Elements in canvas fallback content are not rendered, but they are allowed to be 441 // focusable as long as their canvas is displayed and visible. 442 if (isInCanvasSubtree()) { 443 const Element* e = this; 444 while (e && !e->hasLocalName(canvasTag)) 445 e = e->parentElement(); 446 ASSERT(e); 447 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE; 448 } 449 450 if (renderer()) 451 ASSERT(!renderer()->needsLayout()); 452 else { 453 // If the node is in a display:none tree it might say it needs style recalc but 454 // the whole document is actually up to date. 455 ASSERT(!document()->childNeedsStyleRecalc()); 456 } 457 458 // FIXME: Even if we are not visible, we might have a child that is visible. 459 // Hyatt wants to fix that some day with a "has visible content" flag or the like. 460 if (!renderer() || renderer()->style()->visibility() != VISIBLE) 461 return false; 462 463 return true; 464} 465 466bool Element::isUserActionElementInActiveChain() const 467{ 468 ASSERT(isUserActionElement()); 469 return document()->userActionElements().isInActiveChain(this); 470} 471 472bool Element::isUserActionElementActive() const 473{ 474 ASSERT(isUserActionElement()); 475 return document()->userActionElements().isActive(this); 476} 477 478bool Element::isUserActionElementFocused() const 479{ 480 ASSERT(isUserActionElement()); 481 return document()->userActionElements().isFocused(this); 482} 483 484bool Element::isUserActionElementHovered() const 485{ 486 ASSERT(isUserActionElement()); 487 return document()->userActionElements().isHovered(this); 488} 489 490void Element::setActive(bool flag, bool pause) 491{ 492 if (flag == active()) 493 return; 494 495 if (Document* document = this->document()) 496 document->userActionElements().setActive(this, flag); 497 498 if (!renderer()) 499 return; 500 501 bool reactsToPress = renderStyle()->affectedByActive() || childrenAffectedByActive(); 502 if (reactsToPress) 503 setNeedsStyleRecalc(); 504 505 if (renderer()->style()->hasAppearance() && renderer()->theme()->stateChanged(renderer(), PressedState)) 506 reactsToPress = true; 507 508 // The rest of this function implements a feature that only works if the 509 // platform supports immediate invalidations on the ChromeClient, so bail if 510 // that isn't supported. 511 if (!document()->page()->chrome().client()->supportsImmediateInvalidation()) 512 return; 513 514 if (reactsToPress && pause) { 515 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes 516 // to repaint the "down" state of the control is about the same time as it would take to repaint the 517 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you 518 // leave this method, it will be about that long before the flush of the up state happens again). 519#ifdef HAVE_FUNC_USLEEP 520 double startTime = currentTime(); 521#endif 522 523 Document::updateStyleForAllDocuments(); 524 // Do an immediate repaint. 525 if (renderer()) 526 renderer()->repaint(true); 527 528 // FIXME: Come up with a less ridiculous way of doing this. 529#ifdef HAVE_FUNC_USLEEP 530 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state) 531 double remainingTime = 0.1 - (currentTime() - startTime); 532 if (remainingTime > 0) 533 usleep(static_cast<useconds_t>(remainingTime * 1000000.0)); 534#endif 535 } 536} 537 538void Element::setFocus(bool flag) 539{ 540 if (flag == focused()) 541 return; 542 543 if (Document* document = this->document()) 544 document->userActionElements().setFocused(this, flag); 545 546 setNeedsStyleRecalc(); 547} 548 549void Element::setHovered(bool flag) 550{ 551 if (flag == hovered()) 552 return; 553 554 if (Document* document = this->document()) 555 document->userActionElements().setHovered(this, flag); 556 557 if (!renderer()) { 558 // When setting hover to false, the style needs to be recalc'd even when 559 // there's no renderer (imagine setting display:none in the :hover class, 560 // if a nil renderer would prevent this element from recalculating its 561 // style, it would never go back to its normal style and remain 562 // stuck in its hovered style). 563 if (!flag) 564 setNeedsStyleRecalc(); 565 566 return; 567 } 568 569 if (renderer()->style()->affectedByHover() || childrenAffectedByHover()) 570 setNeedsStyleRecalc(); 571 572 if (renderer()->style()->hasAppearance()) 573 renderer()->theme()->stateChanged(renderer(), HoverState); 574} 575 576void Element::scrollIntoView(bool alignToTop) 577{ 578 document()->updateLayoutIgnorePendingStylesheets(); 579 580 if (!renderer()) 581 return; 582 583 LayoutRect bounds = boundingBox(); 584 // Align to the top / bottom and to the closest edge. 585 if (alignToTop) 586 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); 587 else 588 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways); 589} 590 591void Element::scrollIntoViewIfNeeded(bool centerIfNeeded) 592{ 593 document()->updateLayoutIgnorePendingStylesheets(); 594 595 if (!renderer()) 596 return; 597 598 LayoutRect bounds = boundingBox(); 599 if (centerIfNeeded) 600 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded); 601 else 602 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); 603} 604 605void Element::scrollByUnits(int units, ScrollGranularity granularity) 606{ 607 document()->updateLayoutIgnorePendingStylesheets(); 608 609 if (!renderer()) 610 return; 611 612 if (!renderer()->hasOverflowClip()) 613 return; 614 615 ScrollDirection direction = ScrollDown; 616 if (units < 0) { 617 direction = ScrollUp; 618 units = -units; 619 } 620 Node* stopNode = this; 621 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode); 622} 623 624void Element::scrollByLines(int lines) 625{ 626 scrollByUnits(lines, ScrollByLine); 627} 628 629void Element::scrollByPages(int pages) 630{ 631 scrollByUnits(pages, ScrollByPage); 632} 633 634static float localZoomForRenderer(RenderObject* renderer) 635{ 636 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each 637 // other out, but the alternative is that we'd have to crawl up the whole render tree every 638 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified). 639 float zoomFactor = 1; 640 if (renderer->style()->effectiveZoom() != 1) { 641 // Need to find the nearest enclosing RenderObject that set up 642 // a differing zoom, and then we divide our result by it to eliminate the zoom. 643 RenderObject* prev = renderer; 644 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) { 645 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) { 646 zoomFactor = prev->style()->zoom(); 647 break; 648 } 649 prev = curr; 650 } 651 if (prev->isRenderView()) 652 zoomFactor = prev->style()->zoom(); 653 } 654 return zoomFactor; 655} 656 657static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer) 658{ 659 float zoomFactor = localZoomForRenderer(renderer); 660 if (zoomFactor == 1) 661 return value; 662#if ENABLE(SUBPIXEL_LAYOUT) 663 return lroundf(value / zoomFactor); 664#else 665 // Needed because computeLengthInt truncates (rather than rounds) when scaling up. 666 if (zoomFactor > 1) 667 value++; 668 return static_cast<int>(value / zoomFactor); 669#endif 670} 671 672int Element::offsetLeft() 673{ 674 document()->updateLayoutIgnorePendingStylesheets(); 675 if (RenderBoxModelObject* renderer = renderBoxModelObject()) 676 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer); 677 return 0; 678} 679 680int Element::offsetTop() 681{ 682 document()->updateLayoutIgnorePendingStylesheets(); 683 if (RenderBoxModelObject* renderer = renderBoxModelObject()) 684 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer); 685 return 0; 686} 687 688int Element::offsetWidth() 689{ 690 document()->updateLayoutIgnorePendingStylesheets(); 691 if (RenderBoxModelObject* renderer = renderBoxModelObject()) 692#if ENABLE(SUBPIXEL_LAYOUT) 693 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round(); 694#else 695 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer); 696#endif 697 return 0; 698} 699 700int Element::offsetHeight() 701{ 702 document()->updateLayoutIgnorePendingStylesheets(); 703 if (RenderBoxModelObject* renderer = renderBoxModelObject()) 704#if ENABLE(SUBPIXEL_LAYOUT) 705 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round(); 706#else 707 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer); 708#endif 709 return 0; 710} 711 712Element* Element::bindingsOffsetParent() 713{ 714 Element* element = offsetParent(); 715 if (!element || !element->isInShadowTree()) 716 return element; 717 return element->containingShadowRoot()->type() == ShadowRoot::UserAgentShadowRoot ? 0 : element; 718} 719 720Element* Element::offsetParent() 721{ 722 document()->updateLayoutIgnorePendingStylesheets(); 723 if (RenderObject* renderer = this->renderer()) { 724 if (RenderObject* offsetParent = renderer->offsetParent()) 725 return toElement(offsetParent->node()); 726 } 727 return 0; 728} 729 730int Element::clientLeft() 731{ 732 document()->updateLayoutIgnorePendingStylesheets(); 733 734 if (RenderBox* renderer = renderBox()) 735 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer); 736 return 0; 737} 738 739int Element::clientTop() 740{ 741 document()->updateLayoutIgnorePendingStylesheets(); 742 743 if (RenderBox* renderer = renderBox()) 744 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer); 745 return 0; 746} 747 748int Element::clientWidth() 749{ 750 document()->updateLayoutIgnorePendingStylesheets(); 751 752 // When in strict mode, clientWidth for the document element should return the width of the containing frame. 753 // When in quirks mode, clientWidth for the body element should return the width of the containing frame. 754 bool inQuirksMode = document()->inQuirksMode(); 755 if ((!inQuirksMode && document()->documentElement() == this) || 756 (inQuirksMode && isHTMLElement() && document()->body() == this)) { 757 if (FrameView* view = document()->view()) { 758 if (RenderView* renderView = document()->renderView()) 759 return adjustForAbsoluteZoom(view->layoutWidth(), renderView); 760 } 761 } 762 763 if (RenderBox* renderer = renderBox()) 764#if ENABLE(SUBPIXEL_LAYOUT) 765 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round(); 766#else 767 return adjustForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer); 768#endif 769 return 0; 770} 771 772int Element::clientHeight() 773{ 774 document()->updateLayoutIgnorePendingStylesheets(); 775 776 // When in strict mode, clientHeight for the document element should return the height of the containing frame. 777 // When in quirks mode, clientHeight for the body element should return the height of the containing frame. 778 bool inQuirksMode = document()->inQuirksMode(); 779 780 if ((!inQuirksMode && document()->documentElement() == this) || 781 (inQuirksMode && isHTMLElement() && document()->body() == this)) { 782 if (FrameView* view = document()->view()) { 783 if (RenderView* renderView = document()->renderView()) 784 return adjustForAbsoluteZoom(view->layoutHeight(), renderView); 785 } 786 } 787 788 if (RenderBox* renderer = renderBox()) 789#if ENABLE(SUBPIXEL_LAYOUT) 790 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round(); 791#else 792 return adjustForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer); 793#endif 794 return 0; 795} 796 797int Element::scrollLeft() 798{ 799 document()->updateLayoutIgnorePendingStylesheets(); 800 if (RenderBox* rend = renderBox()) 801 return adjustForAbsoluteZoom(rend->scrollLeft(), rend); 802 return 0; 803} 804 805int Element::scrollTop() 806{ 807 document()->updateLayoutIgnorePendingStylesheets(); 808 if (RenderBox* rend = renderBox()) 809 return adjustForAbsoluteZoom(rend->scrollTop(), rend); 810 return 0; 811} 812 813void Element::setScrollLeft(int newLeft) 814{ 815 document()->updateLayoutIgnorePendingStylesheets(); 816 if (RenderBox* rend = renderBox()) 817 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom())); 818} 819 820void Element::setScrollTop(int newTop) 821{ 822 document()->updateLayoutIgnorePendingStylesheets(); 823 if (RenderBox* rend = renderBox()) 824 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom())); 825} 826 827int Element::scrollWidth() 828{ 829 document()->updateLayoutIgnorePendingStylesheets(); 830 if (RenderBox* rend = renderBox()) 831 return adjustForAbsoluteZoom(rend->scrollWidth(), rend); 832 return 0; 833} 834 835int Element::scrollHeight() 836{ 837 document()->updateLayoutIgnorePendingStylesheets(); 838 if (RenderBox* rend = renderBox()) 839 return adjustForAbsoluteZoom(rend->scrollHeight(), rend); 840 return 0; 841} 842 843IntRect Element::boundsInRootViewSpace() 844{ 845 document()->updateLayoutIgnorePendingStylesheets(); 846 847 FrameView* view = document()->view(); 848 if (!view) 849 return IntRect(); 850 851 Vector<FloatQuad> quads; 852#if ENABLE(SVG) 853 if (isSVGElement() && renderer()) { 854 // Get the bounding rectangle from the SVG model. 855 SVGElement* svgElement = toSVGElement(this); 856 FloatRect localRect; 857 if (svgElement->getBoundingBox(localRect)) 858 quads.append(renderer()->localToAbsoluteQuad(localRect)); 859 } else 860#endif 861 { 862 // Get the bounding rectangle from the box model. 863 if (renderBoxModelObject()) 864 renderBoxModelObject()->absoluteQuads(quads); 865 } 866 867 if (quads.isEmpty()) 868 return IntRect(); 869 870 IntRect result = quads[0].enclosingBoundingBox(); 871 for (size_t i = 1; i < quads.size(); ++i) 872 result.unite(quads[i].enclosingBoundingBox()); 873 874 result = view->contentsToRootView(result); 875 return result; 876} 877 878PassRefPtr<ClientRectList> Element::getClientRects() 879{ 880 document()->updateLayoutIgnorePendingStylesheets(); 881 882 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject(); 883 if (!renderBoxModelObject) 884 return ClientRectList::create(); 885 886 // FIXME: Handle SVG elements. 887 // FIXME: Handle table/inline-table with a caption. 888 889 Vector<FloatQuad> quads; 890 renderBoxModelObject->absoluteQuads(quads); 891 document()->adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(quads, renderBoxModelObject); 892 return ClientRectList::create(quads); 893} 894 895PassRefPtr<ClientRect> Element::getBoundingClientRect() 896{ 897 document()->updateLayoutIgnorePendingStylesheets(); 898 899 Vector<FloatQuad> quads; 900#if ENABLE(SVG) 901 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) { 902 // Get the bounding rectangle from the SVG model. 903 SVGElement* svgElement = toSVGElement(this); 904 FloatRect localRect; 905 if (svgElement->getBoundingBox(localRect)) 906 quads.append(renderer()->localToAbsoluteQuad(localRect)); 907 } else 908#endif 909 { 910 // Get the bounding rectangle from the box model. 911 if (renderBoxModelObject()) 912 renderBoxModelObject()->absoluteQuads(quads); 913 } 914 915 if (quads.isEmpty()) 916 return ClientRect::create(); 917 918 FloatRect result = quads[0].boundingBox(); 919 for (size_t i = 1; i < quads.size(); ++i) 920 result.unite(quads[i].boundingBox()); 921 922 document()->adjustFloatRectForScrollAndAbsoluteZoomAndFrameScale(result, renderer()); 923 return ClientRect::create(result); 924} 925 926IntRect Element::screenRect() const 927{ 928 if (!renderer()) 929 return IntRect(); 930 // FIXME: this should probably respect transforms 931 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms()); 932} 933 934const AtomicString& Element::getAttribute(const AtomicString& localName) const 935{ 936 if (!elementData()) 937 return nullAtom; 938 synchronizeAttribute(localName); 939 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this))) 940 return attribute->value(); 941 return nullAtom; 942} 943 944const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const 945{ 946 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI)); 947} 948 949void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionCode& ec) 950{ 951 if (!Document::isValidName(localName)) { 952 ec = INVALID_CHARACTER_ERR; 953 return; 954 } 955 956 synchronizeAttribute(localName); 957 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(this) ? localName.lower() : localName; 958 959 unsigned index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : ElementData::attributeNotFound; 960 const QualifiedName& qName = index != ElementData::attributeNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom); 961 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute); 962} 963 964void Element::setAttribute(const QualifiedName& name, const AtomicString& value) 965{ 966 synchronizeAttribute(name); 967 unsigned index = elementData() ? elementData()->getAttributeItemIndex(name) : ElementData::attributeNotFound; 968 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute); 969} 970 971void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value) 972{ 973 unsigned index = elementData() ? elementData()->getAttributeItemIndex(name) : ElementData::attributeNotFound; 974 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute); 975} 976 977inline void Element::setAttributeInternal(unsigned index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute) 978{ 979 if (newValue.isNull()) { 980 if (index != ElementData::attributeNotFound) 981 removeAttributeInternal(index, inSynchronizationOfLazyAttribute); 982 return; 983 } 984 985 if (index == ElementData::attributeNotFound) { 986 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute); 987 return; 988 } 989 990 if (!inSynchronizationOfLazyAttribute) 991 willModifyAttribute(name, attributeItem(index)->value(), newValue); 992 993 if (newValue != attributeItem(index)->value()) { 994 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below 995 // will write into the ElementData. 996 // FIXME: Refactor this so it makes some sense. 997 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(name)) 998 attrNode->setValue(newValue); 999 else 1000 ensureUniqueElementData()->attributeItem(index)->setValue(newValue); 1001 } 1002 1003 if (!inSynchronizationOfLazyAttribute) 1004 didModifyAttribute(name, newValue); 1005} 1006 1007static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode) 1008{ 1009 if (inQuirksMode) 1010 return value.lower(); 1011 return value; 1012} 1013 1014static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, StyleResolver* styleResolver) 1015{ 1016 ASSERT(newId != oldId); 1017 if (!oldId.isEmpty() && styleResolver->hasSelectorForId(oldId)) 1018 return true; 1019 if (!newId.isEmpty() && styleResolver->hasSelectorForId(newId)) 1020 return true; 1021 return false; 1022} 1023 1024void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason) 1025{ 1026 parseAttribute(name, newValue); 1027 1028 document()->incDOMTreeVersion(); 1029 1030 StyleResolver* styleResolver = document()->styleResolverIfExists(); 1031 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange; 1032 bool shouldInvalidateStyle = false; 1033 1034 if (isIdAttributeName(name)) { 1035 AtomicString oldId = elementData()->idForStyleResolution(); 1036 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode()); 1037 if (newId != oldId) { 1038 elementData()->setIdForStyleResolution(newId); 1039 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver); 1040 } 1041 } else if (name == classAttr) 1042 classAttributeChanged(newValue); 1043 else if (name == HTMLNames::nameAttr) 1044 elementData()->m_hasNameAttribute = !newValue.isNull(); 1045 else if (name == HTMLNames::pseudoAttr) 1046 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree(); 1047 1048 1049 invalidateNodeListCachesInAncestors(&name, this); 1050 1051 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style. 1052 shouldInvalidateStyle |= !styleResolver; 1053 1054 if (shouldInvalidateStyle) 1055 setNeedsStyleRecalc(); 1056 1057 if (AXObjectCache* cache = document()->existingAXObjectCache()) 1058 cache->handleAttributeChanged(name, this); 1059} 1060 1061inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason) 1062{ 1063#if ENABLE(CUSTOM_ELEMENTS) 1064 if (name == isAttr) { 1065 if (CustomElementRegistry* registry = document()->registry()) 1066 registry->didGiveTypeExtension(this); 1067 } 1068#endif 1069 attributeChanged(name, newValue, reason); 1070} 1071 1072template <typename CharacterType> 1073static inline bool classStringHasClassName(const CharacterType* characters, unsigned length) 1074{ 1075 ASSERT(length > 0); 1076 1077 unsigned i = 0; 1078 do { 1079 if (isNotHTMLSpace(characters[i])) 1080 break; 1081 ++i; 1082 } while (i < length); 1083 1084 return i < length; 1085} 1086 1087static inline bool classStringHasClassName(const AtomicString& newClassString) 1088{ 1089 unsigned length = newClassString.length(); 1090 1091 if (!length) 1092 return false; 1093 1094 if (newClassString.is8Bit()) 1095 return classStringHasClassName(newClassString.characters8(), length); 1096 return classStringHasClassName(newClassString.characters16(), length); 1097} 1098 1099template<typename Checker> 1100static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker) 1101{ 1102 unsigned changedSize = changedClasses.size(); 1103 for (unsigned i = 0; i < changedSize; ++i) { 1104 if (checker.hasSelectorForClass(changedClasses[i])) 1105 return true; 1106 } 1107 return false; 1108} 1109 1110template<typename Checker> 1111static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker) 1112{ 1113 unsigned oldSize = oldClasses.size(); 1114 if (!oldSize) 1115 return checkSelectorForClassChange(newClasses, checker); 1116 BitVector remainingClassBits; 1117 remainingClassBits.ensureSize(oldSize); 1118 // Class vectors tend to be very short. This is faster than using a hash table. 1119 unsigned newSize = newClasses.size(); 1120 for (unsigned i = 0; i < newSize; ++i) { 1121 for (unsigned j = 0; j < oldSize; ++j) { 1122 if (newClasses[i] == oldClasses[j]) { 1123 remainingClassBits.quickSet(j); 1124 continue; 1125 } 1126 } 1127 if (checker.hasSelectorForClass(newClasses[i])) 1128 return true; 1129 } 1130 for (unsigned i = 0; i < oldSize; ++i) { 1131 // If the bit is not set the the corresponding class has been removed. 1132 if (remainingClassBits.quickGet(i)) 1133 continue; 1134 if (checker.hasSelectorForClass(oldClasses[i])) 1135 return true; 1136 } 1137 return false; 1138} 1139 1140void Element::classAttributeChanged(const AtomicString& newClassString) 1141{ 1142 StyleResolver* styleResolver = document()->styleResolverIfExists(); 1143 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange; 1144 bool shouldInvalidateStyle = false; 1145 1146 if (classStringHasClassName(newClassString)) { 1147 const bool shouldFoldCase = document()->inQuirksMode(); 1148 const SpaceSplitString oldClasses = elementData()->classNames(); 1149 elementData()->setClass(newClassString, shouldFoldCase); 1150 const SpaceSplitString& newClasses = elementData()->classNames(); 1151 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, *styleResolver); 1152 } else { 1153 const SpaceSplitString& oldClasses = elementData()->classNames(); 1154 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, *styleResolver); 1155 elementData()->clearClass(); 1156 } 1157 1158 if (hasRareData()) 1159 elementRareData()->clearClassListValueForQuirksMode(); 1160 1161 if (shouldInvalidateStyle) 1162 setNeedsStyleRecalc(); 1163} 1164 1165// Returns true is the given attribute is an event handler. 1166// We consider an event handler any attribute that begins with "on". 1167// It is a simple solution that has the advantage of not requiring any 1168// code or configuration change if a new event handler is defined. 1169 1170static inline bool isEventHandlerAttribute(const Attribute& attribute) 1171{ 1172 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on"); 1173} 1174 1175bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const 1176{ 1177 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value())); 1178} 1179 1180void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const 1181{ 1182 size_t destination = 0; 1183 for (size_t source = 0; source < attributeVector.size(); ++source) { 1184 if (isEventHandlerAttribute(attributeVector[source]) 1185 || isJavaScriptURLAttribute(attributeVector[source]) 1186 || isHTMLContentAttribute(attributeVector[source])) 1187 continue; 1188 1189 if (source != destination) 1190 attributeVector[destination] = attributeVector[source]; 1191 1192 ++destination; 1193 } 1194 attributeVector.shrink(destination); 1195} 1196 1197void Element::parserSetAttributes(const Vector<Attribute>& attributeVector) 1198{ 1199 ASSERT(!inDocument()); 1200 ASSERT(!parentNode()); 1201 ASSERT(!m_elementData); 1202 1203 if (attributeVector.isEmpty()) 1204 return; 1205 1206 if (document() && document()->sharedObjectPool()) 1207 m_elementData = document()->sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector); 1208 else 1209 m_elementData = ShareableElementData::createWithAttributes(attributeVector); 1210 1211 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData. 1212 for (unsigned i = 0; i < attributeVector.size(); ++i) 1213 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly); 1214} 1215 1216bool Element::hasAttributes() const 1217{ 1218 synchronizeAllAttributes(); 1219 return elementData() && elementData()->length(); 1220} 1221 1222bool Element::hasEquivalentAttributes(const Element* other) const 1223{ 1224 synchronizeAllAttributes(); 1225 other->synchronizeAllAttributes(); 1226 if (elementData() == other->elementData()) 1227 return true; 1228 if (elementData()) 1229 return elementData()->isEquivalent(other->elementData()); 1230 if (other->elementData()) 1231 return other->elementData()->isEquivalent(elementData()); 1232 return true; 1233} 1234 1235String Element::nodeName() const 1236{ 1237 return m_tagName.toString(); 1238} 1239 1240String Element::nodeNamePreservingCase() const 1241{ 1242 return m_tagName.toString(); 1243} 1244 1245void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec) 1246{ 1247 ec = 0; 1248 checkSetPrefix(prefix, ec); 1249 if (ec) 1250 return; 1251 1252 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix); 1253} 1254 1255KURL Element::baseURI() const 1256{ 1257 const AtomicString& baseAttribute = getAttribute(baseAttr); 1258 KURL base(KURL(), baseAttribute); 1259 if (!base.protocol().isEmpty()) 1260 return base; 1261 1262 ContainerNode* parent = parentNode(); 1263 if (!parent) 1264 return base; 1265 1266 const KURL& parentBase = parent->baseURI(); 1267 if (parentBase.isNull()) 1268 return base; 1269 1270 return KURL(parentBase, baseAttribute); 1271} 1272 1273const AtomicString& Element::imageSourceURL() const 1274{ 1275 return getAttribute(srcAttr); 1276} 1277 1278bool Element::rendererIsNeeded(const NodeRenderingContext& context) 1279{ 1280 return context.style()->display() != NONE; 1281} 1282 1283RenderObject* Element::createRenderer(RenderArena*, RenderStyle* style) 1284{ 1285 return RenderObject::createObject(this, style); 1286} 1287 1288bool Element::isDisabledFormControl() const 1289{ 1290#if ENABLE(DIALOG_ELEMENT) 1291 // FIXME: disabled and inert are separate concepts in the spec, but now we treat them as the same. 1292 // For example, an inert, non-disabled form control should not be grayed out. 1293 if (isInert()) 1294 return true; 1295#endif 1296 return false; 1297} 1298 1299#if ENABLE(DIALOG_ELEMENT) 1300bool Element::isInert() const 1301{ 1302 Element* dialog = document()->activeModalDialog(); 1303 return dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this); 1304} 1305#endif 1306 1307Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint) 1308{ 1309 bool wasInDocument = inDocument(); 1310 // need to do superclass processing first so inDocument() is true 1311 // by the time we reach updateId 1312 ContainerNode::insertedInto(insertionPoint); 1313 ASSERT(!wasInDocument || inDocument()); 1314 1315#if ENABLE(FULLSCREEN_API) 1316 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement()) 1317 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true); 1318#endif 1319 1320 if (Element* before = pseudoElement(BEFORE)) 1321 before->insertedInto(insertionPoint); 1322 1323 if (Element* after = pseudoElement(AFTER)) 1324 after->insertedInto(insertionPoint); 1325 1326 if (!insertionPoint->isInTreeScope()) 1327 return InsertionDone; 1328 1329 if (hasRareData()) 1330 elementRareData()->clearClassListValueForQuirksMode(); 1331 1332 TreeScope* newScope = insertionPoint->treeScope(); 1333 HTMLDocument* newDocument = !wasInDocument && inDocument() && newScope->documentScope()->isHTMLDocument() ? toHTMLDocument(newScope->documentScope()) : 0; 1334 if (newScope != treeScope()) 1335 newScope = 0; 1336 1337 const AtomicString& idValue = getIdAttribute(); 1338 if (!idValue.isNull()) { 1339 if (newScope) 1340 updateIdForTreeScope(newScope, nullAtom, idValue); 1341 if (newDocument) 1342 updateIdForDocument(newDocument, nullAtom, idValue, AlwaysUpdateHTMLDocumentNamedItemMaps); 1343 } 1344 1345 const AtomicString& nameValue = getNameAttribute(); 1346 if (!nameValue.isNull()) { 1347 if (newScope) 1348 updateNameForTreeScope(newScope, nullAtom, nameValue); 1349 if (newDocument) 1350 updateNameForDocument(newDocument, nullAtom, nameValue); 1351 } 1352 1353 if (newScope && hasTagName(labelTag)) { 1354 if (newScope->shouldCacheLabelsByForAttribute()) 1355 updateLabel(newScope, nullAtom, fastGetAttribute(forAttr)); 1356 } 1357 1358 return InsertionDone; 1359} 1360 1361void Element::removedFrom(ContainerNode* insertionPoint) 1362{ 1363#if ENABLE(SVG) 1364 bool wasInDocument = insertionPoint->document(); 1365#endif 1366 1367 if (Element* before = pseudoElement(BEFORE)) 1368 before->removedFrom(insertionPoint); 1369 1370 if (Element* after = pseudoElement(AFTER)) 1371 after->removedFrom(insertionPoint); 1372 1373#if ENABLE(DIALOG_ELEMENT) 1374 document()->removeFromTopLayer(this); 1375#endif 1376#if ENABLE(FULLSCREEN_API) 1377 if (containsFullScreenElement()) 1378 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false); 1379#endif 1380#if ENABLE(POINTER_LOCK) 1381 if (document()->page()) 1382 document()->page()->pointerLockController()->elementRemoved(this); 1383#endif 1384 1385 setSavedLayerScrollOffset(IntSize()); 1386 1387 if (insertionPoint->isInTreeScope()) { 1388 TreeScope* oldScope = insertionPoint->treeScope(); 1389 HTMLDocument* oldDocument = inDocument() && oldScope->documentScope()->isHTMLDocument() ? toHTMLDocument(oldScope->documentScope()) : 0; 1390 if (oldScope != treeScope() || !isInTreeScope()) 1391 oldScope = 0; 1392 1393 const AtomicString& idValue = getIdAttribute(); 1394 if (!idValue.isNull()) { 1395 if (oldScope) 1396 updateIdForTreeScope(oldScope, idValue, nullAtom); 1397 if (oldDocument) 1398 updateIdForDocument(oldDocument, idValue, nullAtom, AlwaysUpdateHTMLDocumentNamedItemMaps); 1399 } 1400 1401 const AtomicString& nameValue = getNameAttribute(); 1402 if (!nameValue.isNull()) { 1403 if (oldScope) 1404 updateNameForTreeScope(oldScope, nameValue, nullAtom); 1405 if (oldDocument) 1406 updateNameForDocument(oldDocument, nameValue, nullAtom); 1407 } 1408 1409 if (oldScope && hasTagName(labelTag)) { 1410 if (oldScope->shouldCacheLabelsByForAttribute()) 1411 updateLabel(oldScope, fastGetAttribute(forAttr), nullAtom); 1412 } 1413 } 1414 1415 ContainerNode::removedFrom(insertionPoint); 1416#if ENABLE(SVG) 1417 if (wasInDocument && hasPendingResources()) 1418 document()->accessSVGExtensions()->removeElementFromPendingResources(this); 1419#endif 1420} 1421 1422void Element::createRendererIfNeeded(const AttachContext& context) 1423{ 1424 NodeRenderingContext(this, context).createRendererForElementIfNeeded(); 1425} 1426 1427void Element::attach(const AttachContext& context) 1428{ 1429 PostAttachCallbackDisabler callbackDisabler(this); 1430 StyleResolverParentPusher parentPusher(this); 1431 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; 1432 1433 createRendererIfNeeded(context); 1434 1435 if (parentElement() && parentElement()->isInCanvasSubtree()) 1436 setIsInCanvasSubtree(true); 1437 1438 updatePseudoElement(BEFORE); 1439 1440 // When a shadow root exists, it does the work of attaching the children. 1441 if (ElementShadow* shadow = this->shadow()) { 1442 parentPusher.push(); 1443 shadow->attach(); 1444 } else if (firstChild()) 1445 parentPusher.push(); 1446 1447 ContainerNode::attach(context); 1448 1449 updatePseudoElement(AFTER); 1450 1451 if (hasRareData()) { 1452 ElementRareData* data = elementRareData(); 1453 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) { 1454 if (isFocusable() && document()->focusedElement() == this) 1455 document()->updateFocusAppearanceSoon(false /* don't restore selection */); 1456 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false); 1457 } 1458 } 1459} 1460 1461void Element::unregisterNamedFlowContentNode() 1462{ 1463 if (document()->cssRegionsEnabled() && inNamedFlow() && document()->renderView()) 1464 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this); 1465} 1466 1467void Element::detach(const AttachContext& context) 1468{ 1469 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; 1470 unregisterNamedFlowContentNode(); 1471 cancelFocusAppearanceUpdate(); 1472 if (hasRareData()) { 1473 ElementRareData* data = elementRareData(); 1474 data->setPseudoElement(BEFORE, 0); 1475 data->setPseudoElement(AFTER, 0); 1476 data->setIsInCanvasSubtree(false); 1477 data->resetComputedStyle(); 1478 data->resetDynamicRestyleObservations(); 1479 data->setIsInsideRegion(false); 1480 } 1481 1482 if (ElementShadow* shadow = this->shadow()) { 1483 detachChildrenIfNeeded(); 1484 shadow->detach(); 1485 } 1486 1487 // Do not remove the element's hovered and active status 1488 // if performing a reattach. 1489 if (!context.performingReattach) { 1490 if (isUserActionElement()) { 1491 if (hovered()) 1492 document()->hoveredElementDidDetach(this); 1493 if (inActiveChain()) 1494 document()->elementInActiveChainDidDetach(this); 1495 document()->userActionElements().didDetach(this); 1496 } 1497 } 1498 1499 ContainerNode::detach(context); 1500} 1501 1502bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle) 1503{ 1504 ASSERT(currentStyle == renderStyle()); 1505 ASSERT(renderer()); 1506 1507 if (!currentStyle) 1508 return false; 1509 1510 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles(); 1511 if (!pseudoStyleCache) 1512 return false; 1513 1514 size_t cacheSize = pseudoStyleCache->size(); 1515 for (size_t i = 0; i < cacheSize; ++i) { 1516 RefPtr<RenderStyle> newPseudoStyle; 1517 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType(); 1518 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) 1519 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle); 1520 else 1521 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle); 1522 if (!newPseudoStyle) 1523 return true; 1524 if (*newPseudoStyle != *pseudoStyleCache->at(i)) { 1525 if (pseudoId < FIRST_INTERNAL_PSEUDOID) 1526 newStyle->setHasPseudoStyle(pseudoId); 1527 newStyle->addCachedPseudoStyle(newPseudoStyle); 1528 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) { 1529 // FIXME: We should do an actual diff to determine whether a repaint vs. layout 1530 // is needed, but for now just assume a layout will be required. The diff code 1531 // in RenderObject::setStyle would need to be factored out so that it could be reused. 1532 renderer()->setNeedsLayoutAndPrefWidthsRecalc(); 1533 } 1534 return true; 1535 } 1536 } 1537 return false; 1538} 1539 1540PassRefPtr<RenderStyle> Element::styleForRenderer() 1541{ 1542 if (hasCustomStyleCallbacks()) { 1543 if (RefPtr<RenderStyle> style = customStyleForRenderer()) 1544 return style.release(); 1545 } 1546 1547 return document()->ensureStyleResolver()->styleForElement(this); 1548} 1549 1550void Element::recalcStyle(StyleChange change) 1551{ 1552 if (hasCustomStyleCallbacks()) { 1553 if (!willRecalcStyle(change)) 1554 return; 1555 } 1556 1557 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer. 1558 RefPtr<RenderStyle> currentStyle(renderStyle()); 1559 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false; 1560 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules(); 1561 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules(); 1562 1563 if ((change > NoChange || needsStyleRecalc())) { 1564 if (hasRareData()) 1565 elementRareData()->resetComputedStyle(); 1566 } 1567 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) { 1568 StyleChange localChange = Detach; 1569 RefPtr<RenderStyle> newStyle; 1570 if (currentStyle) { 1571 newStyle = styleForRenderer(); 1572 localChange = Node::diff(currentStyle.get(), newStyle.get(), document()); 1573 } 1574 if (localChange == Detach) { 1575 AttachContext reattachContext; 1576 reattachContext.resolvedStyle = newStyle.get(); 1577 reattach(reattachContext); 1578 1579 // attach recalculates the style for all children. No need to do it twice. 1580 clearNeedsStyleRecalc(); 1581 clearChildNeedsStyleRecalc(); 1582 1583 if (hasCustomStyleCallbacks()) 1584 didRecalcStyle(change); 1585 return; 1586 } 1587 1588 if (RenderObject* renderer = this->renderer()) { 1589 if (localChange != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange) 1590 renderer->setAnimatableStyle(newStyle.get()); 1591 else if (needsStyleRecalc()) { 1592 // Although no change occurred, we use the new style so that the cousin style sharing code won't get 1593 // fooled into believing this style is the same. 1594 renderer->setStyleInternal(newStyle.get()); 1595 } 1596 } 1597 1598 // 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 1599 // 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). 1600 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) { 1601 // Cached RenderStyles may depend on the re units. 1602 if (StyleResolver* styleResolver = document()->styleResolverIfExists()) 1603 styleResolver->invalidateMatchedPropertiesCache(); 1604 change = Force; 1605 } 1606 1607 if (change != Force) { 1608 if (styleChangeType() >= FullStyleChange) 1609 change = Force; 1610 else 1611 change = localChange; 1612 } 1613 } 1614 StyleResolverParentPusher parentPusher(this); 1615 1616 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world. 1617 if (ElementShadow* shadow = this->shadow()) { 1618 if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) { 1619 parentPusher.push(); 1620 shadow->recalcStyle(change); 1621 } 1622 } 1623 1624 updatePseudoElement(BEFORE, change); 1625 1626 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar. 1627 // For now we will just worry about the common case, since it's a lot trickier to get the second case right 1628 // without doing way too much re-resolution. 1629 bool forceCheckOfNextElementSibling = false; 1630 bool forceCheckOfAnyElementSibling = false; 1631 for (Node *n = firstChild(); n; n = n->nextSibling()) { 1632 if (n->isTextNode()) { 1633 toText(n)->recalcTextStyle(change); 1634 continue; 1635 } 1636 if (!n->isElementNode()) 1637 continue; 1638 Element* element = toElement(n); 1639 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange; 1640 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)) 1641 element->setNeedsStyleRecalc(); 1642 if (change >= Inherit || element->childNeedsStyleRecalc() || element->needsStyleRecalc()) { 1643 parentPusher.push(); 1644 element->recalcStyle(change); 1645 } 1646 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules; 1647 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules); 1648 } 1649 1650 updatePseudoElement(AFTER, change); 1651 1652 clearNeedsStyleRecalc(); 1653 clearChildNeedsStyleRecalc(); 1654 1655 if (hasCustomStyleCallbacks()) 1656 didRecalcStyle(change); 1657} 1658 1659ElementShadow* Element::shadow() const 1660{ 1661 return hasRareData() ? elementRareData()->shadow() : 0; 1662} 1663 1664ElementShadow* Element::ensureShadow() 1665{ 1666 return ensureElementRareData()->ensureShadow(); 1667} 1668 1669void Element::didAffectSelector(AffectedSelectorMask) 1670{ 1671 setNeedsStyleRecalc(); 1672} 1673 1674PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec) 1675{ 1676 if (alwaysCreateUserAgentShadowRoot()) 1677 ensureUserAgentShadowRoot(); 1678 1679#if ENABLE(SHADOW_DOM) 1680 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled()) 1681 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot); 1682#endif 1683 1684 // Since some elements recreates shadow root dynamically, multiple shadow 1685 // subtrees won't work well in that element. Until they are fixed, we disable 1686 // adding author shadow root for them. 1687 if (!areAuthorShadowsAllowed()) { 1688 ec = HIERARCHY_REQUEST_ERR; 1689 return 0; 1690 } 1691 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot); 1692} 1693 1694ShadowRoot* Element::authorShadowRoot() const 1695{ 1696 ElementShadow* elementShadow = shadow(); 1697 if (!elementShadow) 1698 return 0; 1699 ShadowRoot* shadowRoot = elementShadow->shadowRoot(); 1700 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot) 1701 return shadowRoot; 1702 return 0; 1703} 1704 1705ShadowRoot* Element::userAgentShadowRoot() const 1706{ 1707 if (ElementShadow* elementShadow = shadow()) { 1708 if (ShadowRoot* shadowRoot = elementShadow->shadowRoot()) { 1709 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot); 1710 return shadowRoot; 1711 } 1712 } 1713 1714 return 0; 1715} 1716 1717ShadowRoot* Element::ensureUserAgentShadowRoot() 1718{ 1719 ShadowRoot* shadowRoot = userAgentShadowRoot(); 1720 if (!shadowRoot) { 1721 shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot); 1722 didAddUserAgentShadowRoot(shadowRoot); 1723 } 1724 return shadowRoot; 1725} 1726 1727const AtomicString& Element::shadowPseudoId() const 1728{ 1729 return pseudo(); 1730} 1731 1732bool Element::childTypeAllowed(NodeType type) const 1733{ 1734 switch (type) { 1735 case ELEMENT_NODE: 1736 case TEXT_NODE: 1737 case COMMENT_NODE: 1738 case PROCESSING_INSTRUCTION_NODE: 1739 case CDATA_SECTION_NODE: 1740 case ENTITY_REFERENCE_NODE: 1741 return true; 1742 default: 1743 break; 1744 } 1745 return false; 1746} 1747 1748static void checkForEmptyStyleChange(Element* element, RenderStyle* style) 1749{ 1750 if (!style && !element->styleAffectedByEmpty()) 1751 return; 1752 1753 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes()))) 1754 element->setNeedsStyleRecalc(); 1755} 1756 1757static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback, 1758 Node* beforeChange, Node* afterChange, int childCountDelta) 1759{ 1760 // :empty selector. 1761 checkForEmptyStyleChange(e, style); 1762 1763 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules())) 1764 return; 1765 1766 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time. 1767 // In the DOM case, we only need to do something if |afterChange| is not 0. 1768 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block. 1769 if (e->childrenAffectedByFirstChildRules() && afterChange) { 1770 // Find our new first child. 1771 Node* newFirstChild = 0; 1772 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {}; 1773 1774 // Find the first element node following |afterChange| 1775 Node* firstElementAfterInsertion = 0; 1776 for (firstElementAfterInsertion = afterChange; 1777 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); 1778 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; 1779 1780 // This is the insert/append case. 1781 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() && 1782 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState()) 1783 firstElementAfterInsertion->setNeedsStyleRecalc(); 1784 1785 // We also have to handle node removal. 1786 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChild->renderStyle() || !newFirstChild->renderStyle()->firstChildState())) 1787 newFirstChild->setNeedsStyleRecalc(); 1788 } 1789 1790 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time. 1791 // In the DOM case, we only need to do something if |afterChange| is not 0. 1792 if (e->childrenAffectedByLastChildRules() && beforeChange) { 1793 // Find our new last child. 1794 Node* newLastChild = 0; 1795 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {}; 1796 1797 // Find the last element node going backwards from |beforeChange| 1798 Node* lastElementBeforeInsertion = 0; 1799 for (lastElementBeforeInsertion = beforeChange; 1800 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode(); 1801 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {}; 1802 1803 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() && 1804 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState()) 1805 lastElementBeforeInsertion->setNeedsStyleRecalc(); 1806 1807 // 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 1808 // to match now. 1809 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChild->renderStyle() || !newLastChild->renderStyle()->lastChildState())) 1810 newLastChild->setNeedsStyleRecalc(); 1811 } 1812 1813 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element 1814 // that could be affected by this DOM change. 1815 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) { 1816 Node* firstElementAfterInsertion = 0; 1817 for (firstElementAfterInsertion = afterChange; 1818 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); 1819 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; 1820 if (firstElementAfterInsertion && firstElementAfterInsertion->attached()) 1821 firstElementAfterInsertion->setNeedsStyleRecalc(); 1822 } 1823 1824 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type. 1825 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type. 1826 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the 1827 // backward case. 1828 // |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. 1829 // 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 1830 // here. recalcStyle will then force a walk of the children when it sees that this has happened. 1831 if ((e->childrenAffectedByForwardPositionalRules() && afterChange) 1832 || (e->childrenAffectedByBackwardPositionalRules() && beforeChange)) 1833 e->setNeedsStyleRecalc(); 1834} 1835 1836void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 1837{ 1838 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 1839 if (changedByParser) 1840 checkForEmptyStyleChange(this, renderStyle()); 1841 else 1842 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta); 1843 1844 if (ElementShadow * shadow = this->shadow()) 1845 shadow->invalidateDistribution(); 1846} 1847 1848void Element::removeAllEventListeners() 1849{ 1850 ContainerNode::removeAllEventListeners(); 1851 if (ElementShadow* shadow = this->shadow()) 1852 shadow->removeAllEventListeners(); 1853} 1854 1855void Element::beginParsingChildren() 1856{ 1857 clearIsParsingChildrenFinished(); 1858 StyleResolver* styleResolver = document()->styleResolverIfExists(); 1859 if (styleResolver && attached()) 1860 styleResolver->pushParentElement(this); 1861} 1862 1863void Element::finishParsingChildren() 1864{ 1865 ContainerNode::finishParsingChildren(); 1866 setIsParsingChildrenFinished(); 1867 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0); 1868 if (StyleResolver* styleResolver = document()->styleResolverIfExists()) 1869 styleResolver->popParentElement(this); 1870} 1871 1872#ifndef NDEBUG 1873void Element::formatForDebugger(char* buffer, unsigned length) const 1874{ 1875 StringBuilder result; 1876 String s; 1877 1878 result.append(nodeName()); 1879 1880 s = getIdAttribute(); 1881 if (s.length() > 0) { 1882 if (result.length() > 0) 1883 result.appendLiteral("; "); 1884 result.appendLiteral("id="); 1885 result.append(s); 1886 } 1887 1888 s = getAttribute(classAttr); 1889 if (s.length() > 0) { 1890 if (result.length() > 0) 1891 result.appendLiteral("; "); 1892 result.appendLiteral("class="); 1893 result.append(s); 1894 } 1895 1896 strncpy(buffer, result.toString().utf8().data(), length - 1); 1897} 1898#endif 1899 1900const Vector<RefPtr<Attr> >& Element::attrNodeList() 1901{ 1902 ASSERT(hasSyntheticAttrChildNodes()); 1903 return *attrNodeListForElement(this); 1904} 1905 1906PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec) 1907{ 1908 if (!attrNode) { 1909 ec = TYPE_MISMATCH_ERR; 1910 return 0; 1911 } 1912 1913 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName()); 1914 if (oldAttrNode.get() == attrNode) 1915 return attrNode; // This Attr is already attached to the element. 1916 1917 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object. 1918 // The DOM user must explicitly clone Attr nodes to re-use them in other elements. 1919 if (attrNode->ownerElement()) { 1920 ec = INUSE_ATTRIBUTE_ERR; 1921 return 0; 1922 } 1923 1924 synchronizeAllAttributes(); 1925 UniqueElementData* elementData = ensureUniqueElementData(); 1926 1927 unsigned index = elementData->getAttributeItemIndexForAttributeNode(attrNode); 1928 if (index != ElementData::attributeNotFound) { 1929 if (oldAttrNode) 1930 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value()); 1931 else 1932 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value()); 1933 } 1934 1935 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute); 1936 1937 attrNode->attachToElement(this); 1938 treeScope()->adoptIfNeeded(attrNode); 1939 ensureAttrNodeListForElement(this)->append(attrNode); 1940 1941 return oldAttrNode.release(); 1942} 1943 1944PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec) 1945{ 1946 return setAttributeNode(attr, ec); 1947} 1948 1949PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec) 1950{ 1951 if (!attr) { 1952 ec = TYPE_MISMATCH_ERR; 1953 return 0; 1954 } 1955 if (attr->ownerElement() != this) { 1956 ec = NOT_FOUND_ERR; 1957 return 0; 1958 } 1959 1960 ASSERT(document() == attr->document()); 1961 1962 synchronizeAttribute(attr->qualifiedName()); 1963 1964 unsigned index = elementData()->getAttributeItemIndexForAttributeNode(attr); 1965 if (index == ElementData::attributeNotFound) { 1966 ec = NOT_FOUND_ERR; 1967 return 0; 1968 } 1969 1970 RefPtr<Attr> attrNode = attr; 1971 detachAttrNodeFromElementWithValue(attr, elementData()->attributeItem(index)->value()); 1972 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute); 1973 return attrNode.release(); 1974} 1975 1976bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec) 1977{ 1978 String prefix, localName; 1979 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec)) 1980 return false; 1981 ASSERT(!ec); 1982 1983 QualifiedName qName(prefix, localName, namespaceURI); 1984 1985 if (!Document::hasValidNamespaceForAttributes(qName)) { 1986 ec = NAMESPACE_ERR; 1987 return false; 1988 } 1989 1990 out = qName; 1991 return true; 1992} 1993 1994void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec) 1995{ 1996 QualifiedName parsedName = anyName; 1997 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec)) 1998 return; 1999 setAttribute(parsedName, value); 2000} 2001 2002void Element::removeAttributeInternal(unsigned index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute) 2003{ 2004 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount()); 2005 2006 UniqueElementData* elementData = ensureUniqueElementData(); 2007 2008 QualifiedName name = elementData->attributeItem(index)->name(); 2009 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value(); 2010 2011 if (!inSynchronizationOfLazyAttribute) { 2012 if (!valueBeingRemoved.isNull()) 2013 willModifyAttribute(name, valueBeingRemoved, nullAtom); 2014 } 2015 2016 if (RefPtr<Attr> attrNode = attrIfExists(name)) 2017 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value()); 2018 2019 elementData->removeAttribute(index); 2020 2021 if (!inSynchronizationOfLazyAttribute) 2022 didRemoveAttribute(name); 2023} 2024 2025void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute) 2026{ 2027 if (!inSynchronizationOfLazyAttribute) 2028 willModifyAttribute(name, nullAtom, value); 2029 ensureUniqueElementData()->addAttribute(name, value); 2030 if (!inSynchronizationOfLazyAttribute) 2031 didAddAttribute(name, value); 2032} 2033 2034void Element::removeAttribute(const AtomicString& name) 2035{ 2036 if (!elementData()) 2037 return; 2038 2039 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 2040 unsigned index = elementData()->getAttributeItemIndex(localName, false); 2041 if (index == ElementData::attributeNotFound) { 2042 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement()) 2043 static_cast<StyledElement*>(this)->removeAllInlineStyleProperties(); 2044 return; 2045 } 2046 2047 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute); 2048} 2049 2050void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) 2051{ 2052 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI)); 2053} 2054 2055PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName) 2056{ 2057 if (!elementData()) 2058 return 0; 2059 synchronizeAttribute(localName); 2060 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this)); 2061 if (!attribute) 2062 return 0; 2063 return ensureAttr(attribute->name()); 2064} 2065 2066PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName) 2067{ 2068 if (!elementData()) 2069 return 0; 2070 QualifiedName qName(nullAtom, localName, namespaceURI); 2071 synchronizeAttribute(qName); 2072 const Attribute* attribute = elementData()->getAttributeItem(qName); 2073 if (!attribute) 2074 return 0; 2075 return ensureAttr(attribute->name()); 2076} 2077 2078bool Element::hasAttribute(const AtomicString& localName) const 2079{ 2080 if (!elementData()) 2081 return false; 2082 synchronizeAttribute(localName); 2083 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false); 2084} 2085 2086bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const 2087{ 2088 if (!elementData()) 2089 return false; 2090 QualifiedName qName(nullAtom, localName, namespaceURI); 2091 synchronizeAttribute(qName); 2092 return elementData()->getAttributeItem(qName); 2093} 2094 2095CSSStyleDeclaration *Element::style() 2096{ 2097 return 0; 2098} 2099 2100void Element::focus(bool restorePreviousSelection, FocusDirection direction) 2101{ 2102 if (!inDocument()) 2103 return; 2104 2105 Document* doc = document(); 2106 if (doc->focusedElement() == this) 2107 return; 2108 2109 // If the stylesheets have already been loaded we can reliably check isFocusable. 2110 // If not, we continue and set the focused node on the focus controller below so 2111 // that it can be updated soon after attach. 2112 if (doc->haveStylesheetsLoaded()) { 2113 doc->updateLayoutIgnorePendingStylesheets(); 2114 if (!isFocusable()) 2115 return; 2116 } 2117 2118 if (!supportsFocus()) 2119 return; 2120 2121 RefPtr<Node> protect; 2122 if (Page* page = doc->page()) { 2123 // Focus and change event handlers can cause us to lose our last ref. 2124 // If a focus event handler changes the focus to a different node it 2125 // does not make sense to continue and update appearence. 2126 protect = this; 2127 if (!page->focusController()->setFocusedElement(this, doc->frame(), direction)) 2128 return; 2129 } 2130 2131 // Setting the focused node above might have invalidated the layout due to scripts. 2132 doc->updateLayoutIgnorePendingStylesheets(); 2133 2134 if (!isFocusable()) { 2135 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true); 2136 return; 2137 } 2138 2139 cancelFocusAppearanceUpdate(); 2140 updateFocusAppearance(restorePreviousSelection); 2141} 2142 2143void Element::updateFocusAppearance(bool /*restorePreviousSelection*/) 2144{ 2145 if (isRootEditableElement()) { 2146 Frame* frame = document()->frame(); 2147 if (!frame) 2148 return; 2149 2150 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection. 2151 if (this == frame->selection()->rootEditableElement()) 2152 return; 2153 2154 // FIXME: We should restore the previous selection if there is one. 2155 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM); 2156 2157 if (frame->selection()->shouldChangeSelection(newSelection)) { 2158 frame->selection()->setSelection(newSelection); 2159 frame->selection()->revealSelection(); 2160 } 2161 } else if (renderer() && !renderer()->isWidget()) 2162 renderer()->scrollRectToVisible(boundingBox()); 2163} 2164 2165void Element::blur() 2166{ 2167 cancelFocusAppearanceUpdate(); 2168 Document* doc = document(); 2169 if (treeScope()->focusedElement() == this) { 2170 if (doc->frame()) 2171 doc->frame()->page()->focusController()->setFocusedElement(0, doc->frame()); 2172 else 2173 doc->setFocusedElement(0); 2174 } 2175} 2176 2177void Element::dispatchFocusInEvent(const AtomicString& eventType, PassRefPtr<Element> oldFocusedElement) 2178{ 2179 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 2180 ASSERT(eventType == eventNames().focusinEvent || eventType == eventNames().DOMFocusInEvent); 2181 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document()->defaultView(), 0, oldFocusedElement))); 2182} 2183 2184void Element::dispatchFocusOutEvent(const AtomicString& eventType, PassRefPtr<Element> newFocusedElement) 2185{ 2186 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 2187 ASSERT(eventType == eventNames().focusoutEvent || eventType == eventNames().DOMFocusOutEvent); 2188 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document()->defaultView(), 0, newFocusedElement))); 2189} 2190 2191void Element::dispatchFocusEvent(PassRefPtr<Element> oldFocusedElement, FocusDirection) 2192{ 2193 if (document()->page()) 2194 document()->page()->chrome().client()->elementDidFocus(this); 2195 2196 RefPtr<FocusEvent> event = FocusEvent::create(eventNames().focusEvent, false, false, document()->defaultView(), 0, oldFocusedElement); 2197 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release())); 2198} 2199 2200void Element::dispatchBlurEvent(PassRefPtr<Element> newFocusedElement) 2201{ 2202 if (document()->page()) 2203 document()->page()->chrome().client()->elementDidBlur(this); 2204 2205 RefPtr<FocusEvent> event = FocusEvent::create(eventNames().blurEvent, false, false, document()->defaultView(), 0, newFocusedElement); 2206 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release())); 2207} 2208 2209 2210String Element::innerText() 2211{ 2212 // We need to update layout, since plainText uses line boxes in the render tree. 2213 document()->updateLayoutIgnorePendingStylesheets(); 2214 2215 if (!renderer()) 2216 return textContent(true); 2217 2218 return plainText(rangeOfContents(const_cast<Element*>(this)).get()); 2219} 2220 2221String Element::outerText() 2222{ 2223 // Getting outerText is the same as getting innerText, only 2224 // setting is different. You would think this should get the plain 2225 // text for the outer range, but this is wrong, <br> for instance 2226 // would return different values for inner and outer text by such 2227 // a rule, but it doesn't in WinIE, and we want to match that. 2228 return innerText(); 2229} 2230 2231String Element::title() const 2232{ 2233 return String(); 2234} 2235 2236const AtomicString& Element::pseudo() const 2237{ 2238 return getAttribute(pseudoAttr); 2239} 2240 2241void Element::setPseudo(const AtomicString& value) 2242{ 2243 setAttribute(pseudoAttr, value); 2244} 2245 2246LayoutSize Element::minimumSizeForResizing() const 2247{ 2248 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing(); 2249} 2250 2251void Element::setMinimumSizeForResizing(const LayoutSize& size) 2252{ 2253 if (!hasRareData() && size == defaultMinimumSizeForResizing()) 2254 return; 2255 ensureElementRareData()->setMinimumSizeForResizing(size); 2256} 2257 2258RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier) 2259{ 2260 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier)) 2261 return element->computedStyle(); 2262 2263 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length' 2264 // properties, which are only known by the renderer because it did the layout, will be correct and so that the 2265 // values returned for the ":selection" pseudo-element will be correct. 2266 if (RenderStyle* usedStyle = renderStyle()) { 2267 if (pseudoElementSpecifier) { 2268 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier); 2269 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle; 2270 } else 2271 return usedStyle; 2272 } 2273 2274 if (!attached()) 2275 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the 2276 // document tree and figure out when to destroy the computed style for such elements. 2277 return 0; 2278 2279 ElementRareData* data = ensureElementRareData(); 2280 if (!data->computedStyle()) 2281 data->setComputedStyle(document()->styleForElementIgnoringPendingStylesheets(this)); 2282 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle(); 2283} 2284 2285void Element::setStyleAffectedByEmpty() 2286{ 2287 ensureElementRareData()->setStyleAffectedByEmpty(true); 2288} 2289 2290void Element::setChildrenAffectedByHover(bool value) 2291{ 2292 if (value || hasRareData()) 2293 ensureElementRareData()->setChildrenAffectedByHover(value); 2294} 2295 2296void Element::setChildrenAffectedByActive(bool value) 2297{ 2298 if (value || hasRareData()) 2299 ensureElementRareData()->setChildrenAffectedByActive(value); 2300} 2301 2302void Element::setChildrenAffectedByDrag(bool value) 2303{ 2304 if (value || hasRareData()) 2305 ensureElementRareData()->setChildrenAffectedByDrag(value); 2306} 2307 2308void Element::setChildrenAffectedByFirstChildRules() 2309{ 2310 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true); 2311} 2312 2313void Element::setChildrenAffectedByLastChildRules() 2314{ 2315 ensureElementRareData()->setChildrenAffectedByLastChildRules(true); 2316} 2317 2318void Element::setChildrenAffectedByDirectAdjacentRules() 2319{ 2320 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true); 2321} 2322 2323void Element::setChildrenAffectedByForwardPositionalRules() 2324{ 2325 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true); 2326} 2327 2328void Element::setChildrenAffectedByBackwardPositionalRules() 2329{ 2330 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true); 2331} 2332 2333void Element::setChildIndex(unsigned index) 2334{ 2335 ElementRareData* rareData = ensureElementRareData(); 2336 if (RenderStyle* style = renderStyle()) 2337 style->setUnique(); 2338 rareData->setChildIndex(index); 2339} 2340 2341bool Element::hasFlagsSetDuringStylingOfChildren() const 2342{ 2343 if (!hasRareData()) 2344 return false; 2345 return rareDataChildrenAffectedByHover() 2346 || rareDataChildrenAffectedByActive() 2347 || rareDataChildrenAffectedByDrag() 2348 || rareDataChildrenAffectedByFirstChildRules() 2349 || rareDataChildrenAffectedByLastChildRules() 2350 || rareDataChildrenAffectedByDirectAdjacentRules() 2351 || rareDataChildrenAffectedByForwardPositionalRules() 2352 || rareDataChildrenAffectedByBackwardPositionalRules(); 2353} 2354 2355bool Element::rareDataStyleAffectedByEmpty() const 2356{ 2357 ASSERT(hasRareData()); 2358 return elementRareData()->styleAffectedByEmpty(); 2359} 2360 2361bool Element::rareDataChildrenAffectedByHover() const 2362{ 2363 ASSERT(hasRareData()); 2364 return elementRareData()->childrenAffectedByHover(); 2365} 2366 2367bool Element::rareDataChildrenAffectedByActive() const 2368{ 2369 ASSERT(hasRareData()); 2370 return elementRareData()->childrenAffectedByActive(); 2371} 2372 2373bool Element::rareDataChildrenAffectedByDrag() const 2374{ 2375 ASSERT(hasRareData()); 2376 return elementRareData()->childrenAffectedByDrag(); 2377} 2378 2379bool Element::rareDataChildrenAffectedByFirstChildRules() const 2380{ 2381 ASSERT(hasRareData()); 2382 return elementRareData()->childrenAffectedByFirstChildRules(); 2383} 2384 2385bool Element::rareDataChildrenAffectedByLastChildRules() const 2386{ 2387 ASSERT(hasRareData()); 2388 return elementRareData()->childrenAffectedByLastChildRules(); 2389} 2390 2391bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const 2392{ 2393 ASSERT(hasRareData()); 2394 return elementRareData()->childrenAffectedByDirectAdjacentRules(); 2395} 2396 2397bool Element::rareDataChildrenAffectedByForwardPositionalRules() const 2398{ 2399 ASSERT(hasRareData()); 2400 return elementRareData()->childrenAffectedByForwardPositionalRules(); 2401} 2402 2403bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const 2404{ 2405 ASSERT(hasRareData()); 2406 return elementRareData()->childrenAffectedByBackwardPositionalRules(); 2407} 2408 2409unsigned Element::rareDataChildIndex() const 2410{ 2411 ASSERT(hasRareData()); 2412 return elementRareData()->childIndex(); 2413} 2414 2415void Element::setIsInCanvasSubtree(bool isInCanvasSubtree) 2416{ 2417 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree); 2418} 2419 2420bool Element::isInCanvasSubtree() const 2421{ 2422 return hasRareData() && elementRareData()->isInCanvasSubtree(); 2423} 2424 2425void Element::setIsInsideRegion(bool value) 2426{ 2427 if (value == isInsideRegion()) 2428 return; 2429 2430 ensureElementRareData()->setIsInsideRegion(value); 2431} 2432 2433bool Element::isInsideRegion() const 2434{ 2435 return hasRareData() ? elementRareData()->isInsideRegion() : false; 2436} 2437 2438AtomicString Element::computeInheritedLanguage() const 2439{ 2440 const Node* n = this; 2441 AtomicString value; 2442 // The language property is inherited, so we iterate over the parents to find the first language. 2443 do { 2444 if (n->isElementNode()) { 2445 if (const ElementData* elementData = toElement(n)->elementData()) { 2446 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7 2447 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr)) 2448 value = attribute->value(); 2449 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr)) 2450 value = attribute->value(); 2451 } 2452 } else if (n->isDocumentNode()) { 2453 // checking the MIME content-language 2454 value = toDocument(n)->contentLanguage(); 2455 } 2456 2457 n = n->parentNode(); 2458 } while (n && value.isNull()); 2459 2460 return value; 2461} 2462 2463Locale& Element::locale() const 2464{ 2465 return document()->getCachedLocale(computeInheritedLanguage()); 2466} 2467 2468void Element::cancelFocusAppearanceUpdate() 2469{ 2470 if (hasRareData()) 2471 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false); 2472 if (document()->focusedElement() == this) 2473 document()->cancelFocusAppearanceUpdate(); 2474} 2475 2476void Element::normalizeAttributes() 2477{ 2478 if (!hasAttributes()) 2479 return; 2480 for (unsigned i = 0; i < attributeCount(); ++i) { 2481 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name())) 2482 attr->normalize(); 2483 } 2484} 2485 2486void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change) 2487{ 2488 PseudoElement* existing = pseudoElement(pseudoId); 2489 if (existing) { 2490 // PseudoElement styles hang off their parent element's style so if we needed 2491 // a style recalc we should Force one on the pseudo. 2492 existing->recalcStyle(needsStyleRecalc() ? Force : change); 2493 2494 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded 2495 // is false, otherwise we could continously create and destroy PseudoElements 2496 // when RenderObject::isChildAllowed on our parent returns false for the 2497 // PseudoElement's renderer for each style recalc. 2498 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId))) 2499 setPseudoElement(pseudoId, 0); 2500 } else if (RefPtr<PseudoElement> element = createPseudoElementIfNeeded(pseudoId)) { 2501 element->attach(); 2502 setPseudoElement(pseudoId, element.release()); 2503 } 2504} 2505 2506PassRefPtr<PseudoElement> Element::createPseudoElementIfNeeded(PseudoId pseudoId) 2507{ 2508 if (!document()->styleSheetCollection()->usesBeforeAfterRules()) 2509 return 0; 2510 2511 if (!renderer() || !renderer()->canHaveGeneratedChildren()) 2512 return 0; 2513 2514 if (isPseudoElement()) 2515 return 0; 2516 2517 if (!pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId))) 2518 return 0; 2519 2520 return PseudoElement::create(this, pseudoId); 2521} 2522 2523bool Element::hasPseudoElements() const 2524{ 2525 return hasRareData() && elementRareData()->hasPseudoElements(); 2526} 2527 2528PseudoElement* Element::pseudoElement(PseudoId pseudoId) const 2529{ 2530 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0; 2531} 2532 2533void Element::setPseudoElement(PseudoId pseudoId, PassRefPtr<PseudoElement> element) 2534{ 2535 ensureElementRareData()->setPseudoElement(pseudoId, element); 2536 resetNeedsShadowTreeWalker(); 2537} 2538 2539RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const 2540{ 2541 if (PseudoElement* element = pseudoElement(pseudoId)) 2542 return element->renderer(); 2543 return 0; 2544} 2545 2546// ElementTraversal API 2547Element* Element::firstElementChild() const 2548{ 2549 return ElementTraversal::firstWithin(this); 2550} 2551 2552Element* Element::lastElementChild() const 2553{ 2554 Node* n = lastChild(); 2555 while (n && !n->isElementNode()) 2556 n = n->previousSibling(); 2557 return toElement(n); 2558} 2559 2560unsigned Element::childElementCount() const 2561{ 2562 unsigned count = 0; 2563 Node* n = firstChild(); 2564 while (n) { 2565 count += n->isElementNode(); 2566 n = n->nextSibling(); 2567 } 2568 return count; 2569} 2570 2571bool Element::matchesReadOnlyPseudoClass() const 2572{ 2573 return false; 2574} 2575 2576bool Element::matchesReadWritePseudoClass() const 2577{ 2578 return false; 2579} 2580 2581bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec) 2582{ 2583 if (selector.isEmpty()) { 2584 ec = SYNTAX_ERR; 2585 return false; 2586 } 2587 2588 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec); 2589 if (!selectorQuery) 2590 return false; 2591 return selectorQuery->matches(this); 2592} 2593 2594bool Element::shouldAppearIndeterminate() const 2595{ 2596 return false; 2597} 2598 2599DOMTokenList* Element::classList() 2600{ 2601 ElementRareData* data = ensureElementRareData(); 2602 if (!data->classList()) 2603 data->setClassList(ClassList::create(this)); 2604 return data->classList(); 2605} 2606 2607DOMStringMap* Element::dataset() 2608{ 2609 ElementRareData* data = ensureElementRareData(); 2610 if (!data->dataset()) 2611 data->setDataset(DatasetDOMStringMap::create(this)); 2612 return data->dataset(); 2613} 2614 2615KURL Element::getURLAttribute(const QualifiedName& name) const 2616{ 2617#if !ASSERT_DISABLED 2618 if (elementData()) { 2619 if (const Attribute* attribute = getAttributeItem(name)) 2620 ASSERT(isURLAttribute(*attribute)); 2621 } 2622#endif 2623 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name))); 2624} 2625 2626KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const 2627{ 2628#if !ASSERT_DISABLED 2629 if (elementData()) { 2630 if (const Attribute* attribute = getAttributeItem(name)) 2631 ASSERT(isURLAttribute(*attribute)); 2632 } 2633#endif 2634 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name)); 2635 if (value.isEmpty()) 2636 return KURL(); 2637 return document()->completeURL(value); 2638} 2639 2640int Element::getIntegralAttribute(const QualifiedName& attributeName) const 2641{ 2642 return getAttribute(attributeName).string().toInt(); 2643} 2644 2645void Element::setIntegralAttribute(const QualifiedName& attributeName, int value) 2646{ 2647 // FIXME: Need an AtomicString version of String::number. 2648 setAttribute(attributeName, String::number(value)); 2649} 2650 2651unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const 2652{ 2653 return getAttribute(attributeName).string().toUInt(); 2654} 2655 2656void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value) 2657{ 2658 // FIXME: Need an AtomicString version of String::number. 2659 setAttribute(attributeName, String::number(value)); 2660} 2661 2662#if ENABLE(SVG) 2663bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const 2664{ 2665 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments. 2666 if (childContext.node()->isSVGElement()) 2667 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement(); 2668 2669 return ContainerNode::childShouldCreateRenderer(childContext); 2670} 2671#endif 2672 2673#if ENABLE(FULLSCREEN_API) 2674void Element::webkitRequestFullscreen() 2675{ 2676 document()->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, Document::EnforceIFrameAllowFullScreenRequirement); 2677} 2678 2679void Element::webkitRequestFullScreen(unsigned short flags) 2680{ 2681 document()->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), Document::EnforceIFrameAllowFullScreenRequirement); 2682} 2683 2684bool Element::containsFullScreenElement() const 2685{ 2686 return hasRareData() && elementRareData()->containsFullScreenElement(); 2687} 2688 2689void Element::setContainsFullScreenElement(bool flag) 2690{ 2691 ensureElementRareData()->setContainsFullScreenElement(flag); 2692 setNeedsStyleRecalc(SyntheticStyleChange); 2693} 2694 2695static Element* parentCrossingFrameBoundaries(Element* element) 2696{ 2697 ASSERT(element); 2698 return element->parentElement() ? element->parentElement() : element->document()->ownerElement(); 2699} 2700 2701void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag) 2702{ 2703 Element* element = this; 2704 while ((element = parentCrossingFrameBoundaries(element))) 2705 element->setContainsFullScreenElement(flag); 2706} 2707#endif 2708 2709#if ENABLE(DIALOG_ELEMENT) 2710bool Element::isInTopLayer() const 2711{ 2712 return hasRareData() && elementRareData()->isInTopLayer(); 2713} 2714 2715void Element::setIsInTopLayer(bool inTopLayer) 2716{ 2717 if (isInTopLayer() == inTopLayer) 2718 return; 2719 ensureElementRareData()->setIsInTopLayer(inTopLayer); 2720 2721 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its 2722 // top layer position, or in its usual place if not in the top layer. 2723 reattachIfAttached(); 2724} 2725#endif 2726 2727#if ENABLE(POINTER_LOCK) 2728void Element::webkitRequestPointerLock() 2729{ 2730 if (document()->page()) 2731 document()->page()->pointerLockController()->requestPointerLock(this); 2732} 2733#endif 2734 2735SpellcheckAttributeState Element::spellcheckAttributeState() const 2736{ 2737 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr); 2738 if (value == nullAtom) 2739 return SpellcheckAttributeDefault; 2740 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, "")) 2741 return SpellcheckAttributeTrue; 2742 if (equalIgnoringCase(value, "false")) 2743 return SpellcheckAttributeFalse; 2744 2745 return SpellcheckAttributeDefault; 2746} 2747 2748bool Element::isSpellCheckingEnabled() const 2749{ 2750 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) { 2751 switch (element->spellcheckAttributeState()) { 2752 case SpellcheckAttributeTrue: 2753 return true; 2754 case SpellcheckAttributeFalse: 2755 return false; 2756 case SpellcheckAttributeDefault: 2757 break; 2758 } 2759 } 2760 2761 return true; 2762} 2763 2764RenderRegion* Element::renderRegion() const 2765{ 2766 if (renderer() && renderer()->isRenderRegion()) 2767 return toRenderRegion(renderer()); 2768 2769 return 0; 2770} 2771 2772#if ENABLE(CSS_REGIONS) 2773 2774bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const 2775{ 2776 ASSERT(styleToUse); 2777 2778#if ENABLE(FULLSCREEN_API) 2779 if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this) 2780 return false; 2781#endif 2782 2783 if (isInShadowTree()) 2784 return false; 2785 2786 if (styleToUse->flowThread().isEmpty()) 2787 return false; 2788 2789 return !isRegisteredWithNamedFlow(); 2790} 2791 2792const AtomicString& Element::webkitRegionOverset() const 2793{ 2794 document()->updateLayoutIgnorePendingStylesheets(); 2795 2796 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral)); 2797 if (!document()->cssRegionsEnabled() || !renderRegion()) 2798 return undefinedState; 2799 2800 switch (renderRegion()->regionState()) { 2801 case RenderRegion::RegionFit: { 2802 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral)); 2803 return fitState; 2804 } 2805 case RenderRegion::RegionEmpty: { 2806 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral)); 2807 return emptyState; 2808 } 2809 case RenderRegion::RegionOverset: { 2810 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral)); 2811 return overflowState; 2812 } 2813 case RenderRegion::RegionUndefined: 2814 return undefinedState; 2815 } 2816 2817 ASSERT_NOT_REACHED(); 2818 return undefinedState; 2819} 2820 2821Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const 2822{ 2823 document()->updateLayoutIgnorePendingStylesheets(); 2824 2825 Vector<RefPtr<Range> > rangeObjects; 2826 if (document()->cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) { 2827 RenderRegion* region = toRenderRegion(renderer()); 2828 if (region->isValid()) 2829 region->getRanges(rangeObjects); 2830 } 2831 2832 return rangeObjects; 2833} 2834 2835#endif 2836 2837#ifndef NDEBUG 2838bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const 2839{ 2840 if (name == HTMLNames::styleAttr) 2841 return false; 2842 2843#if ENABLE(SVG) 2844 if (isSVGElement()) 2845 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name); 2846#endif 2847 2848 return true; 2849} 2850#endif 2851 2852#ifdef DUMP_NODE_STATISTICS 2853bool Element::hasNamedNodeMap() const 2854{ 2855 return hasRareData() && elementRareData()->attributeMap(); 2856} 2857#endif 2858 2859inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName) 2860{ 2861 if (!isInTreeScope()) 2862 return; 2863 2864 if (oldName == newName) 2865 return; 2866 2867 updateNameForTreeScope(treeScope(), oldName, newName); 2868 2869 if (!inDocument()) 2870 return; 2871 Document* htmlDocument = document(); 2872 if (!htmlDocument->isHTMLDocument()) 2873 return; 2874 updateNameForDocument(toHTMLDocument(htmlDocument), oldName, newName); 2875} 2876 2877void Element::updateNameForTreeScope(TreeScope* scope, const AtomicString& oldName, const AtomicString& newName) 2878{ 2879 ASSERT(isInTreeScope()); 2880 ASSERT(oldName != newName); 2881 2882 if (!oldName.isEmpty()) 2883 scope->removeElementByName(oldName, this); 2884 if (!newName.isEmpty()) 2885 scope->addElementByName(newName, this); 2886} 2887 2888void Element::updateNameForDocument(HTMLDocument* document, const AtomicString& oldName, const AtomicString& newName) 2889{ 2890 ASSERT(inDocument()); 2891 ASSERT(oldName != newName); 2892 2893 if (WindowNameCollection::nodeMatchesIfNameAttributeMatch(this)) { 2894 const AtomicString& id = WindowNameCollection::nodeMatchesIfIdAttributeMatch(this) ? getIdAttribute() : nullAtom; 2895 if (!oldName.isEmpty() && oldName != id) 2896 document->windowNamedItemMap().remove(oldName.impl(), this); 2897 if (!newName.isEmpty() && newName != id) 2898 document->windowNamedItemMap().add(newName.impl(), this, treeScope()); 2899 } 2900 2901 if (DocumentNameCollection::nodeMatchesIfNameAttributeMatch(this)) { 2902 const AtomicString& id = DocumentNameCollection::nodeMatchesIfIdAttributeMatch(this) ? getIdAttribute() : nullAtom; 2903 if (!oldName.isEmpty() && oldName != id) 2904 document->documentNamedItemMap().remove(oldName.impl(), this); 2905 if (!newName.isEmpty() && newName != id) 2906 document->documentNamedItemMap().add(newName.impl(), this, treeScope()); 2907 } 2908} 2909 2910inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId) 2911{ 2912 if (!isInTreeScope()) 2913 return; 2914 2915 if (oldId == newId) 2916 return; 2917 2918 updateIdForTreeScope(treeScope(), oldId, newId); 2919 2920 if (!inDocument()) 2921 return; 2922 Document* htmlDocument = document(); 2923 if (!htmlDocument->isHTMLDocument()) 2924 return; 2925 updateIdForDocument(toHTMLDocument(htmlDocument), oldId, newId, UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute); 2926} 2927 2928void Element::updateIdForTreeScope(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId) 2929{ 2930 ASSERT(isInTreeScope()); 2931 ASSERT(oldId != newId); 2932 2933 if (!oldId.isEmpty()) 2934 scope->removeElementById(oldId, this); 2935 if (!newId.isEmpty()) 2936 scope->addElementById(newId, this); 2937} 2938 2939void Element::updateIdForDocument(HTMLDocument* document, const AtomicString& oldId, const AtomicString& newId, HTMLDocumentNamedItemMapsUpdatingCondition condition) 2940{ 2941 ASSERT(inDocument()); 2942 ASSERT(oldId != newId); 2943 2944 if (WindowNameCollection::nodeMatchesIfIdAttributeMatch(this)) { 2945 const AtomicString& name = condition == UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute && WindowNameCollection::nodeMatchesIfNameAttributeMatch(this) ? getNameAttribute() : nullAtom; 2946 if (!oldId.isEmpty() && oldId != name) 2947 document->windowNamedItemMap().remove(oldId.impl(), this); 2948 if (!newId.isEmpty() && newId != name) 2949 document->windowNamedItemMap().add(newId.impl(), this, treeScope()); 2950 } 2951 2952 if (DocumentNameCollection::nodeMatchesIfIdAttributeMatch(this)) { 2953 const AtomicString& name = condition == UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute && DocumentNameCollection::nodeMatchesIfNameAttributeMatch(this) ? getNameAttribute() : nullAtom; 2954 if (!oldId.isEmpty() && oldId != name) 2955 document->documentNamedItemMap().remove(oldId.impl(), this); 2956 if (!newId.isEmpty() && newId != name) 2957 document->documentNamedItemMap().add(newId.impl(), this, treeScope()); 2958 } 2959} 2960 2961void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue) 2962{ 2963 ASSERT(hasTagName(labelTag)); 2964 2965 if (!inDocument()) 2966 return; 2967 2968 if (oldForAttributeValue == newForAttributeValue) 2969 return; 2970 2971 if (!oldForAttributeValue.isEmpty()) 2972 scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this)); 2973 if (!newForAttributeValue.isEmpty()) 2974 scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this)); 2975} 2976 2977void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue) 2978{ 2979 if (isIdAttributeName(name)) 2980 updateId(oldValue, newValue); 2981 else if (name == HTMLNames::nameAttr) 2982 updateName(oldValue, newValue); 2983 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) { 2984 TreeScope* scope = treeScope(); 2985 if (scope->shouldCacheLabelsByForAttribute()) 2986 updateLabel(scope, oldValue, newValue); 2987 } 2988 2989 if (oldValue != newValue) { 2990 if (attached() && document()->styleResolverIfExists() && document()->styleResolverIfExists()->hasSelectorForAttribute(name.localName())) 2991 setNeedsStyleRecalc(); 2992 } 2993 2994 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name)) 2995 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue)); 2996 2997#if ENABLE(INSPECTOR) 2998 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue); 2999#endif 3000} 3001 3002void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value) 3003{ 3004 attributeChanged(name, value); 3005 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value); 3006 dispatchSubtreeModifiedEvent(); 3007} 3008 3009void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value) 3010{ 3011 attributeChanged(name, value); 3012 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value); 3013 // Do not dispatch a DOMSubtreeModified event here; see bug 81141. 3014} 3015 3016void Element::didRemoveAttribute(const QualifiedName& name) 3017{ 3018 attributeChanged(name, nullAtom); 3019 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName()); 3020 dispatchSubtreeModifiedEvent(); 3021} 3022 3023PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type) 3024{ 3025 if (HTMLCollection* collection = cachedHTMLCollection(type)) 3026 return collection; 3027 3028 RefPtr<HTMLCollection> collection; 3029 if (type == TableRows) { 3030 ASSERT(hasTagName(tableTag)); 3031 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type); 3032 } else if (type == SelectOptions) { 3033 ASSERT(hasTagName(selectTag)); 3034 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type); 3035 } else if (type == FormControls) { 3036 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag)); 3037 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type); 3038#if ENABLE(MICRODATA) 3039 } else if (type == ItemProperties) { 3040 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLPropertiesCollection>(this, type); 3041#endif 3042 } 3043 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type); 3044} 3045 3046HTMLCollection* Element::cachedHTMLCollection(CollectionType type) 3047{ 3048 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0; 3049} 3050 3051IntSize Element::savedLayerScrollOffset() const 3052{ 3053 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize(); 3054} 3055 3056void Element::setSavedLayerScrollOffset(const IntSize& size) 3057{ 3058 if (size.isZero() && !hasRareData()) 3059 return; 3060 ensureElementRareData()->setSavedLayerScrollOffset(size); 3061} 3062 3063PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name) 3064{ 3065 if (AttrNodeList* attrNodeList = attrNodeListForElement(this)) 3066 return findAttrNodeInList(attrNodeList, name); 3067 return 0; 3068} 3069 3070PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name) 3071{ 3072 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this); 3073 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name); 3074 if (!attrNode) { 3075 attrNode = Attr::create(this, name); 3076 treeScope()->adoptIfNeeded(attrNode.get()); 3077 attrNodeList->append(attrNode); 3078 } 3079 return attrNode.release(); 3080} 3081 3082void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value) 3083{ 3084 ASSERT(hasSyntheticAttrChildNodes()); 3085 attrNode->detachFromElementWithValue(value); 3086 3087 AttrNodeList* attrNodeList = attrNodeListForElement(this); 3088 for (unsigned i = 0; i < attrNodeList->size(); ++i) { 3089 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) { 3090 attrNodeList->remove(i); 3091 if (attrNodeList->isEmpty()) 3092 removeAttrNodeListForElement(this); 3093 return; 3094 } 3095 } 3096 ASSERT_NOT_REACHED(); 3097} 3098 3099void Element::detachAllAttrNodesFromElement() 3100{ 3101 AttrNodeList* attrNodeList = attrNodeListForElement(this); 3102 ASSERT(attrNodeList); 3103 3104 for (unsigned i = 0; i < attributeCount(); ++i) { 3105 const Attribute* attribute = attributeItem(i); 3106 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name())) 3107 attrNode->detachFromElementWithValue(attribute->value()); 3108 } 3109 3110 removeAttrNodeListForElement(this); 3111} 3112 3113bool Element::willRecalcStyle(StyleChange) 3114{ 3115 ASSERT(hasCustomStyleCallbacks()); 3116 return true; 3117} 3118 3119void Element::didRecalcStyle(StyleChange) 3120{ 3121 ASSERT(hasCustomStyleCallbacks()); 3122} 3123 3124 3125PassRefPtr<RenderStyle> Element::customStyleForRenderer() 3126{ 3127 ASSERT(hasCustomStyleCallbacks()); 3128 return 0; 3129} 3130 3131void Element::cloneAttributesFromElement(const Element& other) 3132{ 3133 if (hasSyntheticAttrChildNodes()) 3134 detachAllAttrNodesFromElement(); 3135 3136 other.synchronizeAllAttributes(); 3137 if (!other.m_elementData) { 3138 m_elementData.clear(); 3139 return; 3140 } 3141 3142 // We can't update window and document's named item maps since the presence of image and object elements depend on other attributes and children. 3143 // Fortunately, those named item maps are only updated when this element is in the document, which should never be the case. 3144 ASSERT(!inDocument()); 3145 3146 const AtomicString& oldID = getIdAttribute(); 3147 const AtomicString& newID = other.getIdAttribute(); 3148 3149 if (!oldID.isNull() || !newID.isNull()) 3150 updateId(oldID, newID); 3151 3152 const AtomicString& oldName = getNameAttribute(); 3153 const AtomicString& newName = other.getNameAttribute(); 3154 3155 if (!oldName.isNull() || !newName.isNull()) 3156 updateName(oldName, newName); 3157 3158 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements. 3159 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes. 3160 if (other.m_elementData->isUnique() 3161 && !other.m_elementData->presentationAttributeStyle() 3162 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper())) 3163 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy(); 3164 3165 if (!other.m_elementData->isUnique()) 3166 m_elementData = other.m_elementData; 3167 else 3168 m_elementData = other.m_elementData->makeUniqueCopy(); 3169 3170 for (unsigned i = 0; i < m_elementData->length(); ++i) { 3171 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i); 3172 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning); 3173 } 3174} 3175 3176void Element::cloneDataFromElement(const Element& other) 3177{ 3178 cloneAttributesFromElement(other); 3179 copyNonAttributePropertiesFromElement(other); 3180} 3181 3182void Element::createUniqueElementData() 3183{ 3184 if (!m_elementData) 3185 m_elementData = UniqueElementData::create(); 3186 else { 3187 ASSERT(!m_elementData->isUnique()); 3188 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy(); 3189 } 3190} 3191 3192#if ENABLE(SVG) 3193bool Element::hasPendingResources() const 3194{ 3195 return hasRareData() && elementRareData()->hasPendingResources(); 3196} 3197 3198void Element::setHasPendingResources() 3199{ 3200 ensureElementRareData()->setHasPendingResources(true); 3201} 3202 3203void Element::clearHasPendingResources() 3204{ 3205 ensureElementRareData()->setHasPendingResources(false); 3206} 3207#endif 3208 3209void ElementData::deref() 3210{ 3211 if (!derefBase()) 3212 return; 3213 3214 if (m_isUnique) 3215 delete static_cast<UniqueElementData*>(this); 3216 else 3217 delete static_cast<ShareableElementData*>(this); 3218} 3219 3220ElementData::ElementData() 3221 : m_isUnique(true) 3222 , m_arraySize(0) 3223 , m_hasNameAttribute(false) 3224 , m_presentationAttributeStyleIsDirty(false) 3225 , m_styleAttributeIsDirty(false) 3226#if ENABLE(SVG) 3227 , m_animatedSVGAttributesAreDirty(false) 3228#endif 3229{ 3230} 3231 3232ElementData::ElementData(unsigned arraySize) 3233 : m_isUnique(false) 3234 , m_arraySize(arraySize) 3235 , m_hasNameAttribute(false) 3236 , m_presentationAttributeStyleIsDirty(false) 3237 , m_styleAttributeIsDirty(false) 3238#if ENABLE(SVG) 3239 , m_animatedSVGAttributesAreDirty(false) 3240#endif 3241{ 3242} 3243 3244struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> { 3245 unsigned bitfield; 3246 void* refPtrs[3]; 3247}; 3248 3249COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small); 3250 3251static size_t sizeForShareableElementDataWithAttributeCount(unsigned count) 3252{ 3253 return sizeof(ShareableElementData) + sizeof(Attribute) * count; 3254} 3255 3256PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes) 3257{ 3258 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size())); 3259 return adoptRef(new (NotNull, slot) ShareableElementData(attributes)); 3260} 3261 3262PassRefPtr<UniqueElementData> UniqueElementData::create() 3263{ 3264 return adoptRef(new UniqueElementData); 3265} 3266 3267ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes) 3268 : ElementData(attributes.size()) 3269{ 3270 for (unsigned i = 0; i < m_arraySize; ++i) 3271 new (NotNull, &m_attributeArray[i]) Attribute(attributes[i]); 3272} 3273 3274ShareableElementData::~ShareableElementData() 3275{ 3276 for (unsigned i = 0; i < m_arraySize; ++i) 3277 m_attributeArray[i].~Attribute(); 3278} 3279 3280ShareableElementData::ShareableElementData(const UniqueElementData& other) 3281 : ElementData(other, false) 3282{ 3283 ASSERT(!other.m_presentationAttributeStyle); 3284 3285 if (other.m_inlineStyle) { 3286 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper()); 3287 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded(); 3288 } 3289 3290 for (unsigned i = 0; i < m_arraySize; ++i) 3291 new (NotNull, &m_attributeArray[i]) Attribute(other.m_attributeVector.at(i)); 3292} 3293 3294ElementData::ElementData(const ElementData& other, bool isUnique) 3295 : m_isUnique(isUnique) 3296 , m_arraySize(isUnique ? 0 : other.length()) 3297 , m_hasNameAttribute(other.m_hasNameAttribute) 3298 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty) 3299 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty) 3300#if ENABLE(SVG) 3301 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty) 3302#endif 3303 , m_classNames(other.m_classNames) 3304 , m_idForStyleResolution(other.m_idForStyleResolution) 3305{ 3306 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here. 3307} 3308 3309UniqueElementData::UniqueElementData() 3310{ 3311} 3312 3313UniqueElementData::UniqueElementData(const UniqueElementData& other) 3314 : ElementData(other, true) 3315 , m_presentationAttributeStyle(other.m_presentationAttributeStyle) 3316 , m_attributeVector(other.m_attributeVector) 3317{ 3318 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0; 3319} 3320 3321UniqueElementData::UniqueElementData(const ShareableElementData& other) 3322 : ElementData(other, true) 3323{ 3324 // An ShareableElementData should never have a mutable inline StylePropertySet attached. 3325 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable()); 3326 m_inlineStyle = other.m_inlineStyle; 3327 3328 m_attributeVector.reserveCapacity(other.length()); 3329 for (unsigned i = 0; i < other.length(); ++i) 3330 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]); 3331} 3332 3333PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const 3334{ 3335 if (isUnique()) 3336 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this))); 3337 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this))); 3338} 3339 3340PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const 3341{ 3342 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size())); 3343 return adoptRef(new (NotNull, slot) ShareableElementData(*this)); 3344} 3345 3346void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value) 3347{ 3348 m_attributeVector.append(Attribute(attributeName, value)); 3349} 3350 3351void UniqueElementData::removeAttribute(unsigned index) 3352{ 3353 ASSERT_WITH_SECURITY_IMPLICATION(index < length()); 3354 m_attributeVector.remove(index); 3355} 3356 3357bool ElementData::isEquivalent(const ElementData* other) const 3358{ 3359 if (!other) 3360 return isEmpty(); 3361 3362 unsigned len = length(); 3363 if (len != other->length()) 3364 return false; 3365 3366 for (unsigned i = 0; i < len; i++) { 3367 const Attribute* attribute = attributeItem(i); 3368 const Attribute* otherAttr = other->getAttributeItem(attribute->name()); 3369 if (!otherAttr || attribute->value() != otherAttr->value()) 3370 return false; 3371 } 3372 3373 return true; 3374} 3375 3376unsigned ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const 3377{ 3378 // Continue to checking case-insensitively and/or full namespaced names if necessary: 3379 for (unsigned i = 0; i < length(); ++i) { 3380 const Attribute* attribute = attributeItem(i); 3381 if (!attribute->name().hasPrefix()) { 3382 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName())) 3383 return i; 3384 } else { 3385 // FIXME: Would be faster to do this comparison without calling toString, which 3386 // generates a temporary string by concatenation. But this branch is only reached 3387 // if the attribute name has a prefix, which is rare in HTML. 3388 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase)) 3389 return i; 3390 } 3391 } 3392 return attributeNotFound; 3393} 3394 3395unsigned ElementData::getAttributeItemIndexForAttributeNode(const Attr* attr) const 3396{ 3397 ASSERT(attr); 3398 const Attribute* attributes = attributeBase(); 3399 unsigned count = length(); 3400 for (unsigned i = 0; i < count; ++i) { 3401 if (attributes[i].name() == attr->qualifiedName()) 3402 return i; 3403 } 3404 return attributeNotFound; 3405} 3406 3407Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name) 3408{ 3409 unsigned count = length(); 3410 for (unsigned i = 0; i < count; ++i) { 3411 if (m_attributeVector.at(i).name().matches(name)) 3412 return &m_attributeVector.at(i); 3413 } 3414 return 0; 3415} 3416 3417Attribute* UniqueElementData::attributeItem(unsigned index) 3418{ 3419 ASSERT_WITH_SECURITY_IMPLICATION(index < length()); 3420 return &m_attributeVector.at(index); 3421} 3422 3423} // namespace WebCore 3424