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