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 "core/rendering/RenderMenuList.h" 27 28 #include "core/HTMLNames.h" 29 #include "core/accessibility/AXMenuList.h" 30 #include "core/accessibility/AXObjectCache.h" 31 #include "core/css/CSSFontSelector.h" 32 #include "core/css/resolver/StyleResolver.h" 33 #include "core/dom/NodeRenderStyle.h" 34 #include "core/frame/FrameHost.h" 35 #include "core/frame/FrameView.h" 36 #include "core/frame/LocalFrame.h" 37 #include "core/html/HTMLOptGroupElement.h" 38 #include "core/html/HTMLOptionElement.h" 39 #include "core/html/HTMLSelectElement.h" 40 #include "core/page/Chrome.h" 41 #include "core/rendering/RenderBR.h" 42 #include "core/rendering/RenderScrollbar.h" 43 #include "core/rendering/RenderTheme.h" 44 #include "core/rendering/RenderView.h" 45 #include "platform/fonts/FontCache.h" 46 #include "platform/geometry/IntSize.h" 47 #include "platform/text/PlatformLocale.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(isHTMLSelectElement(element)); 66 } 67 68 RenderMenuList::~RenderMenuList() 69 { 70 if (m_popup) 71 m_popup->disconnectClient(); 72 m_popup = nullptr; 73 } 74 75 // FIXME: Instead of this hack we should add a ShadowRoot to <select> with no insertion point 76 // to prevent children from rendering. 77 bool RenderMenuList::isChildAllowed(RenderObject* object, RenderStyle*) const 78 { 79 return object->isAnonymous() && !object->isRenderFullScreen(); 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 // Use margin:auto instead of align-items:center to get safe centering, i.e. 103 // when the content overflows, treat it the same as align-items: flex-start. 104 // But we only do that for the cases where html.css would otherwise use center. 105 if (style()->alignItems() == ItemPositionCenter) { 106 innerStyle->setMarginTop(Length()); 107 innerStyle->setMarginBottom(Length()); 108 innerStyle->setAlignSelf(ItemPositionFlexStart); 109 } 110 111 innerStyle->setPaddingLeft(Length(RenderTheme::theme().popupInternalPaddingLeft(style()), Fixed)); 112 innerStyle->setPaddingRight(Length(RenderTheme::theme().popupInternalPaddingRight(style()), Fixed)); 113 innerStyle->setPaddingTop(Length(RenderTheme::theme().popupInternalPaddingTop(style()), Fixed)); 114 innerStyle->setPaddingBottom(Length(RenderTheme::theme().popupInternalPaddingBottom(style()), Fixed)); 115 116 if (m_optionStyle) { 117 if ((m_optionStyle->direction() != innerStyle->direction() || m_optionStyle->unicodeBidi() != innerStyle->unicodeBidi())) 118 m_innerBlock->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); 119 innerStyle->setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT); 120 innerStyle->setDirection(m_optionStyle->direction()); 121 innerStyle->setUnicodeBidi(m_optionStyle->unicodeBidi()); 122 } 123 } 124 125 inline HTMLSelectElement* RenderMenuList::selectElement() const 126 { 127 return toHTMLSelectElement(node()); 128 } 129 130 void RenderMenuList::addChild(RenderObject* newChild, RenderObject* beforeChild) 131 { 132 createInnerBlock(); 133 m_innerBlock->addChild(newChild, beforeChild); 134 ASSERT(m_innerBlock == firstChild()); 135 136 if (AXObjectCache* cache = document().existingAXObjectCache()) 137 cache->childrenChanged(this); 138 } 139 140 void RenderMenuList::removeChild(RenderObject* oldChild) 141 { 142 if (oldChild == m_innerBlock || !m_innerBlock) { 143 RenderFlexibleBox::removeChild(oldChild); 144 m_innerBlock = 0; 145 } else 146 m_innerBlock->removeChild(oldChild); 147 } 148 149 void RenderMenuList::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 150 { 151 RenderBlock::styleDidChange(diff, oldStyle); 152 153 if (m_buttonText) 154 m_buttonText->setStyle(style()); 155 if (m_innerBlock) // RenderBlock handled updating the anonymous block's style. 156 adjustInnerStyle(); 157 158 bool fontChanged = !oldStyle || oldStyle->font() != style()->font(); 159 if (fontChanged) 160 updateOptionsWidth(); 161 } 162 163 void RenderMenuList::updateOptionsWidth() 164 { 165 float maxOptionWidth = 0; 166 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 167 int size = listItems.size(); 168 FontCachePurgePreventer fontCachePurgePreventer; 169 170 for (int i = 0; i < size; ++i) { 171 HTMLElement* element = listItems[i]; 172 if (!isHTMLOptionElement(*element)) 173 continue; 174 175 String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); 176 applyTextTransform(style(), text, ' '); 177 if (RenderTheme::theme().popupOptionSupportsTextIndent()) { 178 // Add in the option's text indent. We can't calculate percentage values for now. 179 float optionWidth = 0; 180 if (RenderStyle* optionStyle = element->renderStyle()) 181 optionWidth += minimumValueForLength(optionStyle->textIndent(), 0); 182 if (!text.isEmpty()) 183 optionWidth += style()->font().width(text); 184 maxOptionWidth = max(maxOptionWidth, optionWidth); 185 } else if (!text.isEmpty()) 186 maxOptionWidth = max(maxOptionWidth, style()->font().width(text)); 187 } 188 189 int width = static_cast<int>(ceilf(maxOptionWidth)); 190 if (m_optionsWidth == width) 191 return; 192 193 m_optionsWidth = width; 194 if (parent()) 195 setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); 196 } 197 198 void RenderMenuList::updateFromElement() 199 { 200 if (m_optionsChanged) { 201 updateOptionsWidth(); 202 m_optionsChanged = false; 203 } 204 205 if (m_popupIsVisible) { 206 m_popup->updateFromElement(); 207 } else { 208 if (selectElement()->suggestedIndex() >= 0) 209 setTextFromOption(selectElement()->suggestedIndex()); 210 else 211 setTextFromOption(selectElement()->selectedIndex()); 212 } 213 } 214 215 void RenderMenuList::setTextFromOption(int optionIndex) 216 { 217 HTMLSelectElement* select = selectElement(); 218 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems(); 219 const int size = listItems.size(); 220 221 String text = emptyString(); 222 m_optionStyle.clear(); 223 224 if (multiple()) { 225 unsigned selectedCount = 0; 226 int firstSelectedIndex = -1; 227 for (int i = 0; i < size; ++i) { 228 Element* element = listItems[i]; 229 if (!isHTMLOptionElement(*element)) 230 continue; 231 232 if (toHTMLOptionElement(element)->selected()) { 233 if (++selectedCount == 1) 234 firstSelectedIndex = i; 235 } 236 } 237 238 if (selectedCount == 1) { 239 ASSERT(0 <= firstSelectedIndex); 240 ASSERT(firstSelectedIndex < size); 241 HTMLOptionElement* selectedOptionElement = toHTMLOptionElement(listItems[firstSelectedIndex]); 242 ASSERT(selectedOptionElement->selected()); 243 text = selectedOptionElement->textIndentedToRespectGroupLabel(); 244 m_optionStyle = selectedOptionElement->renderStyle(); 245 } else { 246 Locale& locale = select->locale(); 247 String localizedNumberString = locale.convertToLocalizedNumber(String::number(selectedCount)); 248 text = locale.queryString(blink::WebLocalizedString::SelectMenuListText, localizedNumberString); 249 ASSERT(!m_optionStyle); 250 } 251 } else { 252 const int i = select->optionToListIndex(optionIndex); 253 if (i >= 0 && i < size) { 254 Element* element = listItems[i]; 255 if (isHTMLOptionElement(*element)) { 256 text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); 257 m_optionStyle = element->renderStyle(); 258 } 259 } 260 } 261 262 setText(text.stripWhiteSpace()); 263 264 didUpdateActiveOption(optionIndex); 265 } 266 267 void RenderMenuList::setText(const String& s) 268 { 269 if (s.isEmpty()) { 270 if (!m_buttonText || !m_buttonText->isBR()) { 271 // FIXME: We should not modify the structure of the render tree 272 // during layout. crbug.com/370462 273 DeprecatedDisableModifyRenderTreeStructureAsserts disabler; 274 if (m_buttonText) 275 m_buttonText->destroy(); 276 m_buttonText = new RenderBR(&document()); 277 m_buttonText->setStyle(style()); 278 addChild(m_buttonText); 279 } 280 } else { 281 if (m_buttonText && !m_buttonText->isBR()) 282 m_buttonText->setText(s.impl(), true); 283 else { 284 // FIXME: We should not modify the structure of the render tree 285 // during layout. crbug.com/370462 286 DeprecatedDisableModifyRenderTreeStructureAsserts disabler; 287 if (m_buttonText) 288 m_buttonText->destroy(); 289 m_buttonText = new RenderText(&document(), s.impl()); 290 m_buttonText->setStyle(style()); 291 // We need to set the text explicitly though it was specified in the 292 // constructor because RenderText doesn't refer to the text 293 // specified in the constructor in a case of re-transforming. 294 m_buttonText->setText(s.impl(), true); 295 addChild(m_buttonText); 296 } 297 adjustInnerStyle(); 298 } 299 } 300 301 String RenderMenuList::text() const 302 { 303 return m_buttonText ? m_buttonText->text() : String(); 304 } 305 306 LayoutRect RenderMenuList::controlClipRect(const LayoutPoint& additionalOffset) const 307 { 308 // Clip to the intersection of the content box and the content box for the inner box 309 // This will leave room for the arrows which sit in the inner box padding, 310 // and if the inner box ever spills out of the outer box, that will get clipped too. 311 LayoutRect outerBox(additionalOffset.x() + borderLeft() + paddingLeft(), 312 additionalOffset.y() + borderTop() + paddingTop(), 313 contentWidth(), 314 contentHeight()); 315 316 LayoutRect innerBox(additionalOffset.x() + m_innerBlock->x() + m_innerBlock->paddingLeft(), 317 additionalOffset.y() + m_innerBlock->y() + m_innerBlock->paddingTop(), 318 m_innerBlock->contentWidth(), 319 m_innerBlock->contentHeight()); 320 321 return intersection(outerBox, innerBox); 322 } 323 324 void RenderMenuList::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const 325 { 326 maxLogicalWidth = max(m_optionsWidth, RenderTheme::theme().minimumMenuListSize(style())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight(); 327 if (!style()->width().isPercent()) 328 minLogicalWidth = maxLogicalWidth; 329 } 330 331 void RenderMenuList::computePreferredLogicalWidths() 332 { 333 m_minPreferredLogicalWidth = 0; 334 m_maxPreferredLogicalWidth = 0; 335 RenderStyle* styleToUse = style(); 336 337 if (styleToUse->width().isFixed() && styleToUse->width().value() > 0) 338 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value()); 339 else 340 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); 341 342 if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) { 343 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); 344 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); 345 } 346 347 if (styleToUse->maxWidth().isFixed()) { 348 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); 349 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); 350 } 351 352 LayoutUnit toAdd = borderAndPaddingWidth(); 353 m_minPreferredLogicalWidth += toAdd; 354 m_maxPreferredLogicalWidth += toAdd; 355 356 clearPreferredLogicalWidthsDirty(); 357 } 358 359 void RenderMenuList::showPopup() 360 { 361 if (m_popupIsVisible) 362 return; 363 364 if (document().frameHost()->chrome().hasOpenedPopup()) 365 return; 366 367 // Create m_innerBlock here so it ends up as the first child. 368 // This is important because otherwise we might try to create m_innerBlock 369 // inside the showPopup call and it would fail. 370 createInnerBlock(); 371 if (!m_popup) 372 m_popup = document().frameHost()->chrome().createPopupMenu(*document().frame(), this); 373 m_popupIsVisible = true; 374 375 FloatQuad quad(localToAbsoluteQuad(FloatQuad(borderBoundingBox()))); 376 IntSize size = pixelSnappedIntRect(frameRect()).size(); 377 HTMLSelectElement* select = selectElement(); 378 m_popup->show(quad, size, select->optionToListIndex(select->selectedIndex())); 379 } 380 381 void RenderMenuList::hidePopup() 382 { 383 if (m_popup) 384 m_popup->hide(); 385 } 386 387 void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange) 388 { 389 // Check to ensure a page navigation has not occurred while 390 // the popup was up. 391 Document& doc = toElement(node())->document(); 392 if (&doc != doc.frame()->document()) 393 return; 394 395 HTMLSelectElement* select = selectElement(); 396 select->optionSelectedByUser(select->listToOptionIndex(listIndex), fireOnChange); 397 } 398 399 void RenderMenuList::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow) 400 { 401 selectElement()->listBoxSelectItem(listIndex, allowMultiplySelections, shift, fireOnChangeNow); 402 } 403 404 bool RenderMenuList::multiple() const 405 { 406 return selectElement()->multiple(); 407 } 408 409 void RenderMenuList::didSetSelectedIndex(int listIndex) 410 { 411 didUpdateActiveOption(selectElement()->listToOptionIndex(listIndex)); 412 } 413 414 void RenderMenuList::didUpdateActiveOption(int optionIndex) 415 { 416 if (!AXObjectCache::accessibilityEnabled() || !document().existingAXObjectCache()) 417 return; 418 419 if (m_lastActiveIndex == optionIndex) 420 return; 421 m_lastActiveIndex = optionIndex; 422 423 HTMLSelectElement* select = selectElement(); 424 int listIndex = select->optionToListIndex(optionIndex); 425 if (listIndex < 0 || listIndex >= static_cast<int>(select->listItems().size())) 426 return; 427 if (AXMenuList* menuList = toAXMenuList(document().axObjectCache()->get(this))) 428 menuList->didUpdateActiveOption(optionIndex); 429 } 430 431 String RenderMenuList::itemText(unsigned listIndex) const 432 { 433 HTMLSelectElement* select = selectElement(); 434 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems(); 435 if (listIndex >= listItems.size()) 436 return String(); 437 438 String itemString; 439 Element* element = listItems[listIndex]; 440 if (isHTMLOptGroupElement(*element)) 441 itemString = toHTMLOptGroupElement(*element).groupLabelText(); 442 else if (isHTMLOptionElement(*element)) 443 itemString = toHTMLOptionElement(*element).textIndentedToRespectGroupLabel(); 444 445 applyTextTransform(style(), itemString, ' '); 446 return itemString; 447 } 448 449 String RenderMenuList::itemAccessibilityText(unsigned listIndex) const 450 { 451 // Allow the accessible name be changed if necessary. 452 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 453 if (listIndex >= listItems.size()) 454 return String(); 455 return listItems[listIndex]->fastGetAttribute(aria_labelAttr); 456 } 457 458 String RenderMenuList::itemToolTip(unsigned listIndex) const 459 { 460 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 461 if (listIndex >= listItems.size()) 462 return String(); 463 return listItems[listIndex]->title(); 464 } 465 466 bool RenderMenuList::itemIsEnabled(unsigned listIndex) const 467 { 468 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 469 if (listIndex >= listItems.size()) 470 return false; 471 HTMLElement* element = listItems[listIndex]; 472 if (!isHTMLOptionElement(*element)) 473 return false; 474 475 bool groupEnabled = true; 476 if (Element* parentElement = element->parentElement()) { 477 if (isHTMLOptGroupElement(*parentElement)) 478 groupEnabled = !parentElement->isDisabledFormControl(); 479 } 480 if (!groupEnabled) 481 return false; 482 483 return !element->isDisabledFormControl(); 484 } 485 486 PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const 487 { 488 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 489 if (listIndex >= listItems.size()) { 490 // If we are making an out of bounds access, then we want to use the style 491 // of a different option element (index 0). However, if there isn't an option element 492 // before at index 0, we fall back to the menu's style. 493 if (!listIndex) 494 return menuStyle(); 495 496 // Try to retrieve the style of an option element we know exists (index 0). 497 listIndex = 0; 498 } 499 HTMLElement* element = listItems[listIndex]; 500 501 Color itemBackgroundColor; 502 bool itemHasCustomBackgroundColor; 503 getItemBackgroundColor(listIndex, itemBackgroundColor, itemHasCustomBackgroundColor); 504 505 RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle(); 506 return style ? PopupMenuStyle(resolveColor(style, CSSPropertyColor), itemBackgroundColor, style->font(), style->visibility() == VISIBLE, 507 style->display() == NONE, style->textIndent(), style->direction(), isOverride(style->unicodeBidi()), 508 itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : PopupMenuStyle::DefaultBackgroundColor) : menuStyle(); 509 } 510 511 void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackgroundColor, bool& itemHasCustomBackgroundColor) const 512 { 513 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 514 if (listIndex >= listItems.size()) { 515 itemBackgroundColor = resolveColor(CSSPropertyBackgroundColor); 516 itemHasCustomBackgroundColor = false; 517 return; 518 } 519 HTMLElement* element = listItems[listIndex]; 520 521 Color backgroundColor; 522 if (element->renderStyle()) 523 backgroundColor = resolveColor(element->renderStyle(), CSSPropertyBackgroundColor); 524 itemHasCustomBackgroundColor = backgroundColor.alpha(); 525 // If the item has an opaque background color, return that. 526 if (!backgroundColor.hasAlpha()) { 527 itemBackgroundColor = backgroundColor; 528 return; 529 } 530 531 // Otherwise, the item's background is overlayed on top of the menu background. 532 backgroundColor = resolveColor(CSSPropertyBackgroundColor).blend(backgroundColor); 533 if (!backgroundColor.hasAlpha()) { 534 itemBackgroundColor = backgroundColor; 535 return; 536 } 537 538 // If the menu background is not opaque, then add an opaque white background behind. 539 itemBackgroundColor = Color(Color::white).blend(backgroundColor); 540 } 541 542 PopupMenuStyle RenderMenuList::menuStyle() const 543 { 544 const RenderObject* o = m_innerBlock ? m_innerBlock : this; 545 const RenderStyle* s = o->style(); 546 return PopupMenuStyle(o->resolveColor(CSSPropertyColor), o->resolveColor(CSSPropertyBackgroundColor), s->font(), s->visibility() == VISIBLE, 547 s->display() == NONE, s->textIndent(), style()->direction(), isOverride(style()->unicodeBidi())); 548 } 549 550 LayoutUnit RenderMenuList::clientPaddingLeft() const 551 { 552 return paddingLeft() + m_innerBlock->paddingLeft(); 553 } 554 555 const int endOfLinePadding = 2; 556 LayoutUnit RenderMenuList::clientPaddingRight() const 557 { 558 if (style()->appearance() == MenulistPart || style()->appearance() == MenulistButtonPart) { 559 // For these appearance values, the theme applies padding to leave room for the 560 // drop-down button. But leaving room for the button inside the popup menu itself 561 // looks strange, so we return a small default padding to avoid having a large empty 562 // space appear on the side of the popup menu. 563 return endOfLinePadding; 564 } 565 566 // If the appearance isn't MenulistPart, then the select is styled (non-native), so 567 // we want to return the user specified padding. 568 return paddingRight() + m_innerBlock->paddingRight(); 569 } 570 571 int RenderMenuList::listSize() const 572 { 573 return selectElement()->listItems().size(); 574 } 575 576 int RenderMenuList::selectedIndex() const 577 { 578 HTMLSelectElement* select = selectElement(); 579 return select->optionToListIndex(select->selectedIndex()); 580 } 581 582 void RenderMenuList::popupDidHide() 583 { 584 m_popupIsVisible = false; 585 } 586 587 bool RenderMenuList::itemIsSeparator(unsigned listIndex) const 588 { 589 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 590 return listIndex < listItems.size() && isHTMLHRElement(*listItems[listIndex]); 591 } 592 593 bool RenderMenuList::itemIsLabel(unsigned listIndex) const 594 { 595 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 596 return listIndex < listItems.size() && isHTMLOptGroupElement(*listItems[listIndex]); 597 } 598 599 bool RenderMenuList::itemIsSelected(unsigned listIndex) const 600 { 601 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); 602 if (listIndex >= listItems.size()) 603 return false; 604 HTMLElement* element = listItems[listIndex]; 605 return isHTMLOptionElement(*element) && toHTMLOptionElement(*element).selected(); 606 } 607 608 void RenderMenuList::setTextFromItem(unsigned listIndex) 609 { 610 setTextFromOption(selectElement()->listToOptionIndex(listIndex)); 611 } 612 613 } 614