OLD | NEW |
1 /* | 1 /* |
2 * This file is part of the select element renderer in WebCore. | 2 * This file is part of the select element renderer 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 11 matching lines...) Expand all Loading... |
22 * | 22 * |
23 */ | 23 */ |
24 | 24 |
25 #include "config.h" | 25 #include "config.h" |
26 #include "core/layout/LayoutMenuList.h" | 26 #include "core/layout/LayoutMenuList.h" |
27 | 27 |
28 #include "core/HTMLNames.h" | 28 #include "core/HTMLNames.h" |
29 #include "core/css/CSSFontSelector.h" | 29 #include "core/css/CSSFontSelector.h" |
30 #include "core/css/resolver/StyleResolver.h" | 30 #include "core/css/resolver/StyleResolver.h" |
31 #include "core/dom/AXObjectCache.h" | 31 #include "core/dom/AXObjectCache.h" |
32 #include "core/dom/NodeLayoutStyle.h" | 32 #include "core/dom/NodeComputedStyle.h" |
33 #include "core/frame/FrameHost.h" | 33 #include "core/frame/FrameHost.h" |
34 #include "core/frame/FrameView.h" | 34 #include "core/frame/FrameView.h" |
35 #include "core/frame/LocalFrame.h" | 35 #include "core/frame/LocalFrame.h" |
36 #include "core/frame/Settings.h" | 36 #include "core/frame/Settings.h" |
37 #include "core/html/HTMLOptGroupElement.h" | 37 #include "core/html/HTMLOptGroupElement.h" |
38 #include "core/html/HTMLOptionElement.h" | 38 #include "core/html/HTMLOptionElement.h" |
39 #include "core/html/HTMLSelectElement.h" | 39 #include "core/html/HTMLSelectElement.h" |
40 #include "core/layout/LayoutBR.h" | 40 #include "core/layout/LayoutBR.h" |
41 #include "core/layout/LayoutScrollbar.h" | 41 #include "core/layout/LayoutScrollbar.h" |
42 #include "core/layout/LayoutTheme.h" | 42 #include "core/layout/LayoutTheme.h" |
(...skipping 28 matching lines...) Expand all Loading... |
71 void LayoutMenuList::destroy() | 71 void LayoutMenuList::destroy() |
72 { | 72 { |
73 if (m_popup) | 73 if (m_popup) |
74 m_popup->disconnectClient(); | 74 m_popup->disconnectClient(); |
75 m_popup = nullptr; | 75 m_popup = nullptr; |
76 LayoutFlexibleBox::destroy(); | 76 LayoutFlexibleBox::destroy(); |
77 } | 77 } |
78 | 78 |
79 // FIXME: Instead of this hack we should add a ShadowRoot to <select> with no in
sertion point | 79 // FIXME: Instead of this hack we should add a ShadowRoot to <select> with no in
sertion point |
80 // to prevent children from rendering. | 80 // to prevent children from rendering. |
81 bool LayoutMenuList::isChildAllowed(LayoutObject* object, const LayoutStyle&) co
nst | 81 bool LayoutMenuList::isChildAllowed(LayoutObject* object, const ComputedStyle&)
const |
82 { | 82 { |
83 return object->isAnonymous() && !object->isLayoutFullScreen(); | 83 return object->isAnonymous() && !object->isLayoutFullScreen(); |
84 } | 84 } |
85 | 85 |
86 void LayoutMenuList::createInnerBlock() | 86 void LayoutMenuList::createInnerBlock() |
87 { | 87 { |
88 if (m_innerBlock) { | 88 if (m_innerBlock) { |
89 ASSERT(firstChild() == m_innerBlock); | 89 ASSERT(firstChild() == m_innerBlock); |
90 ASSERT(!m_innerBlock->nextSibling()); | 90 ASSERT(!m_innerBlock->nextSibling()); |
91 return; | 91 return; |
92 } | 92 } |
93 | 93 |
94 // Create an anonymous block. | 94 // Create an anonymous block. |
95 ASSERT(!firstChild()); | 95 ASSERT(!firstChild()); |
96 m_innerBlock = createAnonymousBlock(); | 96 m_innerBlock = createAnonymousBlock(); |
97 adjustInnerStyle(); | 97 adjustInnerStyle(); |
98 LayoutFlexibleBox::addChild(m_innerBlock); | 98 LayoutFlexibleBox::addChild(m_innerBlock); |
99 } | 99 } |
100 | 100 |
101 void LayoutMenuList::adjustInnerStyle() | 101 void LayoutMenuList::adjustInnerStyle() |
102 { | 102 { |
103 LayoutStyle& innerStyle = m_innerBlock->mutableStyleRef(); | 103 ComputedStyle& innerStyle = m_innerBlock->mutableStyleRef(); |
104 innerStyle.setFlexGrow(1); | 104 innerStyle.setFlexGrow(1); |
105 innerStyle.setFlexShrink(1); | 105 innerStyle.setFlexShrink(1); |
106 // Use margin:auto instead of align-items:center to get safe centering, i.e. | 106 // Use margin:auto instead of align-items:center to get safe centering, i.e. |
107 // when the content overflows, treat it the same as align-items: flex-start. | 107 // when the content overflows, treat it the same as align-items: flex-start. |
108 // But we only do that for the cases where html.css would otherwise use cent
er. | 108 // But we only do that for the cases where html.css would otherwise use cent
er. |
109 if (style()->alignItems() == ItemPositionCenter) { | 109 if (style()->alignItems() == ItemPositionCenter) { |
110 innerStyle.setMarginTop(Length()); | 110 innerStyle.setMarginTop(Length()); |
111 innerStyle.setMarginBottom(Length()); | 111 innerStyle.setMarginBottom(Length()); |
112 innerStyle.setAlignSelf(ItemPositionFlexStart); | 112 innerStyle.setAlignSelf(ItemPositionFlexStart); |
113 } | 113 } |
(...skipping 30 matching lines...) Expand all Loading... |
144 void LayoutMenuList::removeChild(LayoutObject* oldChild) | 144 void LayoutMenuList::removeChild(LayoutObject* oldChild) |
145 { | 145 { |
146 if (oldChild == m_innerBlock || !m_innerBlock) { | 146 if (oldChild == m_innerBlock || !m_innerBlock) { |
147 LayoutFlexibleBox::removeChild(oldChild); | 147 LayoutFlexibleBox::removeChild(oldChild); |
148 m_innerBlock = nullptr; | 148 m_innerBlock = nullptr; |
149 } else { | 149 } else { |
150 m_innerBlock->removeChild(oldChild); | 150 m_innerBlock->removeChild(oldChild); |
151 } | 151 } |
152 } | 152 } |
153 | 153 |
154 void LayoutMenuList::styleDidChange(StyleDifference diff, const LayoutStyle* old
Style) | 154 void LayoutMenuList::styleDidChange(StyleDifference diff, const ComputedStyle* o
ldStyle) |
155 { | 155 { |
156 LayoutBlock::styleDidChange(diff, oldStyle); | 156 LayoutBlock::styleDidChange(diff, oldStyle); |
157 | 157 |
158 if (m_buttonText) | 158 if (m_buttonText) |
159 m_buttonText->setStyle(style()); | 159 m_buttonText->setStyle(style()); |
160 if (m_innerBlock) // LayoutBlock handled updating the anonymous block's styl
e. | 160 if (m_innerBlock) // LayoutBlock handled updating the anonymous block's styl
e. |
161 adjustInnerStyle(); | 161 adjustInnerStyle(); |
162 | 162 |
163 bool fontChanged = !oldStyle || oldStyle->font() != style()->font(); | 163 bool fontChanged = !oldStyle || oldStyle->font() != style()->font(); |
164 if (fontChanged) | 164 if (fontChanged) |
165 updateOptionsWidth(); | 165 updateOptionsWidth(); |
166 } | 166 } |
167 | 167 |
168 void LayoutMenuList::updateOptionsWidth() | 168 void LayoutMenuList::updateOptionsWidth() |
169 { | 169 { |
170 float maxOptionWidth = 0; | 170 float maxOptionWidth = 0; |
171 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = selectE
lement()->listItems(); | 171 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = selectE
lement()->listItems(); |
172 int size = listItems.size(); | 172 int size = listItems.size(); |
173 | 173 |
174 for (int i = 0; i < size; ++i) { | 174 for (int i = 0; i < size; ++i) { |
175 HTMLElement* element = listItems[i]; | 175 HTMLElement* element = listItems[i]; |
176 if (!isHTMLOptionElement(*element)) | 176 if (!isHTMLOptionElement(*element)) |
177 continue; | 177 continue; |
178 | 178 |
179 String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLa
bel(); | 179 String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLa
bel(); |
180 applyTextTransform(style(), text, ' '); | 180 applyTextTransform(style(), text, ' '); |
181 if (LayoutTheme::theme().popupOptionSupportsTextIndent()) { | 181 if (LayoutTheme::theme().popupOptionSupportsTextIndent()) { |
182 // Add in the option's text indent. We can't calculate percentage v
alues for now. | 182 // Add in the option's text indent. We can't calculate percentage v
alues for now. |
183 float optionWidth = 0; | 183 float optionWidth = 0; |
184 if (const LayoutStyle* optionStyle = element->layoutStyle()) | 184 if (const ComputedStyle* optionStyle = element->computedStyle()) |
185 optionWidth += minimumValueForLength(optionStyle->textIndent(),
0); | 185 optionWidth += minimumValueForLength(optionStyle->textIndent(),
0); |
186 if (!text.isEmpty()) | 186 if (!text.isEmpty()) |
187 optionWidth += style()->font().width(text); | 187 optionWidth += style()->font().width(text); |
188 maxOptionWidth = std::max(maxOptionWidth, optionWidth); | 188 maxOptionWidth = std::max(maxOptionWidth, optionWidth); |
189 } else if (!text.isEmpty()) { | 189 } else if (!text.isEmpty()) { |
190 maxOptionWidth = std::max(maxOptionWidth, style()->font().width(text
)); | 190 maxOptionWidth = std::max(maxOptionWidth, style()->font().width(text
)); |
191 } | 191 } |
192 } | 192 } |
193 | 193 |
194 int width = static_cast<int>(ceilf(maxOptionWidth)); | 194 int width = static_cast<int>(ceilf(maxOptionWidth)); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 firstSelectedIndex = i; | 238 firstSelectedIndex = i; |
239 } | 239 } |
240 } | 240 } |
241 | 241 |
242 if (selectedCount == 1) { | 242 if (selectedCount == 1) { |
243 ASSERT(0 <= firstSelectedIndex); | 243 ASSERT(0 <= firstSelectedIndex); |
244 ASSERT(firstSelectedIndex < size); | 244 ASSERT(firstSelectedIndex < size); |
245 HTMLOptionElement* selectedOptionElement = toHTMLOptionElement(listI
tems[firstSelectedIndex]); | 245 HTMLOptionElement* selectedOptionElement = toHTMLOptionElement(listI
tems[firstSelectedIndex]); |
246 ASSERT(selectedOptionElement->selected()); | 246 ASSERT(selectedOptionElement->selected()); |
247 text = selectedOptionElement->textIndentedToRespectGroupLabel(); | 247 text = selectedOptionElement->textIndentedToRespectGroupLabel(); |
248 m_optionStyle = selectedOptionElement->mutableLayoutStyle(); | 248 m_optionStyle = selectedOptionElement->mutableComputedStyle(); |
249 } else { | 249 } else { |
250 Locale& locale = select->locale(); | 250 Locale& locale = select->locale(); |
251 String localizedNumberString = locale.convertToLocalizedNumber(Strin
g::number(selectedCount)); | 251 String localizedNumberString = locale.convertToLocalizedNumber(Strin
g::number(selectedCount)); |
252 text = locale.queryString(WebLocalizedString::SelectMenuListText, lo
calizedNumberString); | 252 text = locale.queryString(WebLocalizedString::SelectMenuListText, lo
calizedNumberString); |
253 ASSERT(!m_optionStyle); | 253 ASSERT(!m_optionStyle); |
254 } | 254 } |
255 } else { | 255 } else { |
256 const int i = select->optionToListIndex(optionIndex); | 256 const int i = select->optionToListIndex(optionIndex); |
257 if (i >= 0 && i < size) { | 257 if (i >= 0 && i < size) { |
258 Element* element = listItems[i]; | 258 Element* element = listItems[i]; |
259 if (isHTMLOptionElement(*element)) { | 259 if (isHTMLOptionElement(*element)) { |
260 text = toHTMLOptionElement(element)->textIndentedToRespectGroupL
abel(); | 260 text = toHTMLOptionElement(element)->textIndentedToRespectGroupL
abel(); |
261 m_optionStyle = element->mutableLayoutStyle(); | 261 m_optionStyle = element->mutableComputedStyle(); |
262 } | 262 } |
263 } | 263 } |
264 } | 264 } |
265 | 265 |
266 setText(text.stripWhiteSpace()); | 266 setText(text.stripWhiteSpace()); |
267 | 267 |
268 didUpdateActiveOption(optionIndex); | 268 didUpdateActiveOption(optionIndex); |
269 } | 269 } |
270 | 270 |
271 void LayoutMenuList::setText(const String& s) | 271 void LayoutMenuList::setText(const String& s) |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 IntRect LayoutMenuList::elementRectRelativeToViewport() const | 385 IntRect LayoutMenuList::elementRectRelativeToViewport() const |
386 { | 386 { |
387 return selectElement()->document().view()->contentsToViewport(absoluteBoundi
ngBoxRect()); | 387 return selectElement()->document().view()->contentsToViewport(absoluteBoundi
ngBoxRect()); |
388 } | 388 } |
389 | 389 |
390 Element& LayoutMenuList::ownerElement() const | 390 Element& LayoutMenuList::ownerElement() const |
391 { | 391 { |
392 return *selectElement(); | 392 return *selectElement(); |
393 } | 393 } |
394 | 394 |
395 const LayoutStyle* LayoutMenuList::layoutStyleForItem(Element& element) const | 395 const ComputedStyle* LayoutMenuList::computedStyleForItem(Element& element) cons
t |
396 { | 396 { |
397 document().updateRenderTreeIfNeeded(); | 397 document().updateRenderTreeIfNeeded(); |
398 return element.layoutStyle() ? element.layoutStyle() : element.computedStyle
(); | 398 return element.computedStyle() ? element.computedStyle() : element.ensureCom
putedStyle(); |
399 } | 399 } |
400 | 400 |
401 void LayoutMenuList::didSetSelectedIndex(int listIndex) | 401 void LayoutMenuList::didSetSelectedIndex(int listIndex) |
402 { | 402 { |
403 didUpdateActiveOption(selectElement()->listToOptionIndex(listIndex)); | 403 didUpdateActiveOption(selectElement()->listToOptionIndex(listIndex)); |
404 } | 404 } |
405 | 405 |
406 void LayoutMenuList::didUpdateActiveOption(int optionIndex) | 406 void LayoutMenuList::didUpdateActiveOption(int optionIndex) |
407 { | 407 { |
408 if (!document().existingAXObjectCache()) | 408 if (!document().existingAXObjectCache()) |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 | 486 |
487 // Try to retrieve the style of an option element we know exists (index
0). | 487 // Try to retrieve the style of an option element we know exists (index
0). |
488 listIndex = 0; | 488 listIndex = 0; |
489 } | 489 } |
490 HTMLElement* element = listItems[listIndex]; | 490 HTMLElement* element = listItems[listIndex]; |
491 | 491 |
492 Color itemBackgroundColor; | 492 Color itemBackgroundColor; |
493 bool itemHasCustomBackgroundColor; | 493 bool itemHasCustomBackgroundColor; |
494 getItemBackgroundColor(listIndex, itemBackgroundColor, itemHasCustomBackgrou
ndColor); | 494 getItemBackgroundColor(listIndex, itemBackgroundColor, itemHasCustomBackgrou
ndColor); |
495 | 495 |
496 const LayoutStyle* style = element->layoutStyle() ? element->layoutStyle() :
element->computedStyle(); | 496 const ComputedStyle* style = element->computedStyle() ? element->computedSty
le() : element->ensureComputedStyle(); |
497 return style ? PopupMenuStyle(resolveColor(*style, CSSPropertyColor), itemBa
ckgroundColor, style->font(), style->visibility() == VISIBLE, | 497 return style ? PopupMenuStyle(resolveColor(*style, CSSPropertyColor), itemBa
ckgroundColor, style->font(), style->visibility() == VISIBLE, |
498 isHTMLOptionElement(*element) ? toHTMLOptionElement(*element).isDisplayN
one() : style->display() == NONE, | 498 isHTMLOptionElement(*element) ? toHTMLOptionElement(*element).isDisplayN
one() : style->display() == NONE, |
499 style->textIndent(), style->direction(), isOverride(style->unicodeBidi()
), | 499 style->textIndent(), style->direction(), isOverride(style->unicodeBidi()
), |
500 itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : P
opupMenuStyle::DefaultBackgroundColor) : menuStyle(); | 500 itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : P
opupMenuStyle::DefaultBackgroundColor) : menuStyle(); |
501 } | 501 } |
502 | 502 |
503 void LayoutMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackg
roundColor, bool& itemHasCustomBackgroundColor) const | 503 void LayoutMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackg
roundColor, bool& itemHasCustomBackgroundColor) const |
504 { | 504 { |
505 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = selectE
lement()->listItems(); | 505 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = selectE
lement()->listItems(); |
506 if (listIndex >= listItems.size()) { | 506 if (listIndex >= listItems.size()) { |
507 itemBackgroundColor = resolveColor(CSSPropertyBackgroundColor); | 507 itemBackgroundColor = resolveColor(CSSPropertyBackgroundColor); |
508 itemHasCustomBackgroundColor = false; | 508 itemHasCustomBackgroundColor = false; |
509 return; | 509 return; |
510 } | 510 } |
511 HTMLElement* element = listItems[listIndex]; | 511 HTMLElement* element = listItems[listIndex]; |
512 | 512 |
513 Color backgroundColor; | 513 Color backgroundColor; |
514 if (const LayoutStyle* style = element->layoutStyle()) | 514 if (const ComputedStyle* style = element->computedStyle()) |
515 backgroundColor = resolveColor(*style, CSSPropertyBackgroundColor); | 515 backgroundColor = resolveColor(*style, CSSPropertyBackgroundColor); |
516 itemHasCustomBackgroundColor = backgroundColor.alpha(); | 516 itemHasCustomBackgroundColor = backgroundColor.alpha(); |
517 // If the item has an opaque background color, return that. | 517 // If the item has an opaque background color, return that. |
518 if (!backgroundColor.hasAlpha()) { | 518 if (!backgroundColor.hasAlpha()) { |
519 itemBackgroundColor = backgroundColor; | 519 itemBackgroundColor = backgroundColor; |
520 return; | 520 return; |
521 } | 521 } |
522 | 522 |
523 // Otherwise, the item's background is overlayed on top of the menu backgrou
nd. | 523 // Otherwise, the item's background is overlayed on top of the menu backgrou
nd. |
524 backgroundColor = resolveColor(CSSPropertyBackgroundColor).blend(backgroundC
olor); | 524 backgroundColor = resolveColor(CSSPropertyBackgroundColor).blend(backgroundC
olor); |
525 if (!backgroundColor.hasAlpha()) { | 525 if (!backgroundColor.hasAlpha()) { |
526 itemBackgroundColor = backgroundColor; | 526 itemBackgroundColor = backgroundColor; |
527 return; | 527 return; |
528 } | 528 } |
529 | 529 |
530 // If the menu background is not opaque, then add an opaque white background
behind. | 530 // If the menu background is not opaque, then add an opaque white background
behind. |
531 itemBackgroundColor = Color(Color::white).blend(backgroundColor); | 531 itemBackgroundColor = Color(Color::white).blend(backgroundColor); |
532 } | 532 } |
533 | 533 |
534 PopupMenuStyle LayoutMenuList::menuStyle() const | 534 PopupMenuStyle LayoutMenuList::menuStyle() const |
535 { | 535 { |
536 const LayoutObject* o = m_innerBlock ? m_innerBlock : this; | 536 const LayoutObject* o = m_innerBlock ? m_innerBlock : this; |
537 const LayoutStyle& style = o->styleRef(); | 537 const ComputedStyle& style = o->styleRef(); |
538 return PopupMenuStyle(o->resolveColor(CSSPropertyColor), o->resolveColor(CSS
PropertyBackgroundColor), style.font(), style.visibility() == VISIBLE, | 538 return PopupMenuStyle(o->resolveColor(CSSPropertyColor), o->resolveColor(CSS
PropertyBackgroundColor), style.font(), style.visibility() == VISIBLE, |
539 style.display() == NONE, style.textIndent(), style.direction(), isOverri
de(style.unicodeBidi())); | 539 style.display() == NONE, style.textIndent(), style.direction(), isOverri
de(style.unicodeBidi())); |
540 } | 540 } |
541 | 541 |
542 LayoutUnit LayoutMenuList::clientPaddingLeft() const | 542 LayoutUnit LayoutMenuList::clientPaddingLeft() const |
543 { | 543 { |
544 return paddingLeft() + m_innerBlock->paddingLeft(); | 544 return paddingLeft() + m_innerBlock->paddingLeft(); |
545 } | 545 } |
546 | 546 |
547 const int endOfLinePadding = 2; | 547 const int endOfLinePadding = 2; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 HTMLElement* element = listItems[listIndex]; | 598 HTMLElement* element = listItems[listIndex]; |
599 return isHTMLOptionElement(*element) && toHTMLOptionElement(*element).select
ed(); | 599 return isHTMLOptionElement(*element) && toHTMLOptionElement(*element).select
ed(); |
600 } | 600 } |
601 | 601 |
602 void LayoutMenuList::setTextFromItem(unsigned listIndex) | 602 void LayoutMenuList::setTextFromItem(unsigned listIndex) |
603 { | 603 { |
604 setTextFromOption(selectElement()->listToOptionIndex(listIndex)); | 604 setTextFromOption(selectElement()->listToOptionIndex(listIndex)); |
605 } | 605 } |
606 | 606 |
607 } // namespace blink | 607 } // namespace blink |
OLD | NEW |