📄 element.cpp
字号:
if (FrameView* view = document()->view()) { IntRect visibleContentRect = view->visibleContentRect(); for (size_t i = 0; i < quads.size(); ++i) quads[i].move(-visibleContentRect.x(), -visibleContentRect.y()); } return ClientRectList::create(quads);}PassRefPtr<ClientRect> Element::getBoundingClientRect() const{ document()->updateLayoutIgnorePendingStylesheets(); RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject(); if (!renderBoxModelObject) return ClientRect::create(); Vector<FloatQuad> quads; renderBoxModelObject->absoluteQuads(quads); if (quads.isEmpty()) return ClientRect::create(); IntRect result = quads[0].enclosingBoundingBox(); for (size_t i = 1; i < quads.size(); ++i) result.unite(quads[i].enclosingBoundingBox()); if (FrameView* view = document()->view()) { IntRect visibleContentRect = view->visibleContentRect(); result.move(-visibleContentRect.x(), -visibleContentRect.y()); } return ClientRect::create(result);}static inline bool shouldIgnoreAttributeCase(const Element* e){ return e && e->document()->isHTMLDocument() && e->isHTMLElement();}const AtomicString& Element::getAttribute(const String& name) const{ String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; if (localName == styleAttr.localName() && !m_isStyleAttributeValid) updateStyleAttribute();#if ENABLE(SVG) if (!m_areSVGAttributesValid) updateAnimatedSVGAttribute(name);#endif if (namedAttrMap) if (Attribute* a = namedAttrMap->getAttributeItem(name, shouldIgnoreAttributeCase(this))) return a->value(); return nullAtom;}const AtomicString& Element::getAttributeNS(const String& namespaceURI, const String& localName) const{ return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));}void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec){ if (!Document::isValidName(name)) { ec = INVALID_CHARACTER_ERR; return; } const AtomicString& localName = (shouldIgnoreAttributeCase(this) && !name.string().impl()->isLower()) ? AtomicString(name.string().lower()) : name; // allocate attributemap if necessary Attribute* old = attributes(false)->getAttributeItem(localName, false); document()->incDOMTreeVersion(); if (localName == idAttr.localName()) updateId(old ? old->value() : nullAtom, value); if (old && value.isNull()) namedAttrMap->removeAttribute(old->name()); else if (!old && !value.isNull()) namedAttrMap->addAttribute(createAttribute(QualifiedName(nullAtom, localName, nullAtom), value)); else if (old && !value.isNull()) { old->setValue(value); attributeChanged(old); }}void Element::setAttribute(const QualifiedName& name, const AtomicString& value, ExceptionCode&){ document()->incDOMTreeVersion(); // allocate attributemap if necessary Attribute* old = attributes(false)->getAttributeItem(name); if (name == idAttr) updateId(old ? old->value() : nullAtom, value); if (old && value.isNull()) namedAttrMap->removeAttribute(name); else if (!old && !value.isNull()) namedAttrMap->addAttribute(createAttribute(name, value)); else if (old) { old->setValue(value); attributeChanged(old); }}PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const AtomicString& value){ return Attribute::create(name, value);}void Element::attributeChanged(Attribute* attr, bool){ if (!document()->axObjectCache()->accessibilityEnabled()) return; const QualifiedName& attrName = attr->name(); if (attrName == aria_activedescendantAttr) { // any change to aria-activedescendant attribute triggers accessibility focus change, but document focus remains intact document()->axObjectCache()->handleActiveDescendantChanged(renderer()); } else if (attrName == roleAttr) { // the role attribute can change at any time, and the AccessibilityObject must pick up these changes document()->axObjectCache()->handleAriaRoleChanged(renderer()); }}void Element::setAttributeMap(PassRefPtr<NamedAttrMap> list){ document()->incDOMTreeVersion(); // If setting the whole map changes the id attribute, we need to call updateId. Attribute* oldId = namedAttrMap ? namedAttrMap->getAttributeItem(idAttr) : 0; Attribute* newId = list ? list->getAttributeItem(idAttr) : 0; if (oldId || newId) updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom); if (namedAttrMap) namedAttrMap->m_element = 0; namedAttrMap = list; if (namedAttrMap) { namedAttrMap->m_element = this; unsigned len = namedAttrMap->length(); for (unsigned i = 0; i < len; i++) attributeChanged(namedAttrMap->m_attributes[i].get()); // FIXME: What about attributes that were in the old map that are not in the new map? }}bool Element::hasAttributes() const{ if (!m_isStyleAttributeValid) updateStyleAttribute();#if ENABLE(SVG) if (!m_areSVGAttributesValid) updateAnimatedSVGAttribute(String());#endif return namedAttrMap && namedAttrMap->length() > 0;}String Element::nodeName() const{ return m_tagName.toString();}String Element::nodeNamePreservingCase() const{ return m_tagName.toString();}void Element::setPrefix(const AtomicString &_prefix, ExceptionCode& ec){ ec = 0; checkSetPrefix(_prefix, ec); if (ec) return; m_tagName.setPrefix(_prefix);}KURL Element::baseURI() const{ KURL base(getAttribute(baseAttr)); if (!base.protocol().isEmpty()) return base; Node* parent = parentNode(); if (!parent) return base; const KURL& parentBase = parent->baseURI(); if (parentBase.isNull()) return base; return KURL(parentBase, base.string());}void Element::createAttributeMap() const{ namedAttrMap = NamedAttrMap::create(const_cast<Element*>(this));}bool Element::isURLAttribute(Attribute*) const{ return false;}const QualifiedName& Element::imageSourceAttributeName() const{ return srcAttr;}RenderObject* Element::createRenderer(RenderArena* arena, RenderStyle* style){ if (document()->documentElement() == this && style->display() == NONE) { // Ignore display: none on root elements. Force a display of block in that case. RenderBlock* result = new (arena) RenderBlock(this); if (result) result->setAnimatableStyle(style); return result; } return RenderObject::createObject(this, style);}void Element::insertedIntoDocument(){ // need to do superclass processing first so inDocument() is true // by the time we reach updateId ContainerNode::insertedIntoDocument(); if (hasID()) { if (NamedAttrMap* attrs = namedAttrMap.get()) { Attribute* idItem = attrs->getAttributeItem(idAttr); if (idItem && !idItem->isNull()) updateId(nullAtom, idItem->value()); } }}void Element::removedFromDocument(){ if (hasID()) { if (NamedAttrMap* attrs = namedAttrMap.get()) { Attribute* idItem = attrs->getAttributeItem(idAttr); if (idItem && !idItem->isNull()) updateId(idItem->value(), nullAtom); } } ContainerNode::removedFromDocument();}void Element::attach(){ createRendererIfNeeded(); ContainerNode::attach(); if (hasRareData()) { ElementRareData* data = rareData(); if (data->needsFocusAppearanceUpdateSoonAfterAttach()) { if (isFocusable() && document()->focusedNode() == this) document()->updateFocusAppearanceSoon(); data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false); } }}void Element::detach(){ cancelFocusAppearanceUpdate(); if (hasRareData()) rareData()->resetComputedStyle(); ContainerNode::detach();}void Element::recalcStyle(StyleChange change){ RenderStyle* currentStyle = renderStyle(); bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false; bool hasPositionalRules = changed() && currentStyle && currentStyle->childrenAffectedByPositionalRules(); bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules();#if ENABLE(SVG) if (!hasParentStyle && isShadowNode() && isSVGElement()) hasParentStyle = true;#endif if ((change > NoChange || changed())) { if (hasRareData()) rareData()->resetComputedStyle(); } if (hasParentStyle && (change >= Inherit || changed())) { RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this); StyleChange ch = diff(currentStyle, newStyle.get()); if (ch == Detach || !currentStyle) { if (attached()) detach(); attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along. // attach recalulates the style for all children. No need to do it twice. setChanged(NoStyleChange); setHasChangedChild(false); return; } if (currentStyle) { // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full // style change (e.g., only inline style changed). if (currentStyle->affectedByHoverRules()) newStyle->setAffectedByHoverRules(true); if (currentStyle->affectedByActiveRules()) newStyle->setAffectedByActiveRules(true); if (currentStyle->affectedByDragRules()) newStyle->setAffectedByDragRules(true); if (currentStyle->childrenAffectedByForwardPositionalRules()) newStyle->setChildrenAffectedByForwardPositionalRules(); if (currentStyle->childrenAffectedByBackwardPositionalRules()) newStyle->setChildrenAffectedByBackwardPositionalRules(); if (currentStyle->childrenAffectedByFirstChildRules()) newStyle->setChildrenAffectedByFirstChildRules(); if (currentStyle->childrenAffectedByLastChildRules()) newStyle->setChildrenAffectedByLastChildRules(); if (currentStyle->childrenAffectedByDirectAdjacentRules()) newStyle->setChildrenAffectedByDirectAdjacentRules(); } if (ch != NoChange) { setRenderStyle(newStyle); } else if (changed() && (styleChangeType() != AnimationStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) { // Although no change occurred, we use the new style so that the cousin style sharing code won't get // fooled into believing this style is the same. This is only necessary if the document actually uses // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of // descendants. if (renderer()) renderer()->setStyleInternal(newStyle.get()); else setRenderStyle(newStyle); } else if (styleChangeType() == AnimationStyleChange) setRenderStyle(newStyle); if (change != Force) { if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange) change = Force; else change = ch; } } // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar. // For now we will just worry about the common case, since it's a lot trickier to get the second case right // without doing way too much re-resolution. bool forceCheckOfNextElementSibling = false; for (Node *n = firstChild(); n; n = n->nextSibling()) { bool childRulesChanged = n->changed() && n->styleChangeType() == FullStyleChange; if (forceCheckOfNextElementSibling && n->isElementNode()) n->setChanged(); if (change >= Inherit || n->isTextNode() || n->hasChangedChild() || n->changed()) n->recalcStyle(change); if (n->isElementNode()) forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules; } setChanged(NoStyleChange); setHasChangedChild(false);}bool Element::childTypeAllowed(NodeType type){ switch (type) { case ELEMENT_NODE: case TEXT_NODE: case COMMENT_NODE: case PROCESSING_INSTRUCTION_NODE: case CDATA_SECTION_NODE: case ENTITY_REFERENCE_NODE: return true; break; default: return false; }}static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta){ if (!style || (e->changed() && style->childrenAffectedByPositionalRules())) return; // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time. // In the DOM case, we only need to do something if |afterChange| is not 0. // |afterChange| is 0 in the parser case, so it works out that we'll skip this block. if (style->childrenAffectedByFirstChildRules() && afterChange) { // Find our new first child. Node* newFirstChild = 0; for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {}; // Find the first element node following |afterChange| Node* firstElementAfterInsertion = 0; for (firstElementAfterInsertion = afterChange; firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; // This is the insert/append case. if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() && firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState()) firstElementAfterInsertion->setChanged(); // We also have to handle node removal. if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState()) newFirstChild->setChanged(); } // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time. // In the DOM case, we only need to do something if |afterChange| is not 0. if (style->childrenAffectedByLastChildRules() && beforeChange) { // Find our new last child. Node* newLastChild = 0; for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {}; // Find the last element node going backwards from |beforeChange| Node* lastElementBeforeInsertion = 0; for (lastElementBeforeInsertion = beforeChange; lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode(); lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {}; if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -