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