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