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