475c7d7289342aeaa7ec029b7165c0e9c3828c31
[WebKit-https.git] / Source / WebCore / rendering / RenderMenuList.cpp
1 /*
2  * This file is part of the select element renderer in WebCore.
3  *
4  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
5  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6  *               2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "RenderMenuList.h"
27
28 #include "AXObjectCache.h"
29 #include "AccessibilityMenuList.h"
30 #include "CSSFontSelector.h"
31 #include "Chrome.h"
32 #include "FontCache.h"
33 #include "Frame.h"
34 #include "FrameView.h"
35 #include "HTMLNames.h"
36 #include "HTMLOptionElement.h"
37 #include "HTMLOptGroupElement.h"
38 #include "HTMLSelectElement.h"
39 #include "NodeRenderStyle.h"
40 #include "Page.h"
41 #include "PopupMenu.h"
42 #include "RenderBR.h"
43 #include "RenderScrollbar.h"
44 #include "RenderTheme.h"
45 #include "Settings.h"
46 #include "StyleResolver.h"
47 #include "TextRun.h"
48 #include <math.h>
49
50 using namespace std;
51
52 namespace WebCore {
53
54 using namespace HTMLNames;
55
56 RenderMenuList::RenderMenuList(Element* element)
57     : RenderFlexibleBox(element)
58     , m_buttonText(0)
59     , m_innerBlock(0)
60     , m_optionsChanged(true)
61     , m_optionsWidth(0)
62     , m_lastActiveIndex(-1)
63     , m_popupIsVisible(false)
64 {
65     ASSERT(element);
66     ASSERT(element->isHTMLElement());
67     ASSERT(element->hasTagName(HTMLNames::selectTag));
68 }
69
70 RenderMenuList::~RenderMenuList()
71 {
72     if (m_popup)
73         m_popup->disconnectClient();
74     m_popup = 0;
75 }
76
77 bool RenderMenuList::canBeReplacedWithInlineRunIn() const
78 {
79     return false;
80 }
81
82 void RenderMenuList::createInnerBlock()
83 {
84     if (m_innerBlock) {
85         ASSERT(firstChild() == m_innerBlock);
86         ASSERT(!m_innerBlock->nextSibling());
87         return;
88     }
89
90     // Create an anonymous block.
91     ASSERT(!firstChild());
92     m_innerBlock = createAnonymousBlock();
93     adjustInnerStyle();
94     RenderFlexibleBox::addChild(m_innerBlock);
95 }
96
97 void RenderMenuList::adjustInnerStyle()
98 {
99     RenderStyle* innerStyle = m_innerBlock->style();
100     innerStyle->setFlexGrow(1);
101     innerStyle->setFlexShrink(1);
102     // min-width: 0; is needed for correct shrinking.
103     // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed.
104     innerStyle->setMinWidth(Length(0, Fixed));
105     // Use margin:auto instead of align-items:center to get safe centering, i.e.
106     // when the content overflows, treat it the same as align-items: flex-start.
107     // But we only do that for the cases where html.css would otherwise use center.
108     if (style()->alignItems() == AlignCenter) {
109         innerStyle->setMarginTop(Length());
110         innerStyle->setMarginBottom(Length());
111         innerStyle->setAlignSelf(AlignFlexStart);
112     }
113
114     innerStyle->setPaddingLeft(Length(theme()->popupInternalPaddingLeft(style()), Fixed));
115     innerStyle->setPaddingRight(Length(theme()->popupInternalPaddingRight(style()), Fixed));
116     innerStyle->setPaddingTop(Length(theme()->popupInternalPaddingTop(style()), Fixed));
117     innerStyle->setPaddingBottom(Length(theme()->popupInternalPaddingBottom(style()), Fixed));
118
119     if (document()->page()->chrome()->selectItemWritingDirectionIsNatural()) {
120         // Items in the popup will not respect the CSS text-align and direction properties,
121         // so we must adjust our own style to match.
122         innerStyle->setTextAlign(LEFT);
123         TextDirection direction = (m_buttonText && m_buttonText->text()->defaultWritingDirection() == WTF::Unicode::RightToLeft) ? RTL : LTR;
124         innerStyle->setDirection(direction);
125     } else if (m_optionStyle && document()->page()->chrome()->selectItemAlignmentFollowsMenuWritingDirection()) {
126         if ((m_optionStyle->direction() != innerStyle->direction() || m_optionStyle->unicodeBidi() != innerStyle->unicodeBidi()))
127             m_innerBlock->setNeedsLayoutAndPrefWidthsRecalc();
128         innerStyle->setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT);
129         innerStyle->setDirection(m_optionStyle->direction());
130         innerStyle->setUnicodeBidi(m_optionStyle->unicodeBidi());
131     }
132 }
133
134 inline HTMLSelectElement* RenderMenuList::selectElement() const
135 {
136     return toHTMLSelectElement(node());
137 }
138
139 void RenderMenuList::addChild(RenderObject* newChild, RenderObject* beforeChild)
140 {
141     createInnerBlock();
142     m_innerBlock->addChild(newChild, beforeChild);
143     ASSERT(m_innerBlock == firstChild());
144
145     if (AXObjectCache* cache = document()->existingAXObjectCache())
146         cache->childrenChanged(this);
147 }
148
149 void RenderMenuList::removeChild(RenderObject* oldChild)
150 {
151     if (oldChild == m_innerBlock || !m_innerBlock) {
152         RenderFlexibleBox::removeChild(oldChild);
153         m_innerBlock = 0;
154     } else
155         m_innerBlock->removeChild(oldChild);
156 }
157
158 void RenderMenuList::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
159 {
160     RenderBlock::styleDidChange(diff, oldStyle);
161
162     if (m_buttonText)
163         m_buttonText->setStyle(style());
164     if (m_innerBlock) // RenderBlock handled updating the anonymous block's style.
165         adjustInnerStyle();
166
167     bool fontChanged = !oldStyle || oldStyle->font() != style()->font();
168     if (fontChanged)
169         updateOptionsWidth();
170 }
171
172 void RenderMenuList::updateOptionsWidth()
173 {
174     float maxOptionWidth = 0;
175     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
176     int size = listItems.size();    
177     FontCachePurgePreventer fontCachePurgePreventer;
178
179     for (int i = 0; i < size; ++i) {
180         HTMLElement* element = listItems[i];
181         if (!element->hasTagName(optionTag))
182             continue;
183
184         String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
185         applyTextTransform(style(), text, ' ');
186         if (theme()->popupOptionSupportsTextIndent()) {
187             // Add in the option's text indent.  We can't calculate percentage values for now.
188             float optionWidth = 0;
189             if (RenderStyle* optionStyle = element->renderStyle())
190                 optionWidth += minimumValueForLength(optionStyle->textIndent(), 0, view());
191             if (!text.isEmpty())
192                 optionWidth += style()->font().width(text);
193             maxOptionWidth = max(maxOptionWidth, optionWidth);
194         } else if (!text.isEmpty())
195             maxOptionWidth = max(maxOptionWidth, style()->font().width(text));
196     }
197
198     int width = static_cast<int>(ceilf(maxOptionWidth));
199     if (m_optionsWidth == width)
200         return;
201
202     m_optionsWidth = width;
203     if (parent())
204         setNeedsLayoutAndPrefWidthsRecalc();
205 }
206
207 void RenderMenuList::updateFromElement()
208 {
209     if (m_optionsChanged) {
210         updateOptionsWidth();
211         m_optionsChanged = false;
212     }
213
214     if (m_popupIsVisible)
215         m_popup->updateFromElement();
216     else
217         setTextFromOption(selectElement()->selectedIndex());
218 }
219
220 void RenderMenuList::setTextFromOption(int optionIndex)
221 {
222     HTMLSelectElement* select = selectElement();
223     const Vector<HTMLElement*>& listItems = select->listItems();
224     int size = listItems.size();
225
226     int i = select->optionToListIndex(optionIndex);
227     String text = emptyString();
228     if (i >= 0 && i < size) {
229         Element* element = listItems[i];
230         if (element->hasTagName(optionTag)) {
231             text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
232             m_optionStyle = element->renderStyle();
233         }
234     }
235
236     setText(text.stripWhiteSpace());
237     didUpdateActiveOption(optionIndex);
238 }
239
240 void RenderMenuList::setText(const String& s)
241 {
242     if (s.isEmpty()) {
243         if (!m_buttonText || !m_buttonText->isBR()) {
244             if (m_buttonText)
245                 m_buttonText->destroy();
246             m_buttonText = new (renderArena()) RenderBR(document());
247             m_buttonText->setStyle(style());
248             addChild(m_buttonText);
249         }
250     } else {
251         if (m_buttonText && !m_buttonText->isBR())
252             m_buttonText->setText(s.impl(), true);
253         else {
254             if (m_buttonText)
255                 m_buttonText->destroy();
256             m_buttonText = new (renderArena()) RenderText(document(), s.impl());
257             m_buttonText->setStyle(style());
258             addChild(m_buttonText);
259         }
260         adjustInnerStyle();
261     }
262 }
263
264 String RenderMenuList::text() const
265 {
266     return m_buttonText ? m_buttonText->text() : 0;
267 }
268
269 LayoutRect RenderMenuList::controlClipRect(const LayoutPoint& additionalOffset) const
270 {
271     // Clip to the intersection of the content box and the content box for the inner box
272     // This will leave room for the arrows which sit in the inner box padding,
273     // and if the inner box ever spills out of the outer box, that will get clipped too.
274     LayoutRect outerBox(additionalOffset.x() + borderLeft() + paddingLeft(), 
275                    additionalOffset.y() + borderTop() + paddingTop(),
276                    contentWidth(), 
277                    contentHeight());
278     
279     LayoutRect innerBox(additionalOffset.x() + m_innerBlock->x() + m_innerBlock->paddingLeft(), 
280                    additionalOffset.y() + m_innerBlock->y() + m_innerBlock->paddingTop(),
281                    m_innerBlock->contentWidth(), 
282                    m_innerBlock->contentHeight());
283
284     return intersection(outerBox, innerBox);
285 }
286
287 void RenderMenuList::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
288 {
289     maxLogicalWidth = max(m_optionsWidth, theme()->minimumMenuListSize(style())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight();
290     if (!style()->width().isPercent())
291         minLogicalWidth = maxLogicalWidth;
292 }
293
294 void RenderMenuList::computePreferredLogicalWidths()
295 {
296     m_minPreferredLogicalWidth = 0;
297     m_maxPreferredLogicalWidth = 0;
298     
299     if (style()->width().isFixed() && style()->width().value() > 0)
300         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
301     else
302         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
303
304     if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
305         m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
306         m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
307     }
308
309     if (style()->maxWidth().isFixed()) {
310         m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
311         m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
312     }
313
314     LayoutUnit toAdd = borderAndPaddingWidth();
315     m_minPreferredLogicalWidth += toAdd;
316     m_maxPreferredLogicalWidth += toAdd;
317
318     setPreferredLogicalWidthsDirty(false);
319 }
320
321 void RenderMenuList::showPopup()
322 {
323     if (m_popupIsVisible)
324         return;
325
326     if (document()->page()->chrome()->hasOpenedPopup())
327         return;
328
329     // Create m_innerBlock here so it ends up as the first child.
330     // This is important because otherwise we might try to create m_innerBlock
331     // inside the showPopup call and it would fail.
332     createInnerBlock();
333     if (!m_popup)
334         m_popup = document()->page()->chrome()->createPopupMenu(this);
335     m_popupIsVisible = true;
336
337     // Compute the top left taking transforms into account, but use
338     // the actual width of the element to size the popup.
339     FloatPoint absTopLeft = localToAbsolute(FloatPoint(), UseTransforms);
340     IntRect absBounds = absoluteBoundingBoxRectIgnoringTransforms();
341     absBounds.setLocation(roundedIntPoint(absTopLeft));
342     HTMLSelectElement* select = selectElement();
343     m_popup->show(absBounds, document()->view(), select->optionToListIndex(select->selectedIndex()));
344 }
345
346 void RenderMenuList::hidePopup()
347 {
348     if (m_popup)
349         m_popup->hide();
350 }
351
352 void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
353 {
354     // Check to ensure a page navigation has not occurred while
355     // the popup was up.
356     Document* doc = toElement(node())->document();
357     if (!doc || doc != doc->frame()->document())
358         return;
359     
360     HTMLSelectElement* select = selectElement();
361     select->optionSelectedByUser(select->listToOptionIndex(listIndex), fireOnChange);
362 }
363
364 void RenderMenuList::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow)
365 {
366     selectElement()->listBoxSelectItem(listIndex, allowMultiplySelections, shift, fireOnChangeNow);
367 }
368
369 bool RenderMenuList::multiple() const
370 {
371     return selectElement()->multiple();
372 }
373
374 void RenderMenuList::didSetSelectedIndex(int listIndex)
375 {
376     didUpdateActiveOption(selectElement()->listToOptionIndex(listIndex));
377 }
378
379 void RenderMenuList::didUpdateActiveOption(int optionIndex)
380 {
381     if (!AXObjectCache::accessibilityEnabled() || !document()->existingAXObjectCache())
382         return;
383
384     if (m_lastActiveIndex == optionIndex)
385         return;
386     m_lastActiveIndex = optionIndex;
387
388     HTMLSelectElement* select = selectElement();
389     int listIndex = select->optionToListIndex(optionIndex);
390     if (listIndex < 0 || listIndex >= static_cast<int>(select->listItems().size()))
391         return;
392
393     ASSERT(select->listItems()[listIndex]);
394
395     if (AccessibilityMenuList* menuList = static_cast<AccessibilityMenuList*>(document()->axObjectCache()->get(this)))
396         menuList->didUpdateActiveOption(optionIndex);
397 }
398
399 String RenderMenuList::itemText(unsigned listIndex) const
400 {
401     HTMLSelectElement* select = selectElement();
402     const Vector<HTMLElement*>& listItems = select->listItems();
403     if (listIndex >= listItems.size())
404         return String();
405
406     String itemString;
407     Element* element = listItems[listIndex];
408     if (element->hasTagName(optgroupTag))
409         itemString = static_cast<const HTMLOptGroupElement*>(element)->groupLabelText();
410     else if (element->hasTagName(optionTag))
411         itemString = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
412
413     applyTextTransform(style(), itemString, ' ');
414     return itemString;
415 }
416
417 String RenderMenuList::itemLabel(unsigned) const
418 {
419     return String();
420 }
421
422 String RenderMenuList::itemIcon(unsigned) const
423 {
424     return String();
425 }
426
427 String RenderMenuList::itemAccessibilityText(unsigned listIndex) const
428 {
429     // Allow the accessible name be changed if necessary.
430     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
431     if (listIndex >= listItems.size())
432         return String();
433     return listItems[listIndex]->fastGetAttribute(aria_labelAttr);
434 }
435     
436 String RenderMenuList::itemToolTip(unsigned listIndex) const
437 {
438     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
439     if (listIndex >= listItems.size())
440         return String();
441     return listItems[listIndex]->title();
442 }
443
444 bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
445 {
446     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
447     if (listIndex >= listItems.size())
448         return false;
449     HTMLElement* element = listItems[listIndex];
450     if (!element->hasTagName(optionTag))
451         return false;
452
453     bool groupEnabled = true;
454     if (Element* parentElement = element->parentElement()) {
455         if (parentElement->hasTagName(optgroupTag))
456             groupEnabled = !static_cast<HTMLOptGroupElement*>(parentElement)->disabled();
457     }
458     if (!groupEnabled)
459         return false;
460
461     return element->isEnabledFormControl();
462 }
463
464 PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
465 {
466     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
467     if (listIndex >= listItems.size()) {
468         // If we are making an out of bounds access, then we want to use the style
469         // of a different option element (index 0). However, if there isn't an option element
470         // before at index 0, we fall back to the menu's style.
471         if (!listIndex)
472             return menuStyle();
473
474         // Try to retrieve the style of an option element we know exists (index 0).
475         listIndex = 0;
476     }
477     HTMLElement* element = listItems[listIndex];
478
479     Color itemBackgroundColor;
480     bool itemHasCustomBackgroundColor;
481     getItemBackgroundColor(listIndex, itemBackgroundColor, itemHasCustomBackgroundColor);
482
483     RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle();
484     return style ? PopupMenuStyle(style->visitedDependentColor(CSSPropertyColor), itemBackgroundColor, style->font(), style->visibility() == VISIBLE,
485         style->display() == NONE, style->textIndent(), style->direction(), isOverride(style->unicodeBidi()),
486         itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : PopupMenuStyle::DefaultBackgroundColor) : menuStyle();
487 }
488
489 void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackgroundColor, bool& itemHasCustomBackgroundColor) const
490 {
491     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
492     if (listIndex >= listItems.size()) {
493         itemBackgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
494         itemHasCustomBackgroundColor = false;
495         return;
496     }
497     HTMLElement* element = listItems[listIndex];
498
499     Color backgroundColor;
500     if (element->renderStyle())
501         backgroundColor = element->renderStyle()->visitedDependentColor(CSSPropertyBackgroundColor);
502     itemHasCustomBackgroundColor = backgroundColor.isValid() && backgroundColor.alpha();
503     // If the item has an opaque background color, return that.
504     if (!backgroundColor.hasAlpha()) {
505         itemBackgroundColor = backgroundColor;
506         return;
507     }
508
509     // Otherwise, the item's background is overlayed on top of the menu background.
510     backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor).blend(backgroundColor);
511     if (!backgroundColor.hasAlpha()) {
512         itemBackgroundColor = backgroundColor;
513         return;
514     }
515
516     // If the menu background is not opaque, then add an opaque white background behind.
517     itemBackgroundColor = Color(Color::white).blend(backgroundColor);
518 }
519
520 PopupMenuStyle RenderMenuList::menuStyle() const
521 {
522     RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style();
523     return PopupMenuStyle(s->visitedDependentColor(CSSPropertyColor), s->visitedDependentColor(CSSPropertyBackgroundColor), s->font(), s->visibility() == VISIBLE,
524         s->display() == NONE, s->textIndent(), style()->direction(), isOverride(style()->unicodeBidi()));
525 }
526
527 HostWindow* RenderMenuList::hostWindow() const
528 {
529     return document()->view()->hostWindow();
530 }
531
532 PassRefPtr<Scrollbar> RenderMenuList::createScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
533 {
534     RefPtr<Scrollbar> widget;
535     bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR);
536     if (hasCustomScrollbarStyle)
537         widget = RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, this->node());
538     else
539         widget = Scrollbar::createNativeScrollbar(scrollableArea, orientation, controlSize);
540     return widget.release();
541 }
542
543 int RenderMenuList::clientInsetLeft() const
544 {
545     return 0;
546 }
547
548 int RenderMenuList::clientInsetRight() const
549 {
550     return 0;
551 }
552
553 LayoutUnit RenderMenuList::clientPaddingLeft() const
554 {
555     return paddingLeft() + m_innerBlock->paddingLeft();
556 }
557
558 const int endOfLinePadding = 2;
559 LayoutUnit RenderMenuList::clientPaddingRight() const
560 {
561     if (style()->appearance() == MenulistPart || style()->appearance() == MenulistButtonPart) {
562         // For these appearance values, the theme applies padding to leave room for the
563         // drop-down button. But leaving room for the button inside the popup menu itself
564         // looks strange, so we return a small default padding to avoid having a large empty
565         // space appear on the side of the popup menu.
566         return endOfLinePadding;
567     }
568
569     // If the appearance isn't MenulistPart, then the select is styled (non-native), so
570     // we want to return the user specified padding.
571     return paddingRight() + m_innerBlock->paddingRight();
572 }
573
574 int RenderMenuList::listSize() const
575 {
576     return selectElement()->listItems().size();
577 }
578
579 int RenderMenuList::selectedIndex() const
580 {
581     HTMLSelectElement* select = selectElement();
582     return select->optionToListIndex(select->selectedIndex());
583 }
584
585 void RenderMenuList::popupDidHide()
586 {
587     m_popupIsVisible = false;
588 }
589
590 bool RenderMenuList::itemIsSeparator(unsigned listIndex) const
591 {
592     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
593     return listIndex < listItems.size() && listItems[listIndex]->hasTagName(hrTag);
594 }
595
596 bool RenderMenuList::itemIsLabel(unsigned listIndex) const
597 {
598     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
599     return listIndex < listItems.size() && listItems[listIndex]->hasTagName(optgroupTag);
600 }
601
602 bool RenderMenuList::itemIsSelected(unsigned listIndex) const
603 {
604     const Vector<HTMLElement*>& listItems = selectElement()->listItems();
605     if (listIndex >= listItems.size())
606         return false;
607     HTMLElement* element = listItems[listIndex];
608     return element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected();
609 }
610
611 void RenderMenuList::setTextFromItem(unsigned listIndex)
612 {
613     setTextFromOption(selectElement()->listToOptionIndex(listIndex));
614 }
615
616 FontSelector* RenderMenuList::fontSelector() const
617 {
618     return document()->styleResolver()->fontSelector();
619 }
620
621 }