Index: Source/WebCore/html/HTMLOptGroupElement.cpp |
diff --git a/Source/WebCore/html/HTMLOptGroupElement.cpp b/Source/WebCore/html/HTMLOptGroupElement.cpp |
index 11614432d1115f7d9b352092e9ed8103d441b31e..4d66cfba0224c09da6e6c33940ecc3236d9e799d 100644 |
--- a/Source/WebCore/html/HTMLOptGroupElement.cpp |
+++ b/Source/WebCore/html/HTMLOptGroupElement.cpp |
@@ -26,18 +26,60 @@ |
#include "HTMLOptGroupElement.h" |
#include "Document.h" |
+#include "HTMLContentElement.h" |
+#include "HTMLDivElement.h" |
#include "HTMLNames.h" |
#include "HTMLSelectElement.h" |
#include "RenderMenuList.h" |
#include "NodeRenderStyle.h" |
#include "NodeRenderingContext.h" |
#include "StyleResolver.h" |
+#include "Text.h" |
#include <wtf/StdLibExtras.h> |
+#include <wtf/unicode/CharacterNames.h> |
namespace WebCore { |
using namespace HTMLNames; |
+class GroupLabelElement : public HTMLDivElement { |
+public: |
+ static PassRefPtr<GroupLabelElement> create(Document*); |
+ |
+private: |
+ GroupLabelElement(Document* document) |
+ : HTMLDivElement(HTMLNames::divTag, document) |
+ { |
+ setHasCustomStyleCallbacks(); |
+ } |
+ virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE; |
+}; |
+ |
+PassRefPtr<GroupLabelElement> GroupLabelElement::create(Document* document) |
+{ |
+ return adoptRef(new GroupLabelElement(document)); |
+} |
+ |
+PassRefPtr<RenderStyle> GroupLabelElement::customStyleForRenderer() |
+{ |
+ RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForElement(this); |
+ RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); |
+ |
+ style->setPaddingRight(Length(2, Fixed)); |
+ style->setPaddingLeft(Length(2, Fixed)); |
+ |
+ int paddingBottom = 1; |
+ HTMLSelectElement* selectElement = toHTMLOptGroupElement(shadowHost())->ownerSelectElement(); |
+ if (selectElement) { |
+ const Vector<HTMLElement*>& items = selectElement->listItems(); |
+ if (items[items.size() - 1] == this) |
+ paddingBottom = 0; |
+ } |
+ style->setPaddingBottom(Length(paddingBottom, Fixed)); |
+ |
+ return style.release(); |
+} |
+ |
inline HTMLOptGroupElement::HTMLOptGroupElement(const QualifiedName& tagName, Document* document) |
: HTMLElement(tagName, document) |
{ |
@@ -48,7 +90,9 @@ inline HTMLOptGroupElement::HTMLOptGroupElement(const QualifiedName& tagName, Do |
PassRefPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(const QualifiedName& tagName, Document* document) |
{ |
- return adoptRef(new HTMLOptGroupElement(tagName, document)); |
+ RefPtr<HTMLOptGroupElement> optGroup = adoptRef(new HTMLOptGroupElement(tagName, document)); |
+ optGroup->ensureUserAgentShadowRoot(); |
+ return optGroup.release(); |
} |
bool HTMLOptGroupElement::isDisabledFormControl() const |
@@ -86,6 +130,8 @@ void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const Atomic |
if (name == disabledAttr) |
didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled); |
+ else if (name == labelAttr) |
+ updateGroupLabel(); |
} |
void HTMLOptGroupElement::recalcSelectOptions() |
@@ -97,40 +143,6 @@ void HTMLOptGroupElement::recalcSelectOptions() |
toHTMLSelectElement(select)->setRecalcListItems(); |
} |
-void HTMLOptGroupElement::attach() |
-{ |
- HTMLElement::attach(); |
- // If after attaching nothing called styleForRenderer() on this node we |
- // manually cache the value. This happens if our parent doesn't have a |
- // renderer like <optgroup> or if it doesn't allow children like <select>. |
- if (!m_style && parentNode()->renderStyle()) |
- updateNonRenderStyle(); |
-} |
- |
-void HTMLOptGroupElement::detach() |
-{ |
- m_style.clear(); |
- HTMLElement::detach(); |
-} |
- |
-void HTMLOptGroupElement::updateNonRenderStyle() |
-{ |
- m_style = document()->styleResolver()->styleForElement(this); |
-} |
- |
-RenderStyle* HTMLOptGroupElement::nonRendererStyle() const |
-{ |
- return m_style.get(); |
-} |
- |
-PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer() |
-{ |
- // styleForRenderer is called whenever a new style should be associated |
- // with an Element so now is a good time to update our cached style. |
- updateNonRenderStyle(); |
- return m_style; |
-} |
- |
String HTMLOptGroupElement::groupLabelText() const |
{ |
String itemText = document()->displayStringModifiedByEncoding(getAttribute(labelAttr)); |
@@ -163,4 +175,37 @@ void HTMLOptGroupElement::accessKeyAction(bool) |
select->accessKeyAction(false); |
} |
+void HTMLOptGroupElement::didAddUserAgentShadowRoot(ShadowRoot* root) |
+{ |
+ RefPtr<GroupLabelElement> groupLabelElement = GroupLabelElement::create(document()); |
+ groupLabelElement->appendChild(Text::create(document(), "TEST"), ASSERT_NO_EXCEPTION); |
+ root->appendChild(groupLabelElement); |
+ m_groupLabelElement = groupLabelElement.get(); |
+ |
+ RefPtr<HTMLContentElement> content = HTMLContentElement::create(document()); |
+ content->setAttribute(selectAttr, "option"); |
+ root->appendChild(content); |
+ |
+ updateGroupLabel(); |
+} |
+ |
+void HTMLOptGroupElement::updateGroupLabel() |
+{ |
+ DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1)); |
+ String labelText = groupLabelText(); |
+ if (labelText.isEmpty()) |
+ labelText = nonBreakingSpaceString; |
+ Text* const textNode = toText(userAgentShadowRoot()->firstChild()->firstChild()); |
+ ASSERT(textNode); |
+ if (!textNode) |
+ return; |
+ textNode->replaceWholeText(labelText, ASSERT_NO_EXCEPTION); |
+} |
+ |
+HTMLOptGroupElement* toHTMLOptGroupElement(Node* node) |
+{ |
+ ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optgroupTag)); |
+ return static_cast<HTMLOptGroupElement*>(node); |
+} |
+ |
} // namespace |