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