• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2005, 2006, 2007, 2008, 2009 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 "CSSStyleSelector.h"
31 #include "CString.h"
32 #include "Document.h"
33 #include "Editor.h"
34 #include "ElementRareData.h"
35 #include "ExceptionCode.h"
36 #include "FocusController.h"
37 #include "Frame.h"
38 #include "FrameView.h"
39 #include "HTMLElement.h"
40 #include "HTMLNames.h"
41 #include "NamedAttrMap.h"
42 #include "NodeList.h"
43 #include "NodeRenderStyle.h"
44 #include "Page.h"
45 #include "PlatformString.h"
46 #include "RenderBlock.h"
47 #include "SelectionController.h"
48 #include "TextIterator.h"
49 #include "XMLNames.h"
50 
51 namespace WebCore {
52 
53 using namespace HTMLNames;
54 using namespace XMLNames;
55 
Element(const QualifiedName & tagName,Document * doc)56 Element::Element(const QualifiedName& tagName, Document* doc)
57     : ContainerNode(doc, true)
58     , m_tagName(tagName)
59 {
60 }
61 
~Element()62 Element::~Element()
63 {
64     if (namedAttrMap)
65         namedAttrMap->detachFromElement();
66 }
67 
rareData() const68 inline ElementRareData* Element::rareData() const
69 {
70     ASSERT(hasRareData());
71     return static_cast<ElementRareData*>(NodeRareData::rareDataFromMap(this));
72 }
73 
ensureRareData()74 inline ElementRareData* Element::ensureRareData()
75 {
76     return static_cast<ElementRareData*>(Node::ensureRareData());
77 }
78 
createRareData()79 NodeRareData* Element::createRareData()
80 {
81     return new ElementRareData;
82 }
83 
cloneNode(bool deep)84 PassRefPtr<Node> Element::cloneNode(bool deep)
85 {
86     ExceptionCode ec = 0;
87     RefPtr<Element> clone = document()->createElementNS(namespaceURI(), nodeName(), ec);
88     ASSERT(!ec);
89 
90     // clone attributes
91     if (namedAttrMap)
92         clone->attributes()->setAttributes(*namedAttrMap);
93 
94     clone->copyNonAttributeProperties(this);
95 
96     if (deep)
97         cloneChildNodes(clone.get());
98 
99     return clone.release();
100 }
101 
cloneElement()102 PassRefPtr<Element> Element::cloneElement()
103 {
104     return static_pointer_cast<Element>(cloneNode(false));
105 }
106 
removeAttribute(const QualifiedName & name,ExceptionCode & ec)107 void Element::removeAttribute(const QualifiedName& name, ExceptionCode& ec)
108 {
109     if (namedAttrMap) {
110         namedAttrMap->removeNamedItem(name, ec);
111         if (ec == NOT_FOUND_ERR)
112             ec = 0;
113     }
114 }
115 
setAttribute(const QualifiedName & name,const AtomicString & value)116 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
117 {
118     ExceptionCode ec;
119     setAttribute(name, value, ec);
120 }
121 
setBooleanAttribute(const QualifiedName & name,bool b)122 void Element::setBooleanAttribute(const QualifiedName& name, bool b)
123 {
124     if (b)
125         setAttribute(name, name.localName());
126     else {
127         ExceptionCode ex;
128         removeAttribute(name, ex);
129     }
130 }
131 
132 // Virtual function, defined in base class.
attributes() const133 NamedAttrMap* Element::attributes() const
134 {
135     return attributes(false);
136 }
137 
attributes(bool readonly) const138 NamedAttrMap* Element::attributes(bool readonly) const
139 {
140     if (!m_isStyleAttributeValid)
141         updateStyleAttribute();
142 
143 #if ENABLE(SVG)
144     if (!m_areSVGAttributesValid)
145         updateAnimatedSVGAttribute(String());
146 #endif
147 
148     if (!readonly && !namedAttrMap)
149         createAttributeMap();
150     return namedAttrMap.get();
151 }
152 
nodeType() const153 Node::NodeType Element::nodeType() const
154 {
155     return ELEMENT_NODE;
156 }
157 
getIDAttribute() const158 const AtomicString& Element::getIDAttribute() const
159 {
160     return namedAttrMap ? namedAttrMap->id() : nullAtom;
161 }
162 
hasAttribute(const QualifiedName & name) const163 bool Element::hasAttribute(const QualifiedName& name) const
164 {
165     return hasAttributeNS(name.namespaceURI(), name.localName());
166 }
167 
getAttribute(const QualifiedName & name) const168 const AtomicString& Element::getAttribute(const QualifiedName& name) const
169 {
170     if (name == styleAttr && !m_isStyleAttributeValid)
171         updateStyleAttribute();
172 
173 #if ENABLE(SVG)
174     if (!m_areSVGAttributesValid)
175         updateAnimatedSVGAttribute(name.localName());
176 #endif
177 
178     if (namedAttrMap)
179         if (Attribute* a = namedAttrMap->getAttributeItem(name))
180             return a->value();
181 
182     return nullAtom;
183 }
184 
scrollIntoView(bool alignToTop)185 void Element::scrollIntoView(bool alignToTop)
186 {
187     document()->updateLayoutIgnorePendingStylesheets();
188     IntRect bounds = getRect();
189     if (renderer()) {
190         // Align to the top / bottom and to the closest edge.
191         if (alignToTop)
192             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
193         else
194             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignBottomAlways);
195     }
196 }
197 
scrollIntoViewIfNeeded(bool centerIfNeeded)198 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
199 {
200     document()->updateLayoutIgnorePendingStylesheets();
201     IntRect bounds = getRect();
202     if (renderer()) {
203         if (centerIfNeeded)
204             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, RenderLayer::gAlignCenterIfNeeded, RenderLayer::gAlignCenterIfNeeded);
205         else
206             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignToEdgeIfNeeded);
207     }
208 }
209 
scrollByUnits(int units,ScrollGranularity granularity)210 void Element::scrollByUnits(int units, ScrollGranularity granularity)
211 {
212     document()->updateLayoutIgnorePendingStylesheets();
213     if (RenderObject *rend = renderer()) {
214         if (rend->hasOverflowClip()) {
215             ScrollDirection direction = ScrollDown;
216             if (units < 0) {
217                 direction = ScrollUp;
218                 units = -units;
219             }
220             toRenderBox(rend)->layer()->scroll(direction, granularity, units);
221         }
222     }
223 }
224 
scrollByLines(int lines)225 void Element::scrollByLines(int lines)
226 {
227     scrollByUnits(lines, ScrollByLine);
228 }
229 
scrollByPages(int pages)230 void Element::scrollByPages(int pages)
231 {
232     scrollByUnits(pages, ScrollByPage);
233 }
234 
localZoomForRenderer(RenderObject * renderer)235 static float localZoomForRenderer(RenderObject* renderer)
236 {
237     // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
238     // other out, but the alternative is that we'd have to crawl up the whole render tree every
239     // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
240     float zoomFactor = 1.0f;
241     if (renderer->style()->effectiveZoom() != 1.0f) {
242         // Need to find the nearest enclosing RenderObject that set up
243         // a differing zoom, and then we divide our result by it to eliminate the zoom.
244         RenderObject* prev = renderer;
245         for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
246             if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
247                 zoomFactor = prev->style()->zoom();
248                 break;
249             }
250             prev = curr;
251         }
252         if (prev->isRenderView())
253             zoomFactor = prev->style()->zoom();
254     }
255     return zoomFactor;
256 }
257 
adjustForLocalZoom(int value,RenderObject * renderer)258 static int adjustForLocalZoom(int value, RenderObject* renderer)
259 {
260     float zoomFactor = localZoomForRenderer(renderer);
261     if (zoomFactor == 1.0f)
262         return value;
263     return static_cast<int>(value / zoomFactor);
264 }
265 
adjustForAbsoluteZoom(int value,RenderObject * renderer)266 static int adjustForAbsoluteZoom(int value, RenderObject* renderer)
267 {
268     float zoomFactor = renderer->style()->effectiveZoom();
269     if (zoomFactor == 1.0f)
270         return value;
271     return static_cast<int>(value / zoomFactor);
272 }
273 
offsetLeft()274 int Element::offsetLeft()
275 {
276     document()->updateLayoutIgnorePendingStylesheets();
277     if (RenderBox* rend = renderBox())
278         return adjustForLocalZoom(rend->offsetLeft(), rend);
279     return 0;
280 }
281 
offsetTop()282 int Element::offsetTop()
283 {
284     document()->updateLayoutIgnorePendingStylesheets();
285     if (RenderBox* rend = renderBox())
286         return adjustForLocalZoom(rend->offsetTop(), rend);
287     return 0;
288 }
289 
offsetWidth()290 int Element::offsetWidth()
291 {
292     document()->updateLayoutIgnorePendingStylesheets();
293     if (RenderBox* rend = renderBox())
294         return adjustForAbsoluteZoom(rend->offsetWidth(), rend);
295     return 0;
296 }
297 
offsetHeight()298 int Element::offsetHeight()
299 {
300     document()->updateLayoutIgnorePendingStylesheets();
301     if (RenderBox* rend = renderBox())
302         return adjustForAbsoluteZoom(rend->offsetHeight(), rend);
303     return 0;
304 }
305 
offsetParent()306 Element* Element::offsetParent()
307 {
308     document()->updateLayoutIgnorePendingStylesheets();
309     if (RenderBox* rend = renderBox())
310         if (RenderObject* offsetParent = rend->offsetParent())
311             return static_cast<Element*>(offsetParent->element());
312     return 0;
313 }
314 
clientLeft()315 int Element::clientLeft()
316 {
317     document()->updateLayoutIgnorePendingStylesheets();
318 
319     if (RenderBox* rend = renderBox())
320         return adjustForAbsoluteZoom(rend->clientLeft(), rend);
321     return 0;
322 }
323 
clientTop()324 int Element::clientTop()
325 {
326     document()->updateLayoutIgnorePendingStylesheets();
327 
328     if (RenderBox* rend = renderBox())
329         return adjustForAbsoluteZoom(rend->clientTop(), rend);
330     return 0;
331 }
332 
clientWidth()333 int Element::clientWidth()
334 {
335     document()->updateLayoutIgnorePendingStylesheets();
336 
337     // When in strict mode, clientWidth for the document element should return the width of the containing frame.
338     // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
339     bool inCompatMode = document()->inCompatMode();
340     if ((!inCompatMode && document()->documentElement() == this) ||
341         (inCompatMode && isHTMLElement() && document()->body() == this)) {
342         if (FrameView* view = document()->view())
343             return view->layoutWidth();
344     }
345 
346 
347     if (RenderBox* rend = renderBox()) {
348         if (!rend->isRenderInline())
349             return adjustForAbsoluteZoom(rend->clientWidth(), rend);
350     }
351     return 0;
352 }
353 
clientHeight()354 int Element::clientHeight()
355 {
356     document()->updateLayoutIgnorePendingStylesheets();
357 
358     // When in strict mode, clientHeight for the document element should return the height of the containing frame.
359     // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
360     bool inCompatMode = document()->inCompatMode();
361 
362     if ((!inCompatMode && document()->documentElement() == this) ||
363         (inCompatMode && isHTMLElement() && document()->body() == this)) {
364         if (FrameView* view = document()->view())
365             return view->layoutHeight();
366     }
367 
368     if (RenderBox* rend = renderBox()) {
369         if (!rend->isRenderInline())
370             return adjustForAbsoluteZoom(rend->clientHeight(), rend);
371     }
372     return 0;
373 }
374 
scrollLeft()375 int Element::scrollLeft()
376 {
377     document()->updateLayoutIgnorePendingStylesheets();
378     if (RenderBox* rend = renderBox())
379         return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
380     return 0;
381 }
382 
scrollTop()383 int Element::scrollTop()
384 {
385     document()->updateLayoutIgnorePendingStylesheets();
386     if (RenderBox* rend = renderBox())
387         return adjustForAbsoluteZoom(rend->scrollTop(), rend);
388     return 0;
389 }
390 
setScrollLeft(int newLeft)391 void Element::setScrollLeft(int newLeft)
392 {
393     document()->updateLayoutIgnorePendingStylesheets();
394     if (RenderBox* rend = renderBox())
395         rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
396 }
397 
setScrollTop(int newTop)398 void Element::setScrollTop(int newTop)
399 {
400     document()->updateLayoutIgnorePendingStylesheets();
401     if (RenderBox* rend = renderBox())
402         rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
403 }
404 
scrollWidth()405 int Element::scrollWidth()
406 {
407     document()->updateLayoutIgnorePendingStylesheets();
408     if (RenderBox* rend = renderBox()) {
409         if (rend->hasOverflowClip() || !rend->isRenderInline())
410             return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
411     }
412     return 0;
413 }
414 
scrollHeight()415 int Element::scrollHeight()
416 {
417     document()->updateLayoutIgnorePendingStylesheets();
418     if (RenderBox* rend = renderBox()) {
419         if (rend->hasOverflowClip() || !rend->isRenderInline())
420             return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
421     }
422     return 0;
423 }
424 
shouldIgnoreAttributeCase(const Element * e)425 static inline bool shouldIgnoreAttributeCase(const Element* e)
426 {
427     return e && e->document()->isHTMLDocument() && e->isHTMLElement();
428 }
429 
getAttribute(const String & name) const430 const AtomicString& Element::getAttribute(const String& name) const
431 {
432     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
433     if (localName == styleAttr.localName() && !m_isStyleAttributeValid)
434         updateStyleAttribute();
435 
436 #if ENABLE(SVG)
437     if (!m_areSVGAttributesValid)
438         updateAnimatedSVGAttribute(name);
439 #endif
440 
441     if (namedAttrMap)
442         if (Attribute* a = namedAttrMap->getAttributeItem(name, shouldIgnoreAttributeCase(this)))
443             return a->value();
444 
445     return nullAtom;
446 }
447 
getAttributeNS(const String & namespaceURI,const String & localName) const448 const AtomicString& Element::getAttributeNS(const String& namespaceURI, const String& localName) const
449 {
450     return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
451 }
452 
setAttribute(const AtomicString & name,const AtomicString & value,ExceptionCode & ec)453 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec)
454 {
455     if (!Document::isValidName(name)) {
456         ec = INVALID_CHARACTER_ERR;
457         return;
458     }
459 
460     const AtomicString& localName = (shouldIgnoreAttributeCase(this) && !name.string().impl()->isLower()) ? AtomicString(name.string().lower()) : name;
461 
462     // allocate attributemap if necessary
463     Attribute* old = attributes(false)->getAttributeItem(localName, false);
464 
465     document()->incDOMTreeVersion();
466 
467     if (localName == idAttr.localName())
468         updateId(old ? old->value() : nullAtom, value);
469 
470     if (old && value.isNull())
471         namedAttrMap->removeAttribute(old->name());
472     else if (!old && !value.isNull())
473         namedAttrMap->addAttribute(createAttribute(QualifiedName(nullAtom, localName, nullAtom), value));
474     else if (old && !value.isNull()) {
475         old->setValue(value);
476         attributeChanged(old);
477     }
478 }
479 
setAttribute(const QualifiedName & name,const AtomicString & value,ExceptionCode &)480 void Element::setAttribute(const QualifiedName& name, const AtomicString& value, ExceptionCode&)
481 {
482     document()->incDOMTreeVersion();
483 
484     // allocate attributemap if necessary
485     Attribute* old = attributes(false)->getAttributeItem(name);
486 
487     if (name == idAttr)
488         updateId(old ? old->value() : nullAtom, value);
489 
490     if (old && value.isNull())
491         namedAttrMap->removeAttribute(name);
492     else if (!old && !value.isNull())
493         namedAttrMap->addAttribute(createAttribute(name, value));
494     else if (old) {
495         old->setValue(value);
496         attributeChanged(old);
497     }
498 }
499 
createAttribute(const QualifiedName & name,const AtomicString & value)500 PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const AtomicString& value)
501 {
502     return Attribute::create(name, value);
503 }
504 
attributeChanged(Attribute * attr,bool)505 void Element::attributeChanged(Attribute* attr, bool)
506 {
507     if (!document()->axObjectCache()->accessibilityEnabled())
508         return;
509 
510     const QualifiedName& attrName = attr->name();
511     if (attrName == aria_activedescendantAttr) {
512         // any change to aria-activedescendant attribute triggers accessibility focus change, but document focus remains intact
513         document()->axObjectCache()->handleActiveDescendantChanged(renderer());
514     } else if (attrName == roleAttr) {
515         // the role attribute can change at any time, and the AccessibilityObject must pick up these changes
516         document()->axObjectCache()->handleAriaRoleChanged(renderer());
517     }
518 }
519 
setAttributeMap(PassRefPtr<NamedAttrMap> list)520 void Element::setAttributeMap(PassRefPtr<NamedAttrMap> list)
521 {
522     document()->incDOMTreeVersion();
523 
524     // If setting the whole map changes the id attribute, we need to call updateId.
525 
526     Attribute* oldId = namedAttrMap ? namedAttrMap->getAttributeItem(idAttr) : 0;
527     Attribute* newId = list ? list->getAttributeItem(idAttr) : 0;
528 
529     if (oldId || newId)
530         updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
531 
532     if (namedAttrMap)
533         namedAttrMap->m_element = 0;
534 
535     namedAttrMap = list;
536 
537     if (namedAttrMap) {
538         namedAttrMap->m_element = this;
539         unsigned len = namedAttrMap->length();
540         for (unsigned i = 0; i < len; i++)
541             attributeChanged(namedAttrMap->m_attributes[i].get());
542         // FIXME: What about attributes that were in the old map that are not in the new map?
543     }
544 }
545 
hasAttributes() const546 bool Element::hasAttributes() const
547 {
548     if (!m_isStyleAttributeValid)
549         updateStyleAttribute();
550 
551 #if ENABLE(SVG)
552     if (!m_areSVGAttributesValid)
553         updateAnimatedSVGAttribute(String());
554 #endif
555 
556     return namedAttrMap && namedAttrMap->length() > 0;
557 }
558 
nodeName() const559 String Element::nodeName() const
560 {
561     return m_tagName.toString();
562 }
563 
nodeNamePreservingCase() const564 String Element::nodeNamePreservingCase() const
565 {
566     return m_tagName.toString();
567 }
568 
setPrefix(const AtomicString & _prefix,ExceptionCode & ec)569 void Element::setPrefix(const AtomicString &_prefix, ExceptionCode& ec)
570 {
571     ec = 0;
572     checkSetPrefix(_prefix, ec);
573     if (ec)
574         return;
575 
576     m_tagName.setPrefix(_prefix);
577 }
578 
baseURI() const579 KURL Element::baseURI() const
580 {
581     KURL base(getAttribute(baseAttr));
582     if (!base.protocol().isEmpty())
583         return base;
584 
585     Node* parent = parentNode();
586     if (!parent)
587         return base;
588 
589     const KURL& parentBase = parent->baseURI();
590     if (parentBase.isNull())
591         return base;
592 
593     return KURL(parentBase, base.string());
594 }
595 
createAttributeMap() const596 void Element::createAttributeMap() const
597 {
598     namedAttrMap = NamedAttrMap::create(const_cast<Element*>(this));
599 }
600 
isURLAttribute(Attribute *) const601 bool Element::isURLAttribute(Attribute*) const
602 {
603     return false;
604 }
605 
imageSourceAttributeName() const606 const QualifiedName& Element::imageSourceAttributeName() const
607 {
608     return srcAttr;
609 }
610 
createRenderer(RenderArena * arena,RenderStyle * style)611 RenderObject* Element::createRenderer(RenderArena* arena, RenderStyle* style)
612 {
613     if (document()->documentElement() == this && style->display() == NONE) {
614         // Ignore display: none on root elements.  Force a display of block in that case.
615         RenderBlock* result = new (arena) RenderBlock(this);
616         if (result)
617             result->setAnimatableStyle(style);
618         return result;
619     }
620     return RenderObject::createObject(this, style);
621 }
622 
623 
insertedIntoDocument()624 void Element::insertedIntoDocument()
625 {
626     // need to do superclass processing first so inDocument() is true
627     // by the time we reach updateId
628     ContainerNode::insertedIntoDocument();
629 
630     if (hasID()) {
631         if (NamedAttrMap* attrs = namedAttrMap.get()) {
632             Attribute* idItem = attrs->getAttributeItem(idAttr);
633             if (idItem && !idItem->isNull())
634                 updateId(nullAtom, idItem->value());
635         }
636     }
637 }
638 
removedFromDocument()639 void Element::removedFromDocument()
640 {
641     if (hasID()) {
642         if (NamedAttrMap* attrs = namedAttrMap.get()) {
643             Attribute* idItem = attrs->getAttributeItem(idAttr);
644             if (idItem && !idItem->isNull())
645                 updateId(idItem->value(), nullAtom);
646         }
647     }
648 
649     ContainerNode::removedFromDocument();
650 }
651 
attach()652 void Element::attach()
653 {
654     createRendererIfNeeded();
655     ContainerNode::attach();
656     if (hasRareData()) {
657         ElementRareData* data = rareData();
658         if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
659             if (isFocusable() && document()->focusedNode() == this)
660                 document()->updateFocusAppearanceSoon();
661             data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
662         }
663     }
664 }
665 
detach()666 void Element::detach()
667 {
668     cancelFocusAppearanceUpdate();
669     if (hasRareData())
670         rareData()->resetComputedStyle();
671     ContainerNode::detach();
672 }
673 
recalcStyle(StyleChange change)674 void Element::recalcStyle(StyleChange change)
675 {
676     RenderStyle* currentStyle = renderStyle();
677     bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false;
678     bool hasPositionalRules = changed() && currentStyle && currentStyle->childrenAffectedByPositionalRules();
679     bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules();
680 
681 #if ENABLE(SVG)
682     if (!hasParentStyle && isShadowNode() && isSVGElement())
683         hasParentStyle = true;
684 #endif
685 
686     if ((change > NoChange || changed())) {
687         if (hasRareData())
688             rareData()->resetComputedStyle();
689     }
690     if (hasParentStyle && (change >= Inherit || changed())) {
691         RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this);
692         StyleChange ch = diff(currentStyle, newStyle.get());
693         if (ch == Detach || !currentStyle) {
694             if (attached())
695                 detach();
696             attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
697             // attach recalulates the style for all children. No need to do it twice.
698             setChanged(NoStyleChange);
699             setHasChangedChild(false);
700             return;
701         }
702 
703         if (currentStyle) {
704             // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full
705             // style change (e.g., only inline style changed).
706             if (currentStyle->affectedByHoverRules())
707                 newStyle->setAffectedByHoverRules(true);
708             if (currentStyle->affectedByActiveRules())
709                 newStyle->setAffectedByActiveRules(true);
710             if (currentStyle->affectedByDragRules())
711                 newStyle->setAffectedByDragRules(true);
712             if (currentStyle->childrenAffectedByForwardPositionalRules())
713                 newStyle->setChildrenAffectedByForwardPositionalRules();
714             if (currentStyle->childrenAffectedByBackwardPositionalRules())
715                 newStyle->setChildrenAffectedByBackwardPositionalRules();
716             if (currentStyle->childrenAffectedByFirstChildRules())
717                 newStyle->setChildrenAffectedByFirstChildRules();
718             if (currentStyle->childrenAffectedByLastChildRules())
719                 newStyle->setChildrenAffectedByLastChildRules();
720             if (currentStyle->childrenAffectedByDirectAdjacentRules())
721                 newStyle->setChildrenAffectedByDirectAdjacentRules();
722         }
723 
724         if (ch != NoChange) {
725             setRenderStyle(newStyle);
726         } else if (changed() && (styleChangeType() != AnimationStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) {
727             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
728             // fooled into believing this style is the same.  This is only necessary if the document actually uses
729             // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of
730             // descendants.
731             if (renderer())
732                 renderer()->setStyleInternal(newStyle.get());
733             else
734                 setRenderStyle(newStyle);
735         } else if (styleChangeType() == AnimationStyleChange)
736              setRenderStyle(newStyle);
737 
738         if (change != Force) {
739             if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange)
740                 change = Force;
741             else
742                 change = ch;
743         }
744     }
745 
746     // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
747     // For now we will just worry about the common case, since it's a lot trickier to get the second case right
748     // without doing way too much re-resolution.
749     bool forceCheckOfNextElementSibling = false;
750     for (Node *n = firstChild(); n; n = n->nextSibling()) {
751         bool childRulesChanged = n->changed() && n->styleChangeType() == FullStyleChange;
752         if (forceCheckOfNextElementSibling && n->isElementNode())
753             n->setChanged();
754         if (change >= Inherit || n->isTextNode() || n->hasChangedChild() || n->changed())
755             n->recalcStyle(change);
756         if (n->isElementNode())
757             forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
758     }
759 
760     setChanged(NoStyleChange);
761     setHasChangedChild(false);
762 }
763 
childTypeAllowed(NodeType type)764 bool Element::childTypeAllowed(NodeType type)
765 {
766     switch (type) {
767         case ELEMENT_NODE:
768         case TEXT_NODE:
769         case COMMENT_NODE:
770         case PROCESSING_INSTRUCTION_NODE:
771         case CDATA_SECTION_NODE:
772         case ENTITY_REFERENCE_NODE:
773             return true;
774             break;
775         default:
776             return false;
777     }
778 }
779 
checkForSiblingStyleChanges(Element * e,RenderStyle * style,bool finishedParsingCallback,Node * beforeChange,Node * afterChange,int childCountDelta)780 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
781                                         Node* beforeChange, Node* afterChange, int childCountDelta)
782 {
783     if (!style || (e->changed() && style->childrenAffectedByPositionalRules()))
784         return;
785 
786     // :first-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
787     // In the DOM case, we only need to do something if |afterChange| is not 0.
788     // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
789     if (style->childrenAffectedByFirstChildRules() && afterChange) {
790         // Find our new first child.
791         Node* newFirstChild = 0;
792         for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
793 
794         // Find the first element node following |afterChange|
795         Node* firstElementAfterInsertion = 0;
796         for (firstElementAfterInsertion = afterChange;
797              firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
798              firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
799 
800         // This is the insert/append case.
801         if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
802             firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
803             firstElementAfterInsertion->setChanged();
804 
805         // We also have to handle node removal.
806         if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState())
807             newFirstChild->setChanged();
808     }
809 
810     // :last-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
811     // In the DOM case, we only need to do something if |afterChange| is not 0.
812     if (style->childrenAffectedByLastChildRules() && beforeChange) {
813         // Find our new last child.
814         Node* newLastChild = 0;
815         for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
816 
817         // Find the last element node going backwards from |beforeChange|
818         Node* lastElementBeforeInsertion = 0;
819         for (lastElementBeforeInsertion = beforeChange;
820              lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
821              lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
822 
823         if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
824             lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
825             lastElementBeforeInsertion->setChanged();
826 
827         // 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
828         // to match now.
829         if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState())
830             newLastChild->setChanged();
831     }
832 
833     // The + selector.  We need to invalidate the first element following the insertion point.  It is the only possible element
834     // that could be affected by this DOM change.
835     if (style->childrenAffectedByDirectAdjacentRules() && afterChange) {
836         Node* firstElementAfterInsertion = 0;
837         for (firstElementAfterInsertion = afterChange;
838              firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
839              firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
840         if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
841             firstElementAfterInsertion->setChanged();
842     }
843 
844     // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
845     // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
846     // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
847     // backward case.
848     // |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.
849     // 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
850     // here.  recalcStyle will then force a walk of the children when it sees that this has happened.
851     if ((style->childrenAffectedByForwardPositionalRules() && afterChange) ||
852         (style->childrenAffectedByBackwardPositionalRules() && beforeChange))
853         e->setChanged();
854 
855     // :empty selector.
856     if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes()))
857         e->setChanged();
858 }
859 
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)860 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
861 {
862     ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
863     if (!changedByParser)
864         checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
865 }
866 
finishParsingChildren()867 void Element::finishParsingChildren()
868 {
869     ContainerNode::finishParsingChildren();
870     m_parsingChildrenFinished = true;
871     checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
872 }
873 
dispatchAttrRemovalEvent(Attribute *)874 void Element::dispatchAttrRemovalEvent(Attribute*)
875 {
876     ASSERT(!eventDispatchForbidden());
877 #if 0
878     if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
879         return;
880     ExceptionCode ec = 0;
881     dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(),
882         attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec);
883 #endif
884 }
885 
dispatchAttrAdditionEvent(Attribute *)886 void Element::dispatchAttrAdditionEvent(Attribute*)
887 {
888     ASSERT(!eventDispatchForbidden());
889 #if 0
890     if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
891         return;
892     ExceptionCode ec = 0;
893     dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(),
894         attr->value(),document()->attrName(attr->id()), MutationEvent::ADDITION), ec);
895 #endif
896 }
897 
openTagStartToString() const898 String Element::openTagStartToString() const
899 {
900     String result = "<" + nodeName();
901 
902     NamedAttrMap *attrMap = attributes(true);
903 
904     if (attrMap) {
905         unsigned numAttrs = attrMap->length();
906         for (unsigned i = 0; i < numAttrs; i++) {
907             result += " ";
908 
909             Attribute *attribute = attrMap->attributeItem(i);
910             result += attribute->name().toString();
911             if (!attribute->value().isNull()) {
912                 result += "=\"";
913                 // FIXME: substitute entities for any instances of " or '
914                 result += attribute->value();
915                 result += "\"";
916             }
917         }
918     }
919 
920     return result;
921 }
922 
updateId(const AtomicString & oldId,const AtomicString & newId)923 void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
924 {
925     if (!inDocument())
926         return;
927 
928     if (oldId == newId)
929         return;
930 
931     Document* doc = document();
932     if (!oldId.isEmpty())
933         doc->removeElementById(oldId, this);
934     if (!newId.isEmpty())
935         doc->addElementById(newId, this);
936 }
937 
938 #ifndef NDEBUG
formatForDebugger(char * buffer,unsigned length) const939 void Element::formatForDebugger(char* buffer, unsigned length) const
940 {
941     String result;
942     String s;
943 
944     s = nodeName();
945     if (s.length() > 0) {
946         result += s;
947     }
948 
949     s = getAttribute(idAttr);
950     if (s.length() > 0) {
951         if (result.length() > 0)
952             result += "; ";
953         result += "id=";
954         result += s;
955     }
956 
957     s = getAttribute(classAttr);
958     if (s.length() > 0) {
959         if (result.length() > 0)
960             result += "; ";
961         result += "class=";
962         result += s;
963     }
964 
965     strncpy(buffer, result.utf8().data(), length - 1);
966 }
967 #endif
968 
setAttributeNode(Attr * attr,ExceptionCode & ec)969 PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec)
970 {
971     if (!attr) {
972         ec = TYPE_MISMATCH_ERR;
973         return 0;
974     }
975     return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
976 }
977 
setAttributeNodeNS(Attr * attr,ExceptionCode & ec)978 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
979 {
980     if (!attr) {
981         ec = TYPE_MISMATCH_ERR;
982         return 0;
983     }
984     return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
985 }
986 
removeAttributeNode(Attr * attr,ExceptionCode & ec)987 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
988 {
989     if (!attr) {
990         ec = TYPE_MISMATCH_ERR;
991         return 0;
992     }
993     if (attr->ownerElement() != this) {
994         ec = NOT_FOUND_ERR;
995         return 0;
996     }
997     if (document() != attr->document()) {
998         ec = WRONG_DOCUMENT_ERR;
999         return 0;
1000     }
1001 
1002     NamedAttrMap *attrs = attributes(true);
1003     if (!attrs)
1004         return 0;
1005 
1006     return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec));
1007 }
1008 
setAttributeNS(const AtomicString & namespaceURI,const AtomicString & qualifiedName,const AtomicString & value,ExceptionCode & ec)1009 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1010 {
1011     String prefix, localName;
1012     if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1013         return;
1014 
1015     QualifiedName qName(prefix, localName, namespaceURI);
1016     setAttribute(qName, value, ec);
1017 }
1018 
removeAttribute(const String & name,ExceptionCode & ec)1019 void Element::removeAttribute(const String& name, ExceptionCode& ec)
1020 {
1021     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1022 
1023     if (namedAttrMap) {
1024         namedAttrMap->removeNamedItem(localName, ec);
1025         if (ec == NOT_FOUND_ERR)
1026             ec = 0;
1027     }
1028 }
1029 
removeAttributeNS(const String & namespaceURI,const String & localName,ExceptionCode & ec)1030 void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec)
1031 {
1032     removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec);
1033 }
1034 
getAttributeNode(const String & name)1035 PassRefPtr<Attr> Element::getAttributeNode(const String& name)
1036 {
1037     NamedAttrMap* attrs = attributes(true);
1038     if (!attrs)
1039         return 0;
1040     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1041     return static_pointer_cast<Attr>(attrs->getNamedItem(localName));
1042 }
1043 
getAttributeNodeNS(const String & namespaceURI,const String & localName)1044 PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName)
1045 {
1046     NamedAttrMap* attrs = attributes(true);
1047     if (!attrs)
1048         return 0;
1049     return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI)));
1050 }
1051 
hasAttribute(const String & name) const1052 bool Element::hasAttribute(const String& name) const
1053 {
1054     NamedAttrMap* attrs = attributes(true);
1055     if (!attrs)
1056         return false;
1057 
1058     // This call to String::lower() seems to be required but
1059     // there may be a way to remove it.
1060     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1061     return attrs->getAttributeItem(localName, false);
1062 }
1063 
hasAttributeNS(const String & namespaceURI,const String & localName) const1064 bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const
1065 {
1066     NamedAttrMap* attrs = attributes(true);
1067     if (!attrs)
1068         return false;
1069     return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1070 }
1071 
style()1072 CSSStyleDeclaration *Element::style()
1073 {
1074     return 0;
1075 }
1076 
focus(bool restorePreviousSelection)1077 void Element::focus(bool restorePreviousSelection)
1078 {
1079     Document* doc = document();
1080     if (doc->focusedNode() == this)
1081         return;
1082 
1083     doc->updateLayoutIgnorePendingStylesheets();
1084 
1085     if (!supportsFocus())
1086         return;
1087 
1088     if (Page* page = doc->page())
1089         page->focusController()->setFocusedNode(this, doc->frame());
1090 
1091     if (!isFocusable()) {
1092         ensureRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1093         return;
1094     }
1095 
1096     cancelFocusAppearanceUpdate();
1097     updateFocusAppearance(restorePreviousSelection);
1098 }
1099 
updateFocusAppearance(bool)1100 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1101 {
1102     if (this == rootEditableElement()) {
1103         Frame* frame = document()->frame();
1104         if (!frame)
1105             return;
1106 
1107         // FIXME: We should restore the previous selection if there is one.
1108         Selection newSelection = hasTagName(htmlTag) || hasTagName(bodyTag) ? Selection(Position(this, 0), DOWNSTREAM) : Selection::selectionFromContentsOfNode(this);
1109 
1110         if (frame->shouldChangeSelection(newSelection)) {
1111             frame->selection()->setSelection(newSelection);
1112             frame->revealSelection();
1113         }
1114 #ifdef ANDROID_SCROLL_FIX
1115         // We handle the scrolling the screen with our navigation code,
1116         // so ignore this call to put the rectangle on screen.
1117     }
1118 #else
1119     } else if (renderer() && !renderer()->isWidget())
1120         renderer()->enclosingLayer()->scrollRectToVisible(getRect());
1121 #endif
1122 }
1123 
blur()1124 void Element::blur()
1125 {
1126     cancelFocusAppearanceUpdate();
1127 #ifdef ANDROID_IGNORE_BLUR
1128     // Since we control the focus anyway, there is no need to do blur events
1129     // unless the element has a blur event.
1130     NamedAttrMap* map = attributes();
1131     Node* blur = (map->getNamedItem(HTMLNames::onblurAttr)).get();
1132     if (!blur)
1133         return;
1134 #endif
1135     Document* doc = document();
1136     if (doc->focusedNode() == this) {
1137         if (doc->frame())
1138             doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1139         else
1140             doc->setFocusedNode(0);
1141     }
1142 }
1143 
innerText() const1144 String Element::innerText() const
1145 {
1146     // We need to update layout, since plainText uses line boxes in the render tree.
1147     document()->updateLayoutIgnorePendingStylesheets();
1148 
1149     if (!renderer())
1150         return textContent(true);
1151 
1152     return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1153 }
1154 
outerText() const1155 String Element::outerText() const
1156 {
1157     // Getting outerText is the same as getting innerText, only
1158     // setting is different. You would think this should get the plain
1159     // text for the outer range, but this is wrong, <br> for instance
1160     // would return different values for inner and outer text by such
1161     // a rule, but it doesn't in WinIE, and we want to match that.
1162     return innerText();
1163 }
1164 
title() const1165 String Element::title() const
1166 {
1167     return String();
1168 }
1169 
minimumSizeForResizing() const1170 IntSize Element::minimumSizeForResizing() const
1171 {
1172     return hasRareData() ? rareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing();
1173 }
1174 
setMinimumSizeForResizing(const IntSize & size)1175 void Element::setMinimumSizeForResizing(const IntSize& size)
1176 {
1177     if (size == defaultMinimumSizeForResizing() && !hasRareData())
1178         return;
1179     ensureRareData()->m_minimumSizeForResizing = size;
1180 }
1181 
computedStyle()1182 RenderStyle* Element::computedStyle()
1183 {
1184     if (RenderStyle* usedStyle = renderStyle())
1185         return usedStyle;
1186 
1187     if (!attached())
1188         // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
1189         // document tree and figure out when to destroy the computed style for such elements.
1190         return 0;
1191 
1192     ElementRareData* data = ensureRareData();
1193     if (!data->m_computedStyle)
1194         data->m_computedStyle = document()->styleSelector()->styleForElement(this, parent() ? parent()->computedStyle() : 0);
1195     return data->m_computedStyle.get();
1196 }
1197 
cancelFocusAppearanceUpdate()1198 void Element::cancelFocusAppearanceUpdate()
1199 {
1200     if (hasRareData())
1201         rareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1202     if (document()->focusedNode() == this)
1203         document()->cancelFocusAppearanceUpdate();
1204 }
1205 
normalizeAttributes()1206 void Element::normalizeAttributes()
1207 {
1208     // Normalize attributes.
1209     NamedAttrMap* attrs = attributes(true);
1210     if (!attrs)
1211         return;
1212     unsigned numAttrs = attrs->length();
1213     for (unsigned i = 0; i < numAttrs; i++) {
1214         if (Attr* attr = attrs->attributeItem(i)->attr())
1215             attr->normalize();
1216     }
1217 }
1218 
1219 // ElementTraversal API
firstElementChild() const1220 Element* Element::firstElementChild() const
1221 {
1222     Node* n = firstChild();
1223     while (n && !n->isElementNode())
1224         n = n->nextSibling();
1225     return static_cast<Element*>(n);
1226 }
1227 
lastElementChild() const1228 Element* Element::lastElementChild() const
1229 {
1230     Node* n = lastChild();
1231     while (n && !n->isElementNode())
1232         n = n->previousSibling();
1233     return static_cast<Element*>(n);
1234 }
1235 
previousElementSibling() const1236 Element* Element::previousElementSibling() const
1237 {
1238     Node* n = previousSibling();
1239     while (n && !n->isElementNode())
1240         n = n->previousSibling();
1241     return static_cast<Element*>(n);
1242 }
1243 
nextElementSibling() const1244 Element* Element::nextElementSibling() const
1245 {
1246     Node* n = nextSibling();
1247     while (n && !n->isElementNode())
1248         n = n->nextSibling();
1249     return static_cast<Element*>(n);
1250 }
1251 
childElementCount() const1252 unsigned Element::childElementCount() const
1253 {
1254     unsigned count = 0;
1255     Node* n = firstChild();
1256     while (n) {
1257         count += n->isElementNode();
1258         n = n->nextSibling();
1259     }
1260     return count;
1261 }
1262 
1263 }
1264