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

Unified Diff: Source/core/rendering/RenderMenuList.cpp

Issue 966883002: renderer/RenderMenuList.* -> layout/LayoutMenuList.* (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Remove OWNERS, allowing Source/core/rendering to be deleted. Created 5 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/RenderMenuList.h ('k') | Source/core/testing/Internals.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/RenderMenuList.cpp
diff --git a/Source/core/rendering/RenderMenuList.cpp b/Source/core/rendering/RenderMenuList.cpp
deleted file mode 100644
index 7e42cd3570d2eedf730487caf431000d45dff3fc..0000000000000000000000000000000000000000
--- a/Source/core/rendering/RenderMenuList.cpp
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * This file is part of the select element renderer in WebCore.
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
- * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "core/rendering/RenderMenuList.h"
-
-#include "core/HTMLNames.h"
-#include "core/css/CSSFontSelector.h"
-#include "core/css/resolver/StyleResolver.h"
-#include "core/dom/AXObjectCache.h"
-#include "core/dom/NodeLayoutStyle.h"
-#include "core/frame/FrameHost.h"
-#include "core/frame/FrameView.h"
-#include "core/frame/LocalFrame.h"
-#include "core/frame/Settings.h"
-#include "core/html/HTMLOptGroupElement.h"
-#include "core/html/HTMLOptionElement.h"
-#include "core/html/HTMLSelectElement.h"
-#include "core/layout/LayoutBR.h"
-#include "core/layout/LayoutScrollbar.h"
-#include "core/layout/LayoutTheme.h"
-#include "core/layout/LayoutView.h"
-#include "core/page/Chrome.h"
-#include "platform/fonts/FontCache.h"
-#include "platform/geometry/IntSize.h"
-#include "platform/text/PlatformLocale.h"
-#include <math.h>
-
-namespace blink {
-
-using namespace HTMLNames;
-
-RenderMenuList::RenderMenuList(Element* element)
- : LayoutFlexibleBox(element)
- , m_buttonText(nullptr)
- , m_innerBlock(nullptr)
- , m_optionsChanged(true)
- , m_optionsWidth(0)
- , m_lastActiveIndex(-1)
- , m_popupIsVisible(false)
-{
- ASSERT(isHTMLSelectElement(element));
-}
-
-RenderMenuList::~RenderMenuList()
-{
- ASSERT(!m_popup);
-}
-
-void RenderMenuList::destroy()
-{
- if (m_popup)
- m_popup->disconnectClient();
- m_popup = nullptr;
- LayoutFlexibleBox::destroy();
-}
-
-// FIXME: Instead of this hack we should add a ShadowRoot to <select> with no insertion point
-// to prevent children from rendering.
-bool RenderMenuList::isChildAllowed(LayoutObject* object, const LayoutStyle&) const
-{
- return object->isAnonymous() && !object->isLayoutFullScreen();
-}
-
-void RenderMenuList::createInnerBlock()
-{
- if (m_innerBlock) {
- ASSERT(firstChild() == m_innerBlock);
- ASSERT(!m_innerBlock->nextSibling());
- return;
- }
-
- // Create an anonymous block.
- ASSERT(!firstChild());
- m_innerBlock = createAnonymousBlock();
- adjustInnerStyle();
- LayoutFlexibleBox::addChild(m_innerBlock);
-}
-
-void RenderMenuList::adjustInnerStyle()
-{
- LayoutStyle& innerStyle = m_innerBlock->mutableStyleRef();
- innerStyle.setFlexGrow(1);
- innerStyle.setFlexShrink(1);
- // Use margin:auto instead of align-items:center to get safe centering, i.e.
- // when the content overflows, treat it the same as align-items: flex-start.
- // But we only do that for the cases where html.css would otherwise use center.
- if (style()->alignItems() == ItemPositionCenter) {
- innerStyle.setMarginTop(Length());
- innerStyle.setMarginBottom(Length());
- innerStyle.setAlignSelf(ItemPositionFlexStart);
- }
-
- innerStyle.setPaddingLeft(Length(LayoutTheme::theme().popupInternalPaddingLeft(styleRef()), Fixed));
- innerStyle.setPaddingRight(Length(LayoutTheme::theme().popupInternalPaddingRight(styleRef()), Fixed));
- innerStyle.setPaddingTop(Length(LayoutTheme::theme().popupInternalPaddingTop(styleRef()), Fixed));
- innerStyle.setPaddingBottom(Length(LayoutTheme::theme().popupInternalPaddingBottom(styleRef()), Fixed));
-
- if (m_optionStyle) {
- if ((m_optionStyle->direction() != innerStyle.direction() || m_optionStyle->unicodeBidi() != innerStyle.unicodeBidi()))
- m_innerBlock->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
- innerStyle.setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT);
- innerStyle.setDirection(m_optionStyle->direction());
- innerStyle.setUnicodeBidi(m_optionStyle->unicodeBidi());
- }
-}
-
-inline HTMLSelectElement* RenderMenuList::selectElement() const
-{
- return toHTMLSelectElement(node());
-}
-
-void RenderMenuList::addChild(LayoutObject* newChild, LayoutObject* beforeChild)
-{
- createInnerBlock();
- m_innerBlock->addChild(newChild, beforeChild);
- ASSERT(m_innerBlock == firstChild());
-
- if (AXObjectCache* cache = document().existingAXObjectCache())
- cache->childrenChanged(this);
-}
-
-void RenderMenuList::removeChild(LayoutObject* oldChild)
-{
- if (oldChild == m_innerBlock || !m_innerBlock) {
- LayoutFlexibleBox::removeChild(oldChild);
- m_innerBlock = nullptr;
- } else
- m_innerBlock->removeChild(oldChild);
-}
-
-void RenderMenuList::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyle)
-{
- LayoutBlock::styleDidChange(diff, oldStyle);
-
- if (m_buttonText)
- m_buttonText->setStyle(style());
- if (m_innerBlock) // LayoutBlock handled updating the anonymous block's style.
- adjustInnerStyle();
-
- bool fontChanged = !oldStyle || oldStyle->font() != style()->font();
- if (fontChanged)
- updateOptionsWidth();
-}
-
-void RenderMenuList::updateOptionsWidth()
-{
- float maxOptionWidth = 0;
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- int size = listItems.size();
-
- for (int i = 0; i < size; ++i) {
- HTMLElement* element = listItems[i];
- if (!isHTMLOptionElement(*element))
- continue;
-
- String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
- applyTextTransform(style(), text, ' ');
- if (LayoutTheme::theme().popupOptionSupportsTextIndent()) {
- // Add in the option's text indent. We can't calculate percentage values for now.
- float optionWidth = 0;
- if (const LayoutStyle* optionStyle = element->layoutStyle())
- optionWidth += minimumValueForLength(optionStyle->textIndent(), 0);
- if (!text.isEmpty())
- optionWidth += style()->font().width(text);
- maxOptionWidth = std::max(maxOptionWidth, optionWidth);
- } else if (!text.isEmpty()) {
- maxOptionWidth = std::max(maxOptionWidth, style()->font().width(text));
- }
- }
-
- int width = static_cast<int>(ceilf(maxOptionWidth));
- if (m_optionsWidth == width)
- return;
-
- m_optionsWidth = width;
- if (parent())
- setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
-}
-
-void RenderMenuList::updateFromElement()
-{
- if (m_optionsChanged) {
- updateOptionsWidth();
- m_optionsChanged = false;
- }
-
- if (m_popupIsVisible)
- m_popup->updateFromElement();
-
- if (selectElement()->suggestedIndex() >= 0)
- setTextFromOption(selectElement()->suggestedIndex());
- else
- setTextFromOption(selectElement()->selectedIndex());
-}
-
-void RenderMenuList::setTextFromOption(int optionIndex)
-{
- HTMLSelectElement* select = selectElement();
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems();
- const int size = listItems.size();
-
- String text = emptyString();
- m_optionStyle.clear();
-
- if (multiple()) {
- unsigned selectedCount = 0;
- int firstSelectedIndex = -1;
- for (int i = 0; i < size; ++i) {
- Element* element = listItems[i];
- if (!isHTMLOptionElement(*element))
- continue;
-
- if (toHTMLOptionElement(element)->selected()) {
- if (++selectedCount == 1)
- firstSelectedIndex = i;
- }
- }
-
- if (selectedCount == 1) {
- ASSERT(0 <= firstSelectedIndex);
- ASSERT(firstSelectedIndex < size);
- HTMLOptionElement* selectedOptionElement = toHTMLOptionElement(listItems[firstSelectedIndex]);
- ASSERT(selectedOptionElement->selected());
- text = selectedOptionElement->textIndentedToRespectGroupLabel();
- m_optionStyle = selectedOptionElement->layoutStyle();
- } else {
- Locale& locale = select->locale();
- String localizedNumberString = locale.convertToLocalizedNumber(String::number(selectedCount));
- text = locale.queryString(WebLocalizedString::SelectMenuListText, localizedNumberString);
- ASSERT(!m_optionStyle);
- }
- } else {
- const int i = select->optionToListIndex(optionIndex);
- if (i >= 0 && i < size) {
- Element* element = listItems[i];
- if (isHTMLOptionElement(*element)) {
- text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
- m_optionStyle = element->layoutStyle();
- }
- }
- }
-
- setText(text.stripWhiteSpace());
-
- didUpdateActiveOption(optionIndex);
-}
-
-void RenderMenuList::setText(const String& s)
-{
- if (s.isEmpty()) {
- if (!m_buttonText || !m_buttonText->isBR()) {
- // FIXME: We should not modify the structure of the render tree
- // during layout. crbug.com/370462
- DeprecatedDisableModifyRenderTreeStructureAsserts disabler;
- if (m_buttonText)
- m_buttonText->destroy();
- m_buttonText = new LayoutBR(&document());
- m_buttonText->setStyle(style());
- addChild(m_buttonText);
- }
- } else {
- if (m_buttonText && !m_buttonText->isBR())
- m_buttonText->setText(s.impl(), true);
- else {
- // FIXME: We should not modify the structure of the render tree
- // during layout. crbug.com/370462
- DeprecatedDisableModifyRenderTreeStructureAsserts disabler;
- if (m_buttonText)
- m_buttonText->destroy();
- m_buttonText = new LayoutText(&document(), s.impl());
- m_buttonText->setStyle(style());
- // We need to set the text explicitly though it was specified in the
- // constructor because LayoutText doesn't refer to the text
- // specified in the constructor in a case of re-transforming.
- m_buttonText->setText(s.impl(), true);
- addChild(m_buttonText);
- }
- adjustInnerStyle();
- }
-}
-
-String RenderMenuList::text() const
-{
- return m_buttonText ? m_buttonText->text() : String();
-}
-
-LayoutRect RenderMenuList::controlClipRect(const LayoutPoint& additionalOffset) const
-{
- // Clip to the intersection of the content box and the content box for the inner box
- // This will leave room for the arrows which sit in the inner box padding,
- // and if the inner box ever spills out of the outer box, that will get clipped too.
- LayoutRect outerBox = contentBoxRect();
- outerBox.moveBy(additionalOffset);
-
- LayoutRect innerBox(additionalOffset + m_innerBlock->location()
- + LayoutSize(m_innerBlock->paddingLeft(), m_innerBlock->paddingTop())
- , m_innerBlock->contentSize());
-
- return intersection(outerBox, innerBox);
-}
-
-void RenderMenuList::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
-{
- maxLogicalWidth = std::max(m_optionsWidth, LayoutTheme::theme().minimumMenuListSize(styleRef())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight();
- if (!style()->width().isPercent())
- minLogicalWidth = maxLogicalWidth;
-}
-
-void RenderMenuList::showPopup()
-{
- if (m_popupIsVisible)
- return;
-
- if (document().frameHost()->chrome().hasOpenedPopup())
- return;
-
- // Create m_innerBlock here so it ends up as the first child.
- // This is important because otherwise we might try to create m_innerBlock
- // inside the showPopup call and it would fail.
- createInnerBlock();
- if (!m_popup)
- m_popup = document().frameHost()->chrome().createPopupMenu(*document().frame(), this);
- m_popupIsVisible = true;
-
- FloatQuad quad(localToAbsoluteQuad(FloatQuad(borderBoundingBox())));
- IntSize size = pixelSnappedIntRect(frameRect()).size();
- HTMLSelectElement* select = selectElement();
- m_popup->show(quad, size, select->optionToListIndex(select->selectedIndex()));
-}
-
-void RenderMenuList::hidePopup()
-{
- if (m_popup)
- m_popup->hide();
-}
-
-void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
-{
- // Check to ensure a page navigation has not occurred while
- // the popup was up.
- Document& doc = toElement(node())->document();
- if (&doc != doc.frame()->document())
- return;
-
- HTMLSelectElement* select = selectElement();
- select->optionSelectedByUser(select->listToOptionIndex(listIndex), fireOnChange);
-}
-
-void RenderMenuList::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow)
-{
- selectElement()->listBoxSelectItem(listIndex, allowMultiplySelections, shift, fireOnChangeNow);
-}
-
-bool RenderMenuList::multiple() const
-{
- return selectElement()->multiple();
-}
-
-IntRect RenderMenuList::elementRectRelativeToViewport() const
-{
- return selectElement()->document().view()->contentsToWindow(absoluteBoundingBoxRect());
-}
-
-Element& RenderMenuList::ownerElement() const
-{
- return *selectElement();
-}
-
-const LayoutStyle* RenderMenuList::layoutStyleForItem(Element& element) const
-{
- document().updateRenderTreeIfNeeded();
- return element.layoutStyle() ? element.layoutStyle() : element.computedStyle();
-}
-
-void RenderMenuList::didSetSelectedIndex(int listIndex)
-{
- didUpdateActiveOption(selectElement()->listToOptionIndex(listIndex));
-}
-
-void RenderMenuList::didUpdateActiveOption(int optionIndex)
-{
- if (!document().existingAXObjectCache())
- return;
-
- if (m_lastActiveIndex == optionIndex)
- return;
- m_lastActiveIndex = optionIndex;
-
- HTMLSelectElement* select = selectElement();
- int listIndex = select->optionToListIndex(optionIndex);
- if (listIndex < 0 || listIndex >= static_cast<int>(select->listItems().size()))
- return;
- document().existingAXObjectCache()->handleUpdateActiveMenuOption(this, optionIndex);
-}
-
-String RenderMenuList::itemText(unsigned listIndex) const
-{
- HTMLSelectElement* select = selectElement();
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems();
- if (listIndex >= listItems.size())
- return String();
-
- String itemString;
- Element* element = listItems[listIndex];
- if (isHTMLOptGroupElement(*element))
- itemString = toHTMLOptGroupElement(*element).groupLabelText();
- else if (isHTMLOptionElement(*element))
- itemString = toHTMLOptionElement(*element).textIndentedToRespectGroupLabel();
-
- applyTextTransform(style(), itemString, ' ');
- return itemString;
-}
-
-String RenderMenuList::itemAccessibilityText(unsigned listIndex) const
-{
- // Allow the accessible name be changed if necessary.
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- if (listIndex >= listItems.size())
- return String();
- return listItems[listIndex]->fastGetAttribute(aria_labelAttr);
-}
-
-String RenderMenuList::itemToolTip(unsigned listIndex) const
-{
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- if (listIndex >= listItems.size())
- return String();
- return listItems[listIndex]->title();
-}
-
-bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
-{
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- if (listIndex >= listItems.size())
- return false;
- HTMLElement* element = listItems[listIndex];
- if (!isHTMLOptionElement(*element))
- return false;
-
- bool groupEnabled = true;
- if (Element* parentElement = element->parentElement()) {
- if (isHTMLOptGroupElement(*parentElement))
- groupEnabled = !parentElement->isDisabledFormControl();
- }
- if (!groupEnabled)
- return false;
-
- return !element->isDisabledFormControl();
-}
-
-PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
-{
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- if (listIndex >= listItems.size()) {
- // If we are making an out of bounds access, then we want to use the style
- // of a different option element (index 0). However, if there isn't an option element
- // before at index 0, we fall back to the menu's style.
- if (!listIndex)
- return menuStyle();
-
- // Try to retrieve the style of an option element we know exists (index 0).
- listIndex = 0;
- }
- HTMLElement* element = listItems[listIndex];
-
- Color itemBackgroundColor;
- bool itemHasCustomBackgroundColor;
- getItemBackgroundColor(listIndex, itemBackgroundColor, itemHasCustomBackgroundColor);
-
- const LayoutStyle* style = element->layoutStyle() ? element->layoutStyle() : element->computedStyle();
- return style ? PopupMenuStyle(resolveColor(*style, CSSPropertyColor), itemBackgroundColor, style->font(), style->visibility() == VISIBLE,
- isHTMLOptionElement(*element) ? toHTMLOptionElement(*element).isDisplayNone() : style->display() == NONE,
- style->textIndent(), style->direction(), isOverride(style->unicodeBidi()),
- itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : PopupMenuStyle::DefaultBackgroundColor) : menuStyle();
-}
-
-void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackgroundColor, bool& itemHasCustomBackgroundColor) const
-{
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- if (listIndex >= listItems.size()) {
- itemBackgroundColor = resolveColor(CSSPropertyBackgroundColor);
- itemHasCustomBackgroundColor = false;
- return;
- }
- HTMLElement* element = listItems[listIndex];
-
- Color backgroundColor;
- if (const LayoutStyle* style = element->layoutStyle())
- backgroundColor = resolveColor(*style, CSSPropertyBackgroundColor);
- itemHasCustomBackgroundColor = backgroundColor.alpha();
- // If the item has an opaque background color, return that.
- if (!backgroundColor.hasAlpha()) {
- itemBackgroundColor = backgroundColor;
- return;
- }
-
- // Otherwise, the item's background is overlayed on top of the menu background.
- backgroundColor = resolveColor(CSSPropertyBackgroundColor).blend(backgroundColor);
- if (!backgroundColor.hasAlpha()) {
- itemBackgroundColor = backgroundColor;
- return;
- }
-
- // If the menu background is not opaque, then add an opaque white background behind.
- itemBackgroundColor = Color(Color::white).blend(backgroundColor);
-}
-
-PopupMenuStyle RenderMenuList::menuStyle() const
-{
- const LayoutObject* o = m_innerBlock ? m_innerBlock : this;
- const LayoutStyle& style = o->styleRef();
- return PopupMenuStyle(o->resolveColor(CSSPropertyColor), o->resolveColor(CSSPropertyBackgroundColor), style.font(), style.visibility() == VISIBLE,
- style.display() == NONE, style.textIndent(), style.direction(), isOverride(style.unicodeBidi()));
-}
-
-LayoutUnit RenderMenuList::clientPaddingLeft() const
-{
- return paddingLeft() + m_innerBlock->paddingLeft();
-}
-
-const int endOfLinePadding = 2;
-LayoutUnit RenderMenuList::clientPaddingRight() const
-{
- if (style()->appearance() == MenulistPart || style()->appearance() == MenulistButtonPart) {
- // For these appearance values, the theme applies padding to leave room for the
- // drop-down button. But leaving room for the button inside the popup menu itself
- // looks strange, so we return a small default padding to avoid having a large empty
- // space appear on the side of the popup menu.
- return endOfLinePadding;
- }
-
- // If the appearance isn't MenulistPart, then the select is styled (non-native), so
- // we want to return the user specified padding.
- return paddingRight() + m_innerBlock->paddingRight();
-}
-
-int RenderMenuList::listSize() const
-{
- return selectElement()->listItems().size();
-}
-
-int RenderMenuList::selectedIndex() const
-{
- HTMLSelectElement* select = selectElement();
- return select->optionToListIndex(select->selectedIndex());
-}
-
-void RenderMenuList::popupDidHide()
-{
- m_popupIsVisible = false;
-}
-
-bool RenderMenuList::itemIsSeparator(unsigned listIndex) const
-{
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- return listIndex < listItems.size() && isHTMLHRElement(*listItems[listIndex]);
-}
-
-bool RenderMenuList::itemIsLabel(unsigned listIndex) const
-{
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- return listIndex < listItems.size() && isHTMLOptGroupElement(*listItems[listIndex]);
-}
-
-bool RenderMenuList::itemIsSelected(unsigned listIndex) const
-{
- const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
- if (listIndex >= listItems.size())
- return false;
- HTMLElement* element = listItems[listIndex];
- return isHTMLOptionElement(*element) && toHTMLOptionElement(*element).selected();
-}
-
-void RenderMenuList::setTextFromItem(unsigned listIndex)
-{
- setTextFromOption(selectElement()->listToOptionIndex(listIndex));
-}
-
-} // namespace blink
« no previous file with comments | « Source/core/rendering/RenderMenuList.h ('k') | Source/core/testing/Internals.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698