| Index: Source/core/html/HTMLOptGroupElement.cpp
|
| diff --git a/Source/core/html/HTMLOptGroupElement.cpp b/Source/core/html/HTMLOptGroupElement.cpp
|
| index 01c307a46d66dcaa577f3d43c47493147b70485d..1a169294ce24bb4e9220effd5a5d222b5f000c4d 100644
|
| --- a/Source/core/html/HTMLOptGroupElement.cpp
|
| +++ b/Source/core/html/HTMLOptGroupElement.cpp
|
| @@ -28,13 +28,78 @@
|
| #include "core/HTMLNames.h"
|
| #include "core/dom/Document.h"
|
| #include "core/dom/NodeRenderStyle.h"
|
| +#include "core/dom/Text.h"
|
| +#include "core/html/HTMLContentElement.h"
|
| +#include "core/html/HTMLDivElement.h"
|
| #include "core/html/HTMLSelectElement.h"
|
| #include "wtf/StdLibExtras.h"
|
| +#include "wtf/unicode/CharacterNames.h"
|
|
|
| namespace WebCore {
|
|
|
| using namespace HTMLNames;
|
|
|
| +class GroupLabelElement : public HTMLDivElement {
|
| +public:
|
| + static PassRefPtrWillBeRawPtr<GroupLabelElement> create(Document&);
|
| +
|
| + void setText(const String& text)
|
| + {
|
| + DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1));
|
| + const String& labelText = text.isEmpty() ? nonBreakingSpaceString : text;
|
| + if (!m_textNode) {
|
| + m_textNode = Text::create(document(), labelText);
|
| + appendChild(m_textNode);
|
| + } else {
|
| + m_textNode->replaceWholeText(labelText);
|
| + }
|
| + }
|
| +
|
| +private:
|
| + explicit GroupLabelElement(Document& document)
|
| + : HTMLDivElement(document)
|
| + , m_textNode(nullptr)
|
| + {
|
| + setHasCustomStyleCallbacks();
|
| + }
|
| + virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
|
| +
|
| + RefPtrWillBeMember<Text> m_textNode;
|
| +};
|
| +
|
| +PassRefPtrWillBeRawPtr<GroupLabelElement> GroupLabelElement::create(Document& document)
|
| +{
|
| + return adoptRefWillBeNoop(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 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = selectElement->listItems();
|
| + ASSERT(items.size() > 0);
|
| + if (items.last() == this)
|
| + paddingBottom = 0;
|
| + }
|
| + style->setPaddingBottom(Length(paddingBottom, Fixed));
|
| +
|
| + return style.release();
|
| +}
|
| +
|
| +PassRefPtrWillBeRawPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(Document& document)
|
| +{
|
| + RefPtrWillBeRawPtr<HTMLOptGroupElement> optGroupElement = adoptRefWillBeNoop(new HTMLOptGroupElement(document));
|
| + optGroupElement->ensureUserAgentShadowRoot();
|
| + return optGroupElement.release();
|
| +}
|
| +
|
| inline HTMLOptGroupElement::HTMLOptGroupElement(Document& document)
|
| : HTMLElement(optgroupTag, document)
|
| {
|
| @@ -42,7 +107,11 @@ inline HTMLOptGroupElement::HTMLOptGroupElement(Document& document)
|
| ScriptWrappable::init(this);
|
| }
|
|
|
| -DEFINE_NODE_FACTORY(HTMLOptGroupElement)
|
| +void HTMLOptGroupElement::trace(Visitor* visitor)
|
| +{
|
| + visitor->trace(m_groupLabelElement);
|
| + HTMLElement::trace(visitor);
|
| +}
|
|
|
| bool HTMLOptGroupElement::isDisabledFormControl() const
|
| {
|
| @@ -51,8 +120,11 @@ bool HTMLOptGroupElement::isDisabledFormControl() const
|
|
|
| bool HTMLOptGroupElement::rendererIsFocusable() const
|
| {
|
| - // Optgroup elements do not have a renderer so we check the renderStyle instead.
|
| - return renderStyle() && renderStyle()->display() != NONE;
|
| + HTMLSelectElement* selectElement = ownerSelectElement();
|
| + if (!selectElement || selectElement->usesMenuList()) {
|
| + return !isDisplayNone();
|
| + }
|
| + return HTMLElement::rendererIsFocusable();
|
| }
|
|
|
| void HTMLOptGroupElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
|
| @@ -61,6 +133,12 @@ void HTMLOptGroupElement::childrenChanged(bool changedByParser, Node* beforeChan
|
| HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
|
| }
|
|
|
| +bool HTMLOptGroupElement::rendererIsNeeded(const RenderStyle&)
|
| +{
|
| + HTMLSelectElement* select = ownerSelectElement();
|
| + return select && !select->usesMenuList() && !isDisplayNone();
|
| +}
|
| +
|
| void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
|
| {
|
| HTMLElement::parseAttribute(name, value);
|
| @@ -68,6 +146,8 @@ void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const Atomic
|
|
|
| if (name == disabledAttr)
|
| didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled);
|
| + else if (name == labelAttr)
|
| + updateGroupLabel();
|
| }
|
|
|
| void HTMLOptGroupElement::recalcSelectOptions()
|
| @@ -112,6 +192,7 @@ PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer()
|
| return m_style;
|
| }
|
|
|
| +
|
| String HTMLOptGroupElement::groupLabelText() const
|
| {
|
| String itemText = getAttribute(labelAttr);
|
| @@ -124,6 +205,16 @@ String HTMLOptGroupElement::groupLabelText() const
|
| return itemText;
|
| }
|
|
|
| +LayoutUnit HTMLOptGroupElement::groupLabelHeight() const
|
| +{
|
| + if (!m_groupLabelElement)
|
| + return 0;
|
| + RenderObject* labelRenderer = m_groupLabelElement->renderer();
|
| + if (!labelRenderer)
|
| + return 0;
|
| + return labelRenderer->absoluteBoundingBoxRect().height();
|
| +}
|
| +
|
| HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const
|
| {
|
| return Traversal<HTMLSelectElement>::firstAncestor(*this);
|
| @@ -137,10 +228,47 @@ void HTMLOptGroupElement::accessKeyAction(bool)
|
| select->accessKeyAction(false);
|
| }
|
|
|
| +void HTMLOptGroupElement::didAddUserAgentShadowRoot(ShadowRoot& root)
|
| +{
|
| + RefPtr<GroupLabelElement> groupLabelElement = GroupLabelElement::create(document());
|
| + groupLabelElement->setText(String());
|
| + root.appendChild(groupLabelElement);
|
| + m_groupLabelElement = groupLabelElement.get();
|
| +
|
| + RefPtr<HTMLContentElement> content = HTMLContentElement::create(document());
|
| + content->setAttribute(selectAttr, "option");
|
| + root.appendChild(content);
|
| +}
|
| +
|
| +void HTMLOptGroupElement::updateGroupLabel()
|
| +{
|
| + static_cast<GroupLabelElement*>(ensureUserAgentShadowRoot().firstChild())->setText(groupLabelText());
|
| +}
|
| +
|
| bool HTMLOptGroupElement::isDisplayNone() const
|
| {
|
| - RenderStyle* style = nonRendererStyle();
|
| - return style && style->display() == NONE;
|
| + RenderStyle* style = renderStyle();
|
| + return !style || style->display() == NONE;
|
| +}
|
| +
|
| +Node::InsertionNotificationRequest HTMLOptGroupElement::insertedInto(ContainerNode* insertionPoint)
|
| +{
|
| + HTMLElement::insertedInto(insertionPoint);
|
| + return insertionPoint->inDocument() ? InsertionShouldCallDidNotifySubtreeInsertions : InsertionDone;
|
| +}
|
| +
|
| +void HTMLOptGroupElement::didNotifySubtreeInsertionsToDocument()
|
| +{
|
| + updateView();
|
| +}
|
| +
|
| +void HTMLOptGroupElement::updateView()
|
| +{
|
| + HTMLSelectElement* select = ownerSelectElement();
|
| + if (select && !select->usesMenuList())
|
| + ensureUserAgentShadowRoot();
|
| + else if (userAgentShadowRoot())
|
| + userAgentShadowRoot()->detach();
|
| }
|
|
|
| } // namespace
|
|
|