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