📄 element.cpp
字号:
/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Peter Kelly (pmk@post.com) * (C) 2001 Dirk Mueller (mueller@kde.org) * (C) 2007 David Smith (catfish.man@gmail.com) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * (C) 2007 Eric Seidel (eric@webkit.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#include "config.h"#include "Element.h"#include "AXObjectCache.h"#include "CSSStyleSelector.h"#include "CString.h"#include "ClientRect.h"#include "ClientRectList.h"#include "Document.h"#include "Editor.h"#include "ElementRareData.h"#include "ExceptionCode.h"#include "FocusController.h"#include "Frame.h"#include "FrameView.h"#include "HTMLElement.h"#include "HTMLNames.h"#include "NamedAttrMap.h"#include "NodeList.h"#include "NodeRenderStyle.h"#include "Page.h"#include "PlatformString.h"#include "RenderBlock.h"#if ENABLE(SVG)#include "SVGNames.h"#endif#include "SelectionController.h"#include "TextIterator.h"#include "XMLNames.h"namespace WebCore {using namespace HTMLNames;using namespace XMLNames; Element::Element(const QualifiedName& tagName, Document* doc) : ContainerNode(doc, true) , m_tagName(tagName){}Element::~Element(){ if (namedAttrMap) namedAttrMap->detachFromElement();}inline ElementRareData* Element::rareData() const{ ASSERT(hasRareData()); return static_cast<ElementRareData*>(NodeRareData::rareDataFromMap(this));} inline ElementRareData* Element::ensureRareData(){ return static_cast<ElementRareData*>(Node::ensureRareData());} NodeRareData* Element::createRareData(){ return new ElementRareData;} PassRefPtr<Node> Element::cloneNode(bool deep){ RefPtr<Element> clone = document()->createElement(tagQName(), false); // This will catch HTML elements in the wrong namespace that are not correctly copied. // This is a sanity check as HTML overloads some of the DOM methods. ASSERT(isHTMLElement() == clone->isHTMLElement()); // Clone attributes. if (namedAttrMap) clone->attributes()->setAttributes(*namedAttrMap); clone->copyNonAttributeProperties(this); if (deep) cloneChildNodes(clone.get()); return clone.release();}PassRefPtr<Element> Element::cloneElement(){ return static_pointer_cast<Element>(cloneNode(false));}void Element::removeAttribute(const QualifiedName& name, ExceptionCode& ec){ if (namedAttrMap) { namedAttrMap->removeNamedItem(name, ec); if (ec == NOT_FOUND_ERR) ec = 0; }}void Element::setAttribute(const QualifiedName& name, const AtomicString& value){ ExceptionCode ec; setAttribute(name, value, ec);}void Element::setBooleanAttribute(const QualifiedName& name, bool b){ if (b) setAttribute(name, name.localName()); else { ExceptionCode ex; removeAttribute(name, ex); }}// Virtual function, defined in base class.NamedAttrMap* Element::attributes() const{ return attributes(false);}NamedAttrMap* Element::attributes(bool readonly) const{ if (!m_isStyleAttributeValid) updateStyleAttribute();#if ENABLE(SVG) if (!m_areSVGAttributesValid) updateAnimatedSVGAttribute(String());#endif if (!readonly && !namedAttrMap) createAttributeMap(); return namedAttrMap.get();}Node::NodeType Element::nodeType() const{ return ELEMENT_NODE;}const AtomicString& Element::getIDAttribute() const{ return namedAttrMap ? namedAttrMap->id() : nullAtom;}bool Element::hasAttribute(const QualifiedName& name) const{ return hasAttributeNS(name.namespaceURI(), name.localName());}const AtomicString& Element::getAttribute(const QualifiedName& name) const{ if (name == styleAttr && !m_isStyleAttributeValid) updateStyleAttribute();#if ENABLE(SVG) if (!m_areSVGAttributesValid) updateAnimatedSVGAttribute(name.localName());#endif if (namedAttrMap) if (Attribute* a = namedAttrMap->getAttributeItem(name)) return a->value(); return nullAtom;}void Element::scrollIntoView(bool alignToTop) { document()->updateLayoutIgnorePendingStylesheets(); IntRect bounds = getRect(); if (renderer()) { // Align to the top / bottom and to the closest edge. if (alignToTop) renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); else renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways); }}void Element::scrollIntoViewIfNeeded(bool centerIfNeeded){ document()->updateLayoutIgnorePendingStylesheets(); IntRect bounds = getRect(); if (renderer()) { if (centerIfNeeded) renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded); else renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); }}void Element::scrollByUnits(int units, ScrollGranularity granularity){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderObject *rend = renderer()) { if (rend->hasOverflowClip()) { ScrollDirection direction = ScrollDown; if (units < 0) { direction = ScrollUp; units = -units; } toRenderBox(rend)->layer()->scroll(direction, granularity, units); } }}void Element::scrollByLines(int lines){ scrollByUnits(lines, ScrollByLine);}void Element::scrollByPages(int pages){ scrollByUnits(pages, ScrollByPage);}static float localZoomForRenderer(RenderObject* renderer){ // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each // other out, but the alternative is that we'd have to crawl up the whole render tree every // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified). float zoomFactor = 1.0f; if (renderer->style()->effectiveZoom() != 1.0f) { // Need to find the nearest enclosing RenderObject that set up // a differing zoom, and then we divide our result by it to eliminate the zoom. RenderObject* prev = renderer; for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) { if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) { zoomFactor = prev->style()->zoom(); break; } prev = curr; } if (prev->isRenderView()) zoomFactor = prev->style()->zoom(); } return zoomFactor;}static int adjustForLocalZoom(int value, RenderObject* renderer){ float zoomFactor = localZoomForRenderer(renderer); if (zoomFactor == 1.0f) return value; return static_cast<int>(value / zoomFactor);}static int adjustForAbsoluteZoom(int value, RenderObject* renderer){ float zoomFactor = renderer->style()->effectiveZoom(); if (zoomFactor == 1.0f) return value; return static_cast<int>(value / zoomFactor);}int Element::offsetLeft(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBoxModelObject* rend = renderBoxModelObject()) return adjustForLocalZoom(rend->offsetLeft(), rend); return 0;}int Element::offsetTop(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBoxModelObject* rend = renderBoxModelObject()) return adjustForLocalZoom(rend->offsetTop(), rend); return 0;}int Element::offsetWidth(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBoxModelObject* rend = renderBoxModelObject()) return adjustForAbsoluteZoom(rend->offsetWidth(), rend); return 0;}int Element::offsetHeight(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBoxModelObject* rend = renderBoxModelObject()) return adjustForAbsoluteZoom(rend->offsetHeight(), rend); return 0;}Element* Element::offsetParent(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderObject* rend = renderer()) if (RenderObject* offsetParent = rend->offsetParent()) return static_cast<Element*>(offsetParent->node()); return 0;}int Element::clientLeft(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->clientLeft(), rend); return 0;}int Element::clientTop(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->clientTop(), rend); return 0;}int Element::clientWidth(){ document()->updateLayoutIgnorePendingStylesheets(); // When in strict mode, clientWidth for the document element should return the width of the containing frame. // When in quirks mode, clientWidth for the body element should return the width of the containing frame. bool inCompatMode = document()->inCompatMode(); if ((!inCompatMode && document()->documentElement() == this) || (inCompatMode && isHTMLElement() && document()->body() == this)) { if (FrameView* view = document()->view()) return adjustForAbsoluteZoom(view->layoutWidth(), document()->renderer()); } if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->clientWidth(), rend); return 0;}int Element::clientHeight(){ document()->updateLayoutIgnorePendingStylesheets(); // When in strict mode, clientHeight for the document element should return the height of the containing frame. // When in quirks mode, clientHeight for the body element should return the height of the containing frame. bool inCompatMode = document()->inCompatMode(); if ((!inCompatMode && document()->documentElement() == this) || (inCompatMode && isHTMLElement() && document()->body() == this)) { if (FrameView* view = document()->view()) return adjustForAbsoluteZoom(view->layoutHeight(), document()->renderer()); } if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->clientHeight(), rend); return 0;}int Element::scrollLeft(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->scrollLeft(), rend); return 0;}int Element::scrollTop(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->scrollTop(), rend); return 0;}void Element::setScrollLeft(int newLeft){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));}void Element::setScrollTop(int newTop){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));}int Element::scrollWidth(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->scrollWidth(), rend); return 0;}int Element::scrollHeight(){ document()->updateLayoutIgnorePendingStylesheets(); if (RenderBox* rend = renderBox()) return adjustForAbsoluteZoom(rend->scrollHeight(), rend); return 0;}PassRefPtr<ClientRectList> Element::getClientRects() const{ document()->updateLayoutIgnorePendingStylesheets(); RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject(); if (!renderBoxModelObject) return ClientRectList::create(); // FIXME: Handle SVG elements. // FIXME: Handle table/inline-table with a caption. Vector<FloatQuad> quads; renderBoxModelObject->absoluteQuads(quads);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -