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