| OLD | NEW |
| 1 /* | 1 /* |
| 2 * This file is part of the select element layoutObject in WebCore. | 2 * This file is part of the select element layoutObject in WebCore. |
| 3 * | 3 * |
| 4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | 4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
| 5 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv
ed. | 5 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv
ed. |
| 6 * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo
bile.com/) | 6 * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo
bile.com/) |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 | 49 |
| 50 namespace blink { | 50 namespace blink { |
| 51 | 51 |
| 52 using namespace HTMLNames; | 52 using namespace HTMLNames; |
| 53 | 53 |
| 54 LayoutMenuList::LayoutMenuList(Element* element) | 54 LayoutMenuList::LayoutMenuList(Element* element) |
| 55 : LayoutFlexibleBox(element) | 55 : LayoutFlexibleBox(element) |
| 56 , m_buttonText(nullptr) | 56 , m_buttonText(nullptr) |
| 57 , m_innerBlock(nullptr) | 57 , m_innerBlock(nullptr) |
| 58 , m_optionsChanged(true) | 58 , m_optionsChanged(true) |
| 59 , m_isEmpty(false) |
| 60 , m_hasUpdatedActiveOption(false) |
| 61 , m_popupIsVisible(false) |
| 59 , m_optionsWidth(0) | 62 , m_optionsWidth(0) |
| 60 , m_lastActiveIndex(-1) | 63 , m_lastActiveIndex(-1) |
| 61 , m_popupIsVisible(false) | |
| 62 , m_indexToSelectOnCancel(-1) | 64 , m_indexToSelectOnCancel(-1) |
| 63 { | 65 { |
| 64 ASSERT(isHTMLSelectElement(element)); | 66 ASSERT(isHTMLSelectElement(element)); |
| 65 } | 67 } |
| 66 | 68 |
| 67 LayoutMenuList::~LayoutMenuList() | 69 LayoutMenuList::~LayoutMenuList() |
| 68 { | 70 { |
| 69 ASSERT(!m_popup); | 71 ASSERT(!m_popup); |
| 70 } | 72 } |
| 71 | 73 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 88 { | 90 { |
| 89 if (m_innerBlock) { | 91 if (m_innerBlock) { |
| 90 ASSERT(firstChild() == m_innerBlock); | 92 ASSERT(firstChild() == m_innerBlock); |
| 91 ASSERT(!m_innerBlock->nextSibling()); | 93 ASSERT(!m_innerBlock->nextSibling()); |
| 92 return; | 94 return; |
| 93 } | 95 } |
| 94 | 96 |
| 95 // Create an anonymous block. | 97 // Create an anonymous block. |
| 96 ASSERT(!firstChild()); | 98 ASSERT(!firstChild()); |
| 97 m_innerBlock = createAnonymousBlock(); | 99 m_innerBlock = createAnonymousBlock(); |
| 100 |
| 101 m_buttonText = new LayoutText(&document(), StringImpl::empty()); |
| 102 // We need to set the text explicitly though it was specified in the |
| 103 // constructor because LayoutText doesn't refer to the text |
| 104 // specified in the constructor in a case of re-transforming. |
| 105 m_buttonText->setStyle(mutableStyle()); |
| 106 m_innerBlock->addChild(m_buttonText); |
| 107 |
| 98 adjustInnerStyle(); | 108 adjustInnerStyle(); |
| 99 LayoutFlexibleBox::addChild(m_innerBlock); | 109 LayoutFlexibleBox::addChild(m_innerBlock); |
| 100 } | 110 } |
| 101 | 111 |
| 102 void LayoutMenuList::adjustInnerStyle() | 112 void LayoutMenuList::adjustInnerStyle() |
| 103 { | 113 { |
| 104 ComputedStyle& innerStyle = m_innerBlock->mutableStyleRef(); | 114 ComputedStyle& innerStyle = m_innerBlock->mutableStyleRef(); |
| 105 innerStyle.setFlexGrow(1); | 115 innerStyle.setFlexGrow(1); |
| 106 innerStyle.setFlexShrink(1); | 116 innerStyle.setFlexShrink(1); |
| 107 // min-width: 0; is needed for correct shrinking. | 117 // min-width: 0; is needed for correct shrinking. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 129 } | 139 } |
| 130 } | 140 } |
| 131 | 141 |
| 132 inline HTMLSelectElement* LayoutMenuList::selectElement() const | 142 inline HTMLSelectElement* LayoutMenuList::selectElement() const |
| 133 { | 143 { |
| 134 return toHTMLSelectElement(node()); | 144 return toHTMLSelectElement(node()); |
| 135 } | 145 } |
| 136 | 146 |
| 137 void LayoutMenuList::addChild(LayoutObject* newChild, LayoutObject* beforeChild) | 147 void LayoutMenuList::addChild(LayoutObject* newChild, LayoutObject* beforeChild) |
| 138 { | 148 { |
| 139 createInnerBlock(); | |
| 140 m_innerBlock->addChild(newChild, beforeChild); | 149 m_innerBlock->addChild(newChild, beforeChild); |
| 141 ASSERT(m_innerBlock == firstChild()); | 150 ASSERT(m_innerBlock == firstChild()); |
| 142 | 151 |
| 143 if (AXObjectCache* cache = document().existingAXObjectCache()) | 152 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 144 cache->childrenChanged(this); | 153 cache->childrenChanged(this); |
| 145 } | 154 } |
| 146 | 155 |
| 147 void LayoutMenuList::removeChild(LayoutObject* oldChild) | 156 void LayoutMenuList::removeChild(LayoutObject* oldChild) |
| 148 { | 157 { |
| 149 if (oldChild == m_innerBlock || !m_innerBlock) { | 158 if (oldChild == m_innerBlock || !m_innerBlock) { |
| 150 LayoutFlexibleBox::removeChild(oldChild); | 159 LayoutFlexibleBox::removeChild(oldChild); |
| 151 m_innerBlock = nullptr; | 160 m_innerBlock = nullptr; |
| 152 } else { | 161 } else { |
| 153 m_innerBlock->removeChild(oldChild); | 162 m_innerBlock->removeChild(oldChild); |
| 154 } | 163 } |
| 155 } | 164 } |
| 156 | 165 |
| 157 void LayoutMenuList::styleDidChange(StyleDifference diff, const ComputedStyle* o
ldStyle) | 166 void LayoutMenuList::styleDidChange(StyleDifference diff, const ComputedStyle* o
ldStyle) |
| 158 { | 167 { |
| 159 LayoutBlock::styleDidChange(diff, oldStyle); | 168 LayoutBlock::styleDidChange(diff, oldStyle); |
| 160 | 169 |
| 161 if (m_buttonText) | 170 if (!m_innerBlock) |
| 162 m_buttonText->setStyle(mutableStyle()); | 171 createInnerBlock(); |
| 163 if (m_innerBlock) // LayoutBlock handled updating the anonymous block's styl
e. | 172 |
| 164 adjustInnerStyle(); | 173 m_buttonText->setStyle(mutableStyle()); |
| 174 adjustInnerStyle(); |
| 165 | 175 |
| 166 bool fontChanged = !oldStyle || oldStyle->font() != style()->font(); | 176 bool fontChanged = !oldStyle || oldStyle->font() != style()->font(); |
| 167 if (fontChanged) | 177 if (fontChanged) |
| 168 updateOptionsWidth(); | 178 updateOptionsWidth(); |
| 169 } | 179 } |
| 170 | 180 |
| 171 void LayoutMenuList::updateOptionsWidth() | 181 void LayoutMenuList::updateOptionsWidth() |
| 172 { | 182 { |
| 173 float maxOptionWidth = 0; | 183 float maxOptionWidth = 0; |
| 174 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = selectE
lement()->listItems(); | 184 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = selectE
lement()->listItems(); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 } | 290 } |
| 281 | 291 |
| 282 setText(text.stripWhiteSpace()); | 292 setText(text.stripWhiteSpace()); |
| 283 | 293 |
| 284 didUpdateActiveOption(optionIndex); | 294 didUpdateActiveOption(optionIndex); |
| 285 } | 295 } |
| 286 | 296 |
| 287 void LayoutMenuList::setText(const String& s) | 297 void LayoutMenuList::setText(const String& s) |
| 288 { | 298 { |
| 289 if (s.isEmpty()) { | 299 if (s.isEmpty()) { |
| 290 if (!m_buttonText || !m_buttonText->isBR()) { | 300 // FIXME: This is a hack. We need the select to have the same baseline p
ositioning as |
| 291 // FIXME: We should not modify the structure of the layout tree | 301 // any surrounding text. Wihtout any content, we align the bottom of the
select to the bottom |
| 292 // during layout. crbug.com/370462 | 302 // of the text. With content (In this case the faked " ") we correctly a
lign the middle of |
| 293 DeprecatedDisableModifyLayoutTreeStructureAsserts disabler; | 303 // the select to the middle of the text. It should be possible to remove
this, just set |
| 294 if (m_buttonText) | 304 // s.impl() into the text and have things align correctly ... crbug.com
/485982 |
| 295 m_buttonText->destroy(); | 305 m_isEmpty = true; |
| 296 m_buttonText = new LayoutBR(&document()); | 306 m_buttonText->setText(StringImpl::create(" ", 1), true); |
| 297 m_buttonText->setStyle(mutableStyle()); | |
| 298 addChild(m_buttonText); | |
| 299 } | |
| 300 } else { | 307 } else { |
| 301 if (m_buttonText && !m_buttonText->isBR()) { | 308 m_isEmpty = false; |
| 302 m_buttonText->setText(s.impl(), true); | 309 m_buttonText->setText(s.impl(), true); |
| 303 } else { | |
| 304 // FIXME: We should not modify the structure of the layout tree | |
| 305 // during layout. crbug.com/370462 | |
| 306 DeprecatedDisableModifyLayoutTreeStructureAsserts disabler; | |
| 307 if (m_buttonText) | |
| 308 m_buttonText->destroy(); | |
| 309 m_buttonText = new LayoutText(&document(), s.impl()); | |
| 310 m_buttonText->setStyle(mutableStyle()); | |
| 311 // We need to set the text explicitly though it was specified in the | |
| 312 // constructor because LayoutText doesn't refer to the text | |
| 313 // specified in the constructor in a case of re-transforming. | |
| 314 m_buttonText->setText(s.impl(), true); | |
| 315 addChild(m_buttonText); | |
| 316 } | |
| 317 adjustInnerStyle(); | |
| 318 } | 310 } |
| 311 adjustInnerStyle(); |
| 319 } | 312 } |
| 320 | 313 |
| 321 String LayoutMenuList::text() const | 314 String LayoutMenuList::text() const |
| 322 { | 315 { |
| 323 return m_buttonText ? m_buttonText->text() : String(); | 316 return m_buttonText && !m_isEmpty ? m_buttonText->text() : String(); |
| 324 } | 317 } |
| 325 | 318 |
| 326 LayoutRect LayoutMenuList::controlClipRect(const LayoutPoint& additionalOffset)
const | 319 LayoutRect LayoutMenuList::controlClipRect(const LayoutPoint& additionalOffset)
const |
| 327 { | 320 { |
| 328 // Clip to the intersection of the content box and the content box for the i
nner box | 321 // Clip to the intersection of the content box and the content box for the i
nner box |
| 329 // This will leave room for the arrows which sit in the inner box padding, | 322 // This will leave room for the arrows which sit in the inner box padding, |
| 330 // and if the inner box ever spills out of the outer box, that will get clip
ped too. | 323 // and if the inner box ever spills out of the outer box, that will get clip
ped too. |
| 331 LayoutRect outerBox = contentBoxRect(); | 324 LayoutRect outerBox = contentBoxRect(); |
| 332 outerBox.moveBy(additionalOffset); | 325 outerBox.moveBy(additionalOffset); |
| 333 | 326 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 346 } | 339 } |
| 347 | 340 |
| 348 void LayoutMenuList::showPopup() | 341 void LayoutMenuList::showPopup() |
| 349 { | 342 { |
| 350 if (m_popupIsVisible) | 343 if (m_popupIsVisible) |
| 351 return; | 344 return; |
| 352 | 345 |
| 353 if (document().frameHost()->chrome().hasOpenedPopup()) | 346 if (document().frameHost()->chrome().hasOpenedPopup()) |
| 354 return; | 347 return; |
| 355 | 348 |
| 356 // Create m_innerBlock here so it ends up as the first child. | |
| 357 // This is important because otherwise we might try to create m_innerBlock | |
| 358 // inside the showPopup call and it would fail. | |
| 359 createInnerBlock(); | |
| 360 if (!m_popup) | 349 if (!m_popup) |
| 361 m_popup = document().frameHost()->chrome().createPopupMenu(*document().f
rame(), this); | 350 m_popup = document().frameHost()->chrome().createPopupMenu(*document().f
rame(), this); |
| 362 m_popupIsVisible = true; | 351 m_popupIsVisible = true; |
| 363 | 352 |
| 364 FloatQuad quad(localToAbsoluteQuad(FloatQuad(borderBoundingBox()))); | 353 FloatQuad quad(localToAbsoluteQuad(FloatQuad(borderBoundingBox()))); |
| 365 IntSize size = pixelSnappedIntRect(frameRect()).size(); | 354 IntSize size = pixelSnappedIntRect(frameRect()).size(); |
| 366 HTMLSelectElement* select = selectElement(); | 355 HTMLSelectElement* select = selectElement(); |
| 367 m_popup->show(quad, size, select->optionToListIndex(select->selectedIndex())
); | 356 m_popup->show(quad, size, select->optionToListIndex(select->selectedIndex())
); |
| 368 if (AXObjectCache* cache = document().existingAXObjectCache()) | 357 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 369 cache->didShowMenuListPopup(this); | 358 cache->didShowMenuListPopup(this); |
| 370 | |
| 371 } | 359 } |
| 372 | 360 |
| 373 void LayoutMenuList::hidePopup() | 361 void LayoutMenuList::hidePopup() |
| 374 { | 362 { |
| 375 if (m_popup) | 363 if (m_popup) |
| 376 m_popup->hide(); | 364 m_popup->hide(); |
| 377 } | 365 } |
| 378 | 366 |
| 379 void LayoutMenuList::valueChanged(unsigned listIndex, bool fireOnChange) | 367 void LayoutMenuList::valueChanged(unsigned listIndex, bool fireOnChange) |
| 380 { | 368 { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 return; | 416 return; |
| 429 | 417 |
| 430 if (m_lastActiveIndex == optionIndex) | 418 if (m_lastActiveIndex == optionIndex) |
| 431 return; | 419 return; |
| 432 m_lastActiveIndex = optionIndex; | 420 m_lastActiveIndex = optionIndex; |
| 433 | 421 |
| 434 HTMLSelectElement* select = selectElement(); | 422 HTMLSelectElement* select = selectElement(); |
| 435 int listIndex = select->optionToListIndex(optionIndex); | 423 int listIndex = select->optionToListIndex(optionIndex); |
| 436 if (listIndex < 0 || listIndex >= static_cast<int>(select->listItems().size(
))) | 424 if (listIndex < 0 || listIndex >= static_cast<int>(select->listItems().size(
))) |
| 437 return; | 425 return; |
| 426 |
| 427 // We skip sending accessiblity notifications for the very first option, oth
erwise |
| 428 // we get extra focus and select events that are undesired. |
| 429 if (!m_hasUpdatedActiveOption) { |
| 430 m_hasUpdatedActiveOption = true; |
| 431 return; |
| 432 } |
| 433 |
| 438 document().existingAXObjectCache()->handleUpdateActiveMenuOption(this, optio
nIndex); | 434 document().existingAXObjectCache()->handleUpdateActiveMenuOption(this, optio
nIndex); |
| 439 } | 435 } |
| 440 | 436 |
| 441 String LayoutMenuList::itemText(unsigned listIndex) const | 437 String LayoutMenuList::itemText(unsigned listIndex) const |
| 442 { | 438 { |
| 443 HTMLSelectElement* select = selectElement(); | 439 HTMLSelectElement* select = selectElement(); |
| 444 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = select-
>listItems(); | 440 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = select-
>listItems(); |
| 445 if (listIndex >= listItems.size()) | 441 if (listIndex >= listItems.size()) |
| 446 return String(); | 442 return String(); |
| 447 | 443 |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 HTMLElement* element = listItems[listIndex]; | 619 HTMLElement* element = listItems[listIndex]; |
| 624 return isHTMLOptionElement(*element) && toHTMLOptionElement(*element).select
ed(); | 620 return isHTMLOptionElement(*element) && toHTMLOptionElement(*element).select
ed(); |
| 625 } | 621 } |
| 626 | 622 |
| 627 void LayoutMenuList::provisionalSelectionChanged(unsigned listIndex) | 623 void LayoutMenuList::provisionalSelectionChanged(unsigned listIndex) |
| 628 { | 624 { |
| 629 setIndexToSelectOnCancel(listIndex); | 625 setIndexToSelectOnCancel(listIndex); |
| 630 } | 626 } |
| 631 | 627 |
| 632 } // namespace blink | 628 } // namespace blink |
| OLD | NEW |