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