Beispiel #1
0
template <> inline bool isMatchingElement(const HTMLCollection* htmlCollection, Element* element)
{
    CollectionType type = htmlCollection->type();
    if (!element->isHTMLElement() && !(type == DocAll || type == NodeChildren || type == WindowNamedItems))
        return false;

    switch (type) {
    case DocImages:
        return element->hasLocalName(imgTag);
    case DocScripts:
        return element->hasLocalName(scriptTag);
    case DocForms:
        return element->hasLocalName(formTag);
    case TableTBodies:
        return element->hasLocalName(tbodyTag);
    case TRCells:
        return element->hasLocalName(tdTag) || element->hasLocalName(thTag);
    case TSectionRows:
        return element->hasLocalName(trTag);
    case SelectOptions:
        return element->hasLocalName(optionTag);
    case SelectedOptions:
        return element->hasLocalName(optionTag) && toHTMLOptionElement(element)->selected();
    case DataListOptions:
        if (element->hasLocalName(optionTag)) {
            HTMLOptionElement* option = toHTMLOptionElement(element);
            if (!option->isDisabledFormControl() && !option->value().isEmpty())
                return true;
        }
        return false;
    case MapAreas:
        return element->hasLocalName(areaTag);
    case DocApplets:
        return element->hasLocalName(appletTag) || (element->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(element)->containsJavaApplet());
    case DocEmbeds:
        return element->hasLocalName(embedTag);
    case DocLinks:
        return (element->hasLocalName(aTag) || element->hasLocalName(areaTag)) && element->fastHasAttribute(hrefAttr);
    case DocAnchors:
        return element->hasLocalName(aTag) && element->fastHasAttribute(nameAttr);
    case DocAll:
    case NodeChildren:
        return true;
    case DocumentNamedItems:
        return static_cast<const DocumentNameCollection*>(htmlCollection)->nodeMatches(element);
    case WindowNamedItems:
        return static_cast<const WindowNameCollection*>(htmlCollection)->nodeMatches(element);
    case FormControls:
    case TableRows:
    case ChildNodeListType:
    case ClassNodeListType:
    case NameNodeListType:
    case TagNodeListType:
    case HTMLTagNodeListType:
    case RadioNodeListType:
    case LabelsNodeListType:
        ASSERT_NOT_REACHED();
    }
    return false;
}
Beispiel #2
0
void SelectPopupClient::setValueAndClosePopup(int, const String& stringValue)
{

    ASSERT(m_size == stringValue.length());

    if (m_size > 0) {
        bool selecteds[m_size];
        for (unsigned i = 0; i < m_size; i++)
            selecteds[i] = stringValue[i] - '0';

        const WTF::Vector<HTMLElement*>& items = m_element->listItems();

        if (items.size() != static_cast<unsigned int>(m_size))
            return;

        HTMLOptionElement* option;
        for (unsigned i = 0; i < m_size; i++) {
            if (items[i]->hasTagName(HTMLNames::optionTag)) {
                option = static_cast<HTMLOptionElement*>(items[i]);
                option->setSelectedState(selecteds[i]);
            }
        }
    }
    // Force repaint because we do not send mouse events to the select element
    // and the element doesn't automatically repaint itself.
    m_element->dispatchFormControlChangeEvent();
    m_element->renderer()->repaint();
    closePopup();
}
Beispiel #3
0
static void valueAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
    INC_STATS("DOM.HTMLOptionElement.value._set");
    HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder());
    V8Parameter<WithNullCheck> v = value;
    imp->setValue(v);
    return;
}
Beispiel #4
0
void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
{
    ASSERT(renderer() && renderer()->isListBox());
    
    unsigned start;
    unsigned end;
    ASSERT(m_activeSelectionAnchorIndex >= 0);
    start = min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
    end = max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);

    const Vector<HTMLElement*>& items = listItems();
    for (unsigned i = 0; i < items.size(); i++) {
        if (items[i]->hasLocalName(optionTag)) {
            HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
            if (!option->disabled()) {
                if (i >= start && i <= end)
                    option->setSelectedState(m_activeSelectionState);
                else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.size())
                    option->setSelectedState(false);
                else
                    option->setSelectedState(m_cachedStateForActiveSelection[i]);
            }
        }
    }

    scrollToSelection();
}
Beispiel #5
0
void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
{
    m_listItems.clear();
    HTMLOptionElement* foundSelected = 0;
    for (Node* current = firstChild(); current; current = current->traverseNextSibling(this)) {
        if (current->hasTagName(optgroupTag) && current->firstChild()) {
            // FIXME: It doesn't make sense to add an optgroup to the list items,
            // when it has children, but not to add it if it happens to have,
            // children (say some comment nodes or text nodes), yet that's what
            // this code does!
            m_listItems.append(static_cast<HTMLElement*>(current));
            current = current->firstChild();
            // FIXME: It doesn't make sense to handle an <optgroup> inside another <optgroup>
            // if it's not the first child, but not handle it if it happens to be the first
            // child, yet that's what this code does!
        }

        if (current->hasTagName(optionTag)) {
            m_listItems.append(static_cast<HTMLElement*>(current));
            if (updateSelectedStates) {
                if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) {
                    foundSelected = static_cast<HTMLOptionElement*>(current);
                    foundSelected->setSelectedState(true);
                } else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) {
                    foundSelected->setSelectedState(false);
                    foundSelected = static_cast<HTMLOptionElement*>(current);
                }
            }
        }
        if (current->hasTagName(hrTag))
            m_listItems.append(static_cast<HTMLElement*>(current));
    }
    m_recalcListItems = false;
}
Beispiel #6
0
void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fireOnChange)
{
    const Vector<HTMLElement*>& items = listItems();
    int listIndex = optionToListIndex(optionIndex);
    HTMLOptionElement* element = 0;

    if (!multiple())
        deselect = true;

    if (listIndex >= 0) {
        if (m_activeSelectionAnchorIndex < 0 || deselect)
            setActiveSelectionAnchorIndex(listIndex);
        if (m_activeSelectionEndIndex < 0 || deselect)
            setActiveSelectionEndIndex(listIndex);
        element = static_cast<HTMLOptionElement*>(items[listIndex]);
        element->setSelectedState(true);
    }

    if (deselect)
        deselectItems(element);

    scrollToSelection();

    // This only gets called with fireOnChange for menu lists. 
    if (fireOnChange && usesMenuList())
        menuListOnChange();

    Frame* frame = document()->frame();
    if (frame)
        frame->page()->chrome()->client()->formStateDidChange(this);
}
Beispiel #7
0
static void disabledAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
    INC_STATS("DOM.HTMLOptionElement.disabled._set");
    HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder());
    bool v = value->BooleanValue();
    imp->setDisabled(v);
    return;
}
Beispiel #8
0
void SelectPopupClient::setValueAndClosePopup(int, const String& stringValue)
{
    ASSERT(m_element);

    static const char* cancelValue = "-1";
    if (stringValue == cancelValue) {
        closePopup();
        return;
    }

    if (m_size > 0) {
        bool selecteds[m_size];
        for (unsigned i = 0; i < m_size; i++)
            selecteds[i] = stringValue[i] - '0';

        const Vector<HTMLElement*>& items = m_element->listItems();

        if (items.size() != static_cast<unsigned int>(m_size))
            return;

        HTMLOptionElement* option;
        for (unsigned i = 0; i < m_size; i++) {
            if (items[i]->hasTagName(HTMLNames::optionTag)) {
                option = static_cast<HTMLOptionElement*>(items[i]);
                option->setSelectedState(selecteds[i]);
            }
        }
    }
    // Force repaint because we do not send mouse events to the select element
    // and the element doesn't automatically repaint itself.
    if (m_element->renderer())
        m_element->renderer()->repaint();

    m_notifyChangeTimer.startOneShot(0);
}
static void selectedAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder());
    bool v = value->BooleanValue();
    imp->setSelected(v);
    return;
}
void
HTMLSelectOptionAccessible::SetSelected(bool aSelect)
{
  HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent);
  if (option)
    option->SetSelected(aSelect);
}
void
HTMLOptionsCollection::GetSupportedNames(nsTArray<nsString>& aNames)
{
  AutoTArray<nsIAtom*, 8> atoms;
  for (uint32_t i = 0; i < mElements.Length(); ++i) {
    HTMLOptionElement* content = mElements.ElementAt(i);
    if (content) {
      // Note: HasName means the names is exposed on the document,
      // which is false for options, so we don't check it here.
      const nsAttrValue* val = content->GetParsedAttr(nsGkAtoms::name);
      if (val && val->Type() == nsAttrValue::eAtom) {
        nsIAtom* name = val->GetAtomValue();
        if (!atoms.Contains(name)) {
          atoms.AppendElement(name);
        }
      }
      if (content->HasID()) {
        nsIAtom* id = content->GetID();
        if (!atoms.Contains(id)) {
          atoms.AppendElement(id);
        }
      }
    }
  }

  uint32_t atomsLen = atoms.Length();
  nsString* names = aNames.AppendElements(atomsLen);
  for (uint32_t i = 0; i < atomsLen; ++i) {
    atoms[i]->ToString(names[i]);
  }
}
void
HTMLOptionsCollection::GetSupportedNames(unsigned aFlags,
                                         nsTArray<nsString>& aNames)
{
  if (!(aFlags & JSITER_HIDDEN)) {
    return;
  }

  nsAutoTArray<nsIAtom*, 8> atoms;
  for (uint32_t i = 0; i < mElements.Length(); ++i) {
    HTMLOptionElement* content = mElements.ElementAt(i);
    if (content) {
      // Note: HasName means the names is exposed on the document,
      // which is false for options, so we don't check it here.
      const nsAttrValue* val = content->GetParsedAttr(nsGkAtoms::name);
      if (val && val->Type() == nsAttrValue::eAtom) {
        nsIAtom* name = val->GetAtomValue();
        if (!atoms.Contains(name)) {
          atoms.AppendElement(name);
        }
      }
      if (content->HasID()) {
        nsIAtom* id = content->GetID();
        if (!atoms.Contains(id)) {
          atoms.AppendElement(id);
        }
      }
    }
  }

  aNames.SetCapacity(atoms.Length());
  for (uint32_t i = 0; i < atoms.Length(); ++i) {
    aNames.AppendElement(nsDependentAtomString(atoms[i]));
  }
}
static void defaultSelectedAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder());
    bool v = value->BooleanValue();
    imp->setBooleanAttribute(WebCore::HTMLNames::selectedAttr, v);
    return;
}
static void labelAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder());
    V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, v, value);
    imp->setLabel(v);
    return;
}
JSValue jsHTMLOptionElementValue(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSHTMLOptionElement* castedThis = static_cast<JSHTMLOptionElement*>(asObject(slotBase));
    UNUSED_PARAM(exec);
    HTMLOptionElement* imp = static_cast<HTMLOptionElement*>(castedThis->impl());
    JSValue result = jsString(exec, imp->value());
    return result;
}
void setJSHTMLOptionElementText(ExecState* exec, JSObject* thisObject, JSValue value)
{
    JSHTMLOptionElement* castedThisObj = static_cast<JSHTMLOptionElement*>(thisObject);
    HTMLOptionElement* imp = static_cast<HTMLOptionElement*>(castedThisObj->impl());
    ExceptionCode ec = 0;
    imp->setText(valueToStringWithNullCheck(exec, value), ec);
    setDOMException(exec, ec);
}
JSValue jsHTMLOptionElementDisabled(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSHTMLOptionElement* castedThis = static_cast<JSHTMLOptionElement*>(asObject(slotBase));
    UNUSED_PARAM(exec);
    HTMLOptionElement* imp = static_cast<HTMLOptionElement*>(castedThis->impl());
    JSValue result = jsBoolean(imp->disabled());
    return result;
}
uint64_t
HTMLSelectOptionAccessible::NativeState() const
{
  // As a HTMLSelectOptionAccessible we can have the following states:
  // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN
  // Upcall to Accessible, but skip HyperTextAccessible impl
  // because we don't want EDITABLE or SELECTABLE_TEXT
  uint64_t state = Accessible::NativeState();

  Accessible* select = GetSelect();
  if (!select)
    return state;

  uint64_t selectState = select->State();
  if (selectState & states::INVISIBLE)
    return state;

  // Are we selected?
  HTMLOptionElement* option = HTMLOptionElement::FromNode(mContent);
  bool selected = option && option->Selected();
  if (selected)
    state |= states::SELECTED;

  if (selectState & states::OFFSCREEN) {
    state |= states::OFFSCREEN;
  } else if (selectState & states::COLLAPSED) {
    // <select> is COLLAPSED: add OFFSCREEN, if not the currently
    // visible option
    if (!selected) {
      state |= states::OFFSCREEN;
      // Ensure the invisible state is removed. Otherwise, group info will skip
      // this option. Furthermore, this gets cached and this doesn't get
      // invalidated even once the select is expanded.
      state &= ~states::INVISIBLE;
    } else {
      // Clear offscreen and invisible for currently showing option
      state &= ~(states::OFFSCREEN | states::INVISIBLE);
      state |= selectState & states::OPAQUE1;
    }
  } else {
    // XXX list frames are weird, don't rely on Accessible's general
    // visibility implementation unless they get reimplemented in layout
    state &= ~states::OFFSCREEN;
    // <select> is not collapsed: compare bounds to calculate OFFSCREEN
    Accessible* listAcc = Parent();
    if (listAcc) {
      nsIntRect optionRect = Bounds();
      nsIntRect listRect = listAcc->Bounds();
      if (optionRect.Y() < listRect.Y() ||
          optionRect.YMost() > listRect.YMost()) {
        state |= states::OFFSCREEN;
      }
    }
  }

  return state;
}
Beispiel #19
0
static inline bool isAcceptableElement(CollectionType type, Element* element)
{
    if (!element->isHTMLElement() && !(type == DocAll || type == NodeChildren))
        return false;

    switch (type) {
    case DocImages:
        return element->hasLocalName(imgTag);
    case DocScripts:
        return element->hasLocalName(scriptTag);
    case DocForms:
        return element->hasLocalName(formTag);
    case TableTBodies:
        return element->hasLocalName(tbodyTag);
    case TRCells:
        return element->hasLocalName(tdTag) || element->hasLocalName(thTag);
    case TSectionRows:
        return element->hasLocalName(trTag);
    case SelectOptions:
        return element->hasLocalName(optionTag);
    case SelectedOptions:
        return element->hasLocalName(optionTag) && toHTMLOptionElement(element)->selected();
    case DataListOptions:
        if (element->hasLocalName(optionTag)) {
            HTMLOptionElement* option = static_cast<HTMLOptionElement*>(element);
            if (!option->disabled() && !option->value().isEmpty())
                return true;
        }
        return false;
    case MapAreas:
        return element->hasLocalName(areaTag);
    case DocApplets:
        return element->hasLocalName(appletTag) || (element->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(element)->containsJavaApplet());
    case DocEmbeds:
        return element->hasLocalName(embedTag);
    case DocObjects:
        return element->hasLocalName(objectTag);
    case DocLinks:
        return (element->hasLocalName(aTag) || element->hasLocalName(areaTag)) && element->fastHasAttribute(hrefAttr);
    case DocAnchors:
        return element->hasLocalName(aTag) && element->fastHasAttribute(nameAttr);
    case DocAll:
    case NodeChildren:
        return true;
#if ENABLE(MICRODATA)
    case ItemProperties:
        return element->fastHasAttribute(itempropAttr);
#endif
    case FormControls:
    case DocumentNamedItems:
    case TableRows:
    case WindowNamedItems:
    case NodeListCollectionType:
        ASSERT_NOT_REACHED();
    }
    return false;
}
NS_IMETHODIMP
HTMLSelectOptionAccessible::SetSelected(bool aSelect)
{
  if (IsDefunct())
    return NS_ERROR_FAILURE;

  HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent);
  return option ? option->SetSelected(aSelect) : NS_ERROR_FAILURE;
}
Beispiel #21
0
static void textAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
    INC_STATS("DOM.HTMLOptionElement.text._set");
    HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder());
    V8Parameter<WithNullCheck> v = value;
    ExceptionCode ec = 0;
    imp->setText(v, ec);
    if (UNLIKELY(ec))
        V8Proxy::setDOMException(ec);
    return;
}
static void textAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder());
    V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, v, value);
    ExceptionCode ec = 0;
    imp->setText(v, ec);
    if (UNLIKELY(ec))
        setDOMException(ec, info.GetIsolate());
    return;
}
uint64_t
HTMLSelectOptionAccessible::NativeState()
{
  // As a HTMLSelectOptionAccessible we can have the following states:
  // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN
  // Upcall to Accessible, but skip HyperTextAccessible impl
  // because we don't want EDITABLE or SELECTABLE_TEXT
  uint64_t state = Accessible::NativeState();

  Accessible* select = GetSelect();
  if (!select)
    return state;

  uint64_t selectState = select->State();
  if (selectState & states::INVISIBLE)
    return state;

  // Are we selected?
  HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent);
  bool selected = option && option->Selected();
  if (selected)
    state |= states::SELECTED;

  if (selectState & states::OFFSCREEN) {
    state |= states::OFFSCREEN;
  } else if (selectState & states::COLLAPSED) {
    // <select> is COLLAPSED: add OFFSCREEN, if not the currently
    // visible option
    if (!selected) {
      state |= states::OFFSCREEN;
      state ^= states::INVISIBLE;
    } else {
      // Clear offscreen and invisible for currently showing option
      state &= ~(states::OFFSCREEN | states::INVISIBLE);
      state |= selectState & states::OPAQUE1;
    }
  } else {
    // XXX list frames are weird, don't rely on Accessible's general
    // visibility implementation unless they get reimplemented in layout
    state &= ~states::OFFSCREEN;
    // <select> is not collapsed: compare bounds to calculate OFFSCREEN
    Accessible* listAcc = Parent();
    if (listAcc) {
      nsIntRect optionRect = Bounds();
      nsIntRect listRect = listAcc->Bounds();
      if (optionRect.y < listRect.y ||
          optionRect.y + optionRect.height > listRect.y + listRect.height) {
        state |= states::OFFSCREEN;
      }
    }
  }

  return state;
}
Beispiel #24
0
void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement)
{
    const Vector<HTMLElement*>& items = listItems();
    unsigned i;
    for (i = 0; i < items.size(); i++) {
        if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) {
            HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]);
            element->setSelectedState(false);
        }
    }
}
v8::Handle<v8::Value> removeElement(HTMLSelectElement* imp, const v8::Arguments& args) 
{
    if (V8HTMLOptionElement::HasInstance(args[0])) {
        HTMLOptionElement* element = V8HTMLOptionElement::toNative(v8::Handle<v8::Object>::Cast(args[0]));
        imp->remove(element->index());
        return v8::Undefined();
    }

    imp->remove(toInt32(args[0]));
    return v8::Undefined();
}
bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
{
    if (!obj->isListBox())
        return true;

    paintCombo(obj, info, rect);
    RenderStyle* style = obj->style();
    if (style)
        style->setColor(Color::transparent);
    Node* node = obj->node();
    if (!node || !node->hasTagName(HTMLNames::selectTag))
        return true;

    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node);
    // The first item may be visible.  Make sure it does not draw.
    // If it has a style, it overrides the RenderListBox's style, so we
    // need to make sure both are set to transparent.
    node = select->item(0);
    if (node) {
        RenderObject* renderer = node->renderer();
        if (renderer) {
            RenderStyle* renderStyle = renderer->style();
            if (renderStyle)
                renderStyle->setColor(Color::transparent);
        }
    }
    // Find the first selected option, and draw its text.
    // FIXME: In a later change, if there is more than one item selected,
    // draw a string that says "X items" like iPhone Safari does
    int index = select->selectedIndex();
    node = select->item(index);
    if (!node || !node->hasTagName(HTMLNames::optionTag))
        return true;

    HTMLOptionElement* option = static_cast<HTMLOptionElement*>(node);
    String label = option->textIndentedToRespectGroupLabel();
    SkRect r(rect);

    SkPaint paint;
    paint.setAntiAlias(true);
    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    // Values for text size and positioning determined by trial and error
    paint.setTextSize(r.height() - SkIntToScalar(6));

    SkCanvas* canvas = getCanvasFromInfo(info);
    int saveCount = canvas->save();
    r.fRight -= SkIntToScalar(RenderSkinCombo::extraWidth());
    canvas->clipRect(r);
    canvas->drawText(label.characters(), label.length() << 1,
             r.fLeft + SkIntToScalar(5), r.fBottom - SkIntToScalar(5), paint);
    canvas->restoreToCount(saveCount);

    return true;    
}
Beispiel #27
0
void PopupMenuImpl::addOption(HTMLOptionElement& element, bool enableExtraStyling, SharedBuffer* data)
{
    PagePopupClient::addString("{\n", data);
    PagePopupClient::addString("type: \"option\",\n", data);
    addProperty("label", element.text(), data);
    addProperty("title", element.title(), data);
    addProperty("value", element.listIndex(), data);
    addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr), data);
    addProperty("disabled", element.isDisabledFormControl(), data);
    addElementStyle(element, enableExtraStyling, data);
    PagePopupClient::addString("},\n", data);
}
HTMLKeygenElement::HTMLKeygenElement(Document* doc, HTMLFormElement* f)
    : HTMLSelectElement(keygenTag, doc, f)
{
    Vector<String> keys = supportedKeySizes();
        
    Vector<String>::const_iterator end = keys.end();
    for (Vector<String>::const_iterator it = keys.begin(); it != end; ++it) {
        HTMLOptionElement* o = new HTMLOptionElement(doc, form());
        addChild(o);
        o->addChild(new Text(doc, *it));
    }
}
void LayoutMenuList::setTextFromOption(int optionIndex)
{
    HTMLSelectElement* select = selectElement();
    const HeapVector<Member<HTMLElement>>& listItems = select->listItems();
    const int size = listItems.size();

    String text = emptyString();
    m_optionStyle.clear();

    if (selectElement()->multiple()) {
        unsigned selectedCount = 0;
        int firstSelectedIndex = -1;
        for (int i = 0; i < size; ++i) {
            Element* element = listItems[i];
            if (!isHTMLOptionElement(*element))
                continue;

            if (toHTMLOptionElement(element)->selected()) {
                if (++selectedCount == 1)
                    firstSelectedIndex = i;
            }
        }

        if (selectedCount == 1) {
            ASSERT(0 <= firstSelectedIndex);
            ASSERT(firstSelectedIndex < size);
            HTMLOptionElement* selectedOptionElement = toHTMLOptionElement(listItems[firstSelectedIndex]);
            ASSERT(selectedOptionElement->selected());
            text = selectedOptionElement->textIndentedToRespectGroupLabel();
            m_optionStyle = selectedOptionElement->mutableComputedStyle();
        } else {
            Locale& locale = select->locale();
            String localizedNumberString = locale.convertToLocalizedNumber(String::number(selectedCount));
            text = locale.queryString(WebLocalizedString::SelectMenuListText, localizedNumberString);
            ASSERT(!m_optionStyle);
        }
    } else {
        const int i = select->optionToListIndex(optionIndex);
        if (i >= 0 && i < size) {
            Element* element = listItems[i];
            if (isHTMLOptionElement(*element)) {
                text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
                m_optionStyle = element->mutableComputedStyle();
            }
        }
    }

    setText(text.stripWhiteSpace());

    didUpdateActiveOption(optionIndex);
}
HRESULT STDMETHODCALLTYPE DOMHTMLOptionElement::label( 
        /* [retval][out] */ BSTR* result)
{
    if (!result)
        return E_POINTER;

    *result = 0;

    ASSERT(m_element);
    ASSERT(m_element->hasTagName(optionTag));
    HTMLOptionElement* optionElement = static_cast<HTMLOptionElement*>(m_element);

    *result = BString(optionElement->label()).release();
    return S_OK;
}