Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: Source/core/layout/LayoutMenuList.cpp

Issue 1150303003: [Reland] Setup LayoutMenuList to not modify layout tree outside style recalc. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/layout/LayoutMenuList.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « Source/core/layout/LayoutMenuList.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698