Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: Source/WebCore/html/HTMLOptionElement.cpp

Issue 14096013: Implement select element list box with shadow DOM. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@shadowselect
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 5 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
6 * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. 6 * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
7 * Copyright (C) 2010 Google Inc. All rights reserved. 7 * Copyright (C) 2010 Google Inc. All rights reserved.
8 * Copyright (C) 2011 Motorola Mobility, Inc. All rights reserved. 8 * Copyright (C) 2011 Motorola Mobility, Inc. All rights reserved.
9 * 9 *
10 * This library is free software; you can redistribute it and/or 10 * This library is free software; you can redistribute it and/or
(...skipping 16 matching lines...) Expand all
27 #include "config.h" 27 #include "config.h"
28 #include "HTMLOptionElement.h" 28 #include "HTMLOptionElement.h"
29 29
30 #include "Attribute.h" 30 #include "Attribute.h"
31 #include "Document.h" 31 #include "Document.h"
32 #include "ExceptionCode.h" 32 #include "ExceptionCode.h"
33 #include "HTMLDataListElement.h" 33 #include "HTMLDataListElement.h"
34 #include "HTMLNames.h" 34 #include "HTMLNames.h"
35 #include "HTMLParserIdioms.h" 35 #include "HTMLParserIdioms.h"
36 #include "HTMLSelectElement.h" 36 #include "HTMLSelectElement.h"
37 #include "NodeRenderStyle.h"
38 #include "NodeRenderingContext.h"
39 #include "NodeTraversal.h" 37 #include "NodeTraversal.h"
40 #include "RenderMenuList.h" 38 #include "RenderMenuList.h"
41 #include "RenderTheme.h" 39 #include "RenderTheme.h"
42 #include "ScriptElement.h" 40 #include "ScriptElement.h"
41 #include "ShadowRoot.h"
43 #include "StyleResolver.h" 42 #include "StyleResolver.h"
44 #include "Text.h" 43 #include "Text.h"
45 #include <wtf/StdLibExtras.h> 44 #include <wtf/StdLibExtras.h>
46 #include <wtf/Vector.h> 45 #include <wtf/Vector.h>
47 #include <wtf/text/StringBuilder.h> 46 #include <wtf/text/StringBuilder.h>
48 47
49 namespace WebCore { 48 namespace WebCore {
50 49
51 using namespace HTMLNames; 50 using namespace HTMLNames;
52 51
53 HTMLOptionElement::HTMLOptionElement(const QualifiedName& tagName, Document* doc ument) 52 HTMLOptionElement::HTMLOptionElement(const QualifiedName& tagName, Document* doc ument)
54 : HTMLElement(tagName, document) 53 : HTMLElement(tagName, document)
55 , m_disabled(false) 54 , m_disabled(false)
56 , m_isSelected(false) 55 , m_isSelected(false)
57 { 56 {
58 ASSERT(hasTagName(optionTag)); 57 ASSERT(hasTagName(optionTag));
59 setHasCustomStyleCallbacks(); 58 setHasCustomStyleCallbacks();
60 ScriptWrappable::init(this); 59 ScriptWrappable::init(this);
61 } 60 }
62 61
63 PassRefPtr<HTMLOptionElement> HTMLOptionElement::create(Document* document) 62 PassRefPtr<HTMLOptionElement> HTMLOptionElement::create(Document* document)
64 { 63 {
65 return adoptRef(new HTMLOptionElement(optionTag, document)); 64 return HTMLOptionElement::create(optionTag, document);
66 } 65 }
67 66
68 PassRefPtr<HTMLOptionElement> HTMLOptionElement::create(const QualifiedName& tag Name, Document* document) 67 PassRefPtr<HTMLOptionElement> HTMLOptionElement::create(const QualifiedName& tag Name, Document* document)
69 { 68 {
70 return adoptRef(new HTMLOptionElement(tagName, document)); 69 RefPtr<HTMLOptionElement> option = adoptRef(new HTMLOptionElement(tagName, d ocument));
70 option->ensureUserAgentShadowRoot();
yosin_UTC9 2013/05/01 01:38:21 Can we postpone creating shadow root until this op
71 return option.release();
71 } 72 }
72 73
73 PassRefPtr<HTMLOptionElement> HTMLOptionElement::createForJSConstructor(Document * document, const String& data, const String& value, 74 PassRefPtr<HTMLOptionElement> HTMLOptionElement::createForJSConstructor(Document * document, const String& data, const String& value,
74 bool defaultSelected, bool selected, ExceptionCode& ec) 75 bool defaultSelected, bool selected, ExceptionCode& ec)
75 { 76 {
76 RefPtr<HTMLOptionElement> element = adoptRef(new HTMLOptionElement(optionTag , document)); 77 RefPtr<HTMLOptionElement> element = HTMLOptionElement::create(optionTag, doc ument);
77 78
78 RefPtr<Text> text = Text::create(document, data.isNull() ? "" : data); 79 RefPtr<Text> text = Text::create(document, data.isNull() ? "" : data);
79 80
80 ec = 0; 81 ec = 0;
81 element->appendChild(text.release(), ec); 82 element->appendChild(text.release(), ec);
82 if (ec) 83 if (ec)
83 return 0; 84 return 0;
84 85
85 if (!value.isNull()) 86 if (!value.isNull())
86 element->setValue(value); 87 element->setValue(value);
87 if (defaultSelected) 88 if (defaultSelected)
88 element->setAttribute(selectedAttr, emptyAtom); 89 element->setAttribute(selectedAttr, emptyAtom);
89 element->setSelected(selected); 90 element->setSelected(selected);
90 91
91 return element.release(); 92 return element.release();
92 } 93 }
93 94
94 void HTMLOptionElement::attach()
95 {
96 HTMLElement::attach();
97 // If after attaching nothing called styleForRenderer() on this node we
98 // manually cache the value. This happens if our parent doesn't have a
99 // renderer like <optgroup> or if it doesn't allow children like <select>.
100 if (!m_style && parentNode()->renderStyle())
101 updateNonRenderStyle();
102 }
103
104 void HTMLOptionElement::detach()
105 {
106 m_style.clear();
107 HTMLElement::detach();
108 }
109
110 bool HTMLOptionElement::supportsFocus() const 95 bool HTMLOptionElement::supportsFocus() const
111 { 96 {
112 return HTMLElement::supportsFocus(); 97 return HTMLElement::supportsFocus();
113 } 98 }
114 99
115 bool HTMLOptionElement::isFocusable() const 100 bool HTMLOptionElement::isFocusable() const
116 { 101 {
117 // Option elements do not have a renderer so we check the renderStyle instea d. 102 // Option elements do not have a renderer so we check the renderStyle instea d.
118 return supportsFocus() && renderStyle() && renderStyle()->display() != NONE; 103 return supportsFocus() && renderStyle() && renderStyle()->display() != NONE;
119 } 104 }
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 renderer()->theme()->stateChanged(renderer(), EnabledState); 194 renderer()->theme()->stateChanged(renderer(), EnabledState);
210 } 195 }
211 } else if (name == selectedAttr) { 196 } else if (name == selectedAttr) {
212 // FIXME: This doesn't match what the HTML specification says. 197 // FIXME: This doesn't match what the HTML specification says.
213 // The specification implies that removing the selected attribute or 198 // The specification implies that removing the selected attribute or
214 // changing the value of a selected attribute that is already present 199 // changing the value of a selected attribute that is already present
215 // has no effect on whether the element is selected. Further, it seems 200 // has no effect on whether the element is selected. Further, it seems
216 // that we need to do more than just set m_isSelected to select in that 201 // that we need to do more than just set m_isSelected to select in that
217 // case; we'd need to do the other work from the setSelected function. 202 // case; we'd need to do the other work from the setSelected function.
218 m_isSelected = !value.isNull(); 203 m_isSelected = !value.isNull();
204 } else if (name == labelAttr) {
205 updateLabel();
219 } else 206 } else
220 HTMLElement::parseAttribute(name, value); 207 HTMLElement::parseAttribute(name, value);
221 } 208 }
222 209
223 String HTMLOptionElement::value() const 210 String HTMLOptionElement::value() const
224 { 211 {
225 const AtomicString& value = fastGetAttribute(valueAttr); 212 const AtomicString& value = fastGetAttribute(valueAttr);
226 if (!value.isNull()) 213 if (!value.isNull())
227 return value; 214 return value;
228 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace).simplifyWhiteSp ace(isHTMLSpace); 215 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace).simplifyWhiteSp ace(isHTMLSpace);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 252
266 void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange , Node* afterChange, int childCountDelta) 253 void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange , Node* afterChange, int childCountDelta)
267 { 254 {
268 #if ENABLE(DATALIST_ELEMENT) 255 #if ENABLE(DATALIST_ELEMENT)
269 if (HTMLDataListElement* dataList = ownerDataListElement()) 256 if (HTMLDataListElement* dataList = ownerDataListElement())
270 dataList->optionElementChildrenChanged(); 257 dataList->optionElementChildrenChanged();
271 else 258 else
272 #endif 259 #endif
273 if (HTMLSelectElement* select = ownerSelectElement()) 260 if (HTMLSelectElement* select = ownerSelectElement())
274 select->optionElementChildrenChanged(); 261 select->optionElementChildrenChanged();
262 updateLabel();
275 HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, chi ldCountDelta); 263 HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, chi ldCountDelta);
276 } 264 }
277 265
278 #if ENABLE(DATALIST_ELEMENT) 266 #if ENABLE(DATALIST_ELEMENT)
279 HTMLDataListElement* HTMLOptionElement::ownerDataListElement() const 267 HTMLDataListElement* HTMLOptionElement::ownerDataListElement() const
280 { 268 {
281 for (ContainerNode* parent = parentNode(); parent ; parent = parent->parentN ode()) { 269 for (ContainerNode* parent = parentNode(); parent ; parent = parent->parentN ode()) {
282 if (parent->hasTagName(datalistTag)) 270 if (parent->hasTagName(datalistTag))
283 return static_cast<HTMLDataListElement*>(parent); 271 return static_cast<HTMLDataListElement*>(parent);
284 } 272 }
(...skipping 19 matching lines...) Expand all
304 if (!label.isNull()) 292 if (!label.isNull())
305 return label; 293 return label;
306 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace).simplifyWhiteSp ace(isHTMLSpace); 294 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace).simplifyWhiteSp ace(isHTMLSpace);
307 } 295 }
308 296
309 void HTMLOptionElement::setLabel(const String& label) 297 void HTMLOptionElement::setLabel(const String& label)
310 { 298 {
311 setAttribute(labelAttr, label); 299 setAttribute(labelAttr, label);
312 } 300 }
313 301
314 void HTMLOptionElement::updateNonRenderStyle()
315 {
316 m_style = document()->styleResolver()->styleForElement(this);
317 }
318
319 RenderStyle* HTMLOptionElement::nonRendererStyle() const
320 {
321 return m_style.get();
322 }
323
324 PassRefPtr<RenderStyle> HTMLOptionElement::customStyleForRenderer()
325 {
326 // styleForRenderer is called whenever a new style should be associated
327 // with an Element so now is a good time to update our cached style.
328 updateNonRenderStyle();
329 return m_style;
330 }
331
332 void HTMLOptionElement::didRecalcStyle(StyleChange)
333 {
334 // FIXME: This is nasty, we ask our owner select to repaint even if the new
335 // style is exactly the same.
336 if (HTMLSelectElement* select = ownerSelectElement()) {
337 if (RenderObject* renderer = select->renderer())
338 renderer->repaint();
339 }
340 }
341
342 String HTMLOptionElement::textIndentedToRespectGroupLabel() const 302 String HTMLOptionElement::textIndentedToRespectGroupLabel() const
343 { 303 {
344 ContainerNode* parent = parentNode(); 304 ContainerNode* parent = parentNode();
345 if (parent && parent->hasTagName(optgroupTag)) 305 if (parent && parent->hasTagName(optgroupTag))
346 return " " + text(); 306 return " " + text();
347 return text(); 307 return text();
348 } 308 }
349 309
350 bool HTMLOptionElement::isDisabledFormControl() const 310 bool HTMLOptionElement::isDisabledFormControl() const
351 { 311 {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 text.append(node->nodeValue()); 343 text.append(node->nodeValue());
384 // Text nodes inside script elements are not part of the option text. 344 // Text nodes inside script elements are not part of the option text.
385 if (node->isElementNode() && toScriptElementIfPossible(toElement(node))) 345 if (node->isElementNode() && toScriptElementIfPossible(toElement(node)))
386 node = NodeTraversal::nextSkippingChildren(node, this); 346 node = NodeTraversal::nextSkippingChildren(node, this);
387 else 347 else
388 node = NodeTraversal::next(node, this); 348 node = NodeTraversal::next(node, this);
389 } 349 }
390 return text.toString(); 350 return text.toString();
391 } 351 }
392 352
353 void HTMLOptionElement::updateLabel()
354 {
355 Text* const textNode = toText(userAgentShadowRoot()->firstChild());
356 if (textNode)
357 textNode->replaceWholeText(text(), ASSERT_NO_EXCEPTION);
358 else
359 userAgentShadowRoot()->appendChild(Text::create(document(), text()), ASS ERT_NO_EXCEPTION);
360 }
361
362 PassRefPtr<RenderStyle> HTMLOptionElement::customStyleForRenderer()
363 {
364 RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForEle ment(this);
365 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
366
367 HTMLSelectElement* selectElement = ownerSelectElement();
368 if (selectElement) {
369 const Vector<HTMLElement*>& items = selectElement->listItems();
370 if (items[items.size() - 1] == this)
yosin_UTC9 2013/05/01 01:38:21 nit: We should check item.size() > 0.
371 style->setPaddingBottom(Length(0, Fixed));
372 }
373
374 return style.release();
375 }
376
393 #ifndef NDEBUG 377 #ifndef NDEBUG
394 378
395 HTMLOptionElement* toHTMLOptionElement(Node* node) 379 HTMLOptionElement* toHTMLOptionElement(Node* node)
396 { 380 {
397 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optionTag)); 381 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optionTag));
398 return static_cast<HTMLOptionElement*>(node); 382 return static_cast<HTMLOptionElement*>(node);
399 } 383 }
400 384
401 const HTMLOptionElement* toHTMLOptionElement(const Node* node) 385 const HTMLOptionElement* toHTMLOptionElement(const Node* node)
402 { 386 {
403 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optionTag)); 387 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optionTag));
404 return static_cast<const HTMLOptionElement*>(node); 388 return static_cast<const HTMLOptionElement*>(node);
405 } 389 }
406 390
407 #endif 391 #endif
408 392
409 } // namespace 393 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698