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