diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderMenuList.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderMenuList.cpp | 154 |
1 files changed, 78 insertions, 76 deletions
diff --git a/Source/WebCore/rendering/RenderMenuList.cpp b/Source/WebCore/rendering/RenderMenuList.cpp index f4d821a4a..de5fbc470 100644 --- a/Source/WebCore/rendering/RenderMenuList.cpp +++ b/Source/WebCore/rendering/RenderMenuList.cpp @@ -2,7 +2,7 @@ * 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. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2015 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 @@ -29,7 +29,6 @@ #include "AccessibilityMenuList.h" #include "CSSFontSelector.h" #include "Chrome.h" -#include "FontCache.h" #include "Frame.h" #include "FrameView.h" #include "HTMLNames.h" @@ -43,7 +42,6 @@ #include "RenderText.h" #include "RenderTheme.h" #include "RenderView.h" -#include "Settings.h" #include "StyleResolver.h" #include "TextRun.h" #include <math.h> @@ -64,15 +62,15 @@ static size_t selectedOptionCount(const RenderMenuList& renderMenuList) size_t count = 0; for (size_t i = 0; i < numberOfItems; ++i) { - if (listItems[i]->hasTagName(optionTag) && toHTMLOptionElement(listItems[i])->selected()) + if (is<HTMLOptionElement>(*listItems[i]) && downcast<HTMLOptionElement>(*listItems[i]).selected()) ++count; } return count; } #endif -RenderMenuList::RenderMenuList(HTMLSelectElement& element, PassRef<RenderStyle> style) - : RenderFlexibleBox(element, std::move(style)) +RenderMenuList::RenderMenuList(HTMLSelectElement& element, RenderStyle&& style) + : RenderFlexibleBox(element, WTFMove(style)) , m_buttonText(nullptr) , m_innerBlock(nullptr) , m_needsOptionsWidthUpdate(true) @@ -86,16 +84,18 @@ RenderMenuList::RenderMenuList(HTMLSelectElement& element, PassRef<RenderStyle> RenderMenuList::~RenderMenuList() { + // Do not add any code here. Add it to willBeDestroyed() instead. +} + +void RenderMenuList::willBeDestroyed() +{ #if !PLATFORM(IOS) if (m_popup) m_popup->disconnectClient(); - m_popup = 0; + m_popup = nullptr; #endif -} -bool RenderMenuList::canBeReplacedWithInlineRunIn() const -{ - return false; + RenderFlexibleBox::willBeDestroyed(); } void RenderMenuList::createInnerBlock() @@ -115,25 +115,21 @@ void RenderMenuList::createInnerBlock() void RenderMenuList::adjustInnerStyle() { - RenderStyle& innerStyle = m_innerBlock->style(); + auto& innerStyle = m_innerBlock->mutableStyle(); innerStyle.setFlexGrow(1); innerStyle.setFlexShrink(1); // min-width: 0; is needed for correct shrinking. - // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed. innerStyle.setMinWidth(Length(0, Fixed)); // 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() == AlignCenter) { + if (style().alignItems().position() == ItemPositionCenter) { innerStyle.setMarginTop(Length()); innerStyle.setMarginBottom(Length()); - innerStyle.setAlignSelf(AlignFlexStart); + innerStyle.setAlignSelfPosition(ItemPositionFlexStart); } - innerStyle.setPaddingLeft(Length(theme().popupInternalPaddingLeft(&style()), Fixed)); - innerStyle.setPaddingRight(Length(theme().popupInternalPaddingRight(&style()), Fixed)); - innerStyle.setPaddingTop(Length(theme().popupInternalPaddingTop(&style()), Fixed)); - innerStyle.setPaddingBottom(Length(theme().popupInternalPaddingBottom(&style()), Fixed)); + innerStyle.setPaddingBox(theme().popupInternalPaddingBox(style())); if (document().page()->chrome().selectItemWritingDirectionIsNatural()) { // Items in the popup will not respect the CSS text-align and direction properties, @@ -173,7 +169,7 @@ void RenderMenuList::adjustInnerStyle() HTMLSelectElement& RenderMenuList::selectElement() const { - return toHTMLSelectElement(nodeForNonAnonymous()); + return downcast<HTMLSelectElement>(nodeForNonAnonymous()); } void RenderMenuList::addChild(RenderObject* newChild, RenderObject* beforeChild) @@ -202,7 +198,7 @@ void RenderMenuList::styleDidChange(StyleDifference diff, const RenderStyle* old if (m_innerBlock) // RenderBlock handled updating the anonymous block's style. adjustInnerStyle(); - bool fontChanged = !oldStyle || oldStyle->font() != style().font(); + bool fontChanged = !oldStyle || oldStyle->fontCascade() != style().fontCascade(); if (fontChanged) { updateOptionsWidth(); m_needsOptionsWidthUpdate = false; @@ -214,25 +210,30 @@ void RenderMenuList::updateOptionsWidth() float maxOptionWidth = 0; const Vector<HTMLElement*>& listItems = selectElement().listItems(); int size = listItems.size(); - FontCachePurgePreventer fontCachePurgePreventer; for (int i = 0; i < size; ++i) { HTMLElement* element = listItems[i]; - if (!isHTMLOptionElement(element)) + if (!is<HTMLOptionElement>(*element)) continue; - String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); + String text = downcast<HTMLOptionElement>(*element).textIndentedToRespectGroupLabel(); applyTextTransform(style(), text, ' '); if (theme().popupOptionSupportsTextIndent()) { // Add in the option's text indent. We can't calculate percentage values for now. float optionWidth = 0; - if (RenderStyle* optionStyle = element->renderStyle()) + if (auto* optionStyle = element->computedStyle()) optionWidth += minimumValueForLength(optionStyle->textIndent(), 0); - if (!text.isEmpty()) - optionWidth += style().font().width(text); + if (!text.isEmpty()) { + const FontCascade& font = style().fontCascade(); + TextRun run = RenderBlock::constructTextRun(text, style()); + optionWidth += font.width(run); + } maxOptionWidth = std::max(maxOptionWidth, optionWidth); - } else if (!text.isEmpty()) - maxOptionWidth = std::max(maxOptionWidth, style().font().width(text)); + } else if (!text.isEmpty()) { + const FontCascade& font = style().fontCascade(); + TextRun run = RenderBlock::constructTextRun(text, style()); + maxOptionWidth = std::max(maxOptionWidth, font.width(run)); + } } int width = static_cast<int>(ceilf(maxOptionWidth)); @@ -268,9 +269,10 @@ void RenderMenuList::setTextFromOption(int optionIndex) String text = emptyString(); if (i >= 0 && i < size) { Element* element = listItems[i]; - if (isHTMLOptionElement(element)) { - text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); - m_optionStyle = element->renderStyle(); + if (is<HTMLOptionElement>(*element)) { + text = downcast<HTMLOptionElement>(*element).textIndentedToRespectGroupLabel(); + auto* style = element->computedStyle(); + m_optionStyle = style ? RenderStyle::clonePtr(*style) : nullptr; } } @@ -324,8 +326,8 @@ LayoutRect RenderMenuList::controlClipRect(const LayoutPoint& additionalOffset) void RenderMenuList::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const { - maxLogicalWidth = std::max(m_optionsWidth, theme().minimumMenuListSize(&style())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight(); - if (!style().width().isPercent()) + maxLogicalWidth = std::max(m_optionsWidth, theme().minimumMenuListSize(style())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight(); + if (!style().width().isPercentOrCalculated()) minLogicalWidth = maxLogicalWidth; } @@ -349,7 +351,7 @@ void RenderMenuList::computePreferredLogicalWidths() m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().maxWidth().value())); } - LayoutUnit toAdd = borderAndPaddingWidth(); + LayoutUnit toAdd = horizontalBorderAndPaddingExtent(); m_minPreferredLogicalWidth += toAdd; m_maxPreferredLogicalWidth += toAdd; @@ -376,7 +378,7 @@ void RenderMenuList::showPopup() // inside the showPopup call and it would fail. createInnerBlock(); if (!m_popup) - m_popup = document().page()->chrome().createPopupMenu(this); + m_popup = document().page()->chrome().createPopupMenu(*this); m_popupIsVisible = true; // Compute the top left taking transforms into account, but use @@ -434,10 +436,8 @@ void RenderMenuList::didUpdateActiveOption(int optionIndex) if (listIndex < 0 || listIndex >= static_cast<int>(selectElement().listItems().size())) return; - HTMLElement* listItem = selectElement().listItems()[listIndex]; - ASSERT(listItem); - if (listItem->renderer()) { - if (AccessibilityMenuList* menuList = toAccessibilityMenuList(document().axObjectCache()->get(this))) + if (AXObjectCache* cache = document().existingAXObjectCache()) { + if (AccessibilityMenuList* menuList = downcast<AccessibilityMenuList>(cache->get(this))) menuList->didUpdateActiveOption(optionIndex); } } @@ -450,10 +450,10 @@ String RenderMenuList::itemText(unsigned listIndex) const String itemString; Element* element = listItems[listIndex]; - if (isHTMLOptGroupElement(element)) - itemString = toHTMLOptGroupElement(element)->groupLabelText(); - else if (isHTMLOptionElement(element)) - itemString = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); + if (is<HTMLOptGroupElement>(*element)) + itemString = downcast<HTMLOptGroupElement>(*element).groupLabelText(); + else if (is<HTMLOptionElement>(*element)) + itemString = downcast<HTMLOptionElement>(*element).textIndentedToRespectGroupLabel(); applyTextTransform(style(), itemString, ' '); return itemString; @@ -475,7 +475,7 @@ String RenderMenuList::itemAccessibilityText(unsigned listIndex) const const Vector<HTMLElement*>& listItems = selectElement().listItems(); if (listIndex >= listItems.size()) return String(); - return listItems[listIndex]->fastGetAttribute(aria_labelAttr); + return listItems[listIndex]->attributeWithoutSynchronization(aria_labelAttr); } String RenderMenuList::itemToolTip(unsigned listIndex) const @@ -492,12 +492,12 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const if (listIndex >= listItems.size()) return false; HTMLElement* element = listItems[listIndex]; - if (!isHTMLOptionElement(element)) + if (!is<HTMLOptionElement>(*element)) return false; bool groupEnabled = true; if (Element* parentElement = element->parentElement()) { - if (isHTMLOptGroupElement(parentElement)) + if (is<HTMLOptGroupElement>(*parentElement)) groupEnabled = !parentElement->isDisabledFormControl(); } if (!groupEnabled) @@ -525,10 +525,10 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const bool itemHasCustomBackgroundColor; getItemBackgroundColor(listIndex, itemBackgroundColor, itemHasCustomBackgroundColor); - RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle(); - return style ? PopupMenuStyle(style->visitedDependentColor(CSSPropertyColor), itemBackgroundColor, style->font(), style->visibility() == VISIBLE, - style->display() == NONE, style->textIndent(), style->direction(), isOverride(style->unicodeBidi()), - itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : PopupMenuStyle::DefaultBackgroundColor) : menuStyle(); + auto& style = *element->computedStyle(); + return PopupMenuStyle(style.visitedDependentColor(CSSPropertyColor), itemBackgroundColor, style.fontCascade(), style.visibility() == VISIBLE, + style.display() == NONE, true, style.textIndent(), style.direction(), isOverride(style.unicodeBidi()), + itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : PopupMenuStyle::DefaultBackgroundColor); } void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackgroundColor, bool& itemHasCustomBackgroundColor) const @@ -541,19 +541,17 @@ void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackg } HTMLElement* element = listItems[listIndex]; - Color backgroundColor; - if (element->renderStyle()) - backgroundColor = element->renderStyle()->visitedDependentColor(CSSPropertyBackgroundColor); - itemHasCustomBackgroundColor = backgroundColor.isValid() && backgroundColor.alpha(); + Color backgroundColor = element->computedStyle()->visitedDependentColor(CSSPropertyBackgroundColor); + itemHasCustomBackgroundColor = backgroundColor.isValid() && backgroundColor.isVisible(); // If the item has an opaque background color, return that. - if (!backgroundColor.hasAlpha()) { + if (backgroundColor.isOpaque()) { itemBackgroundColor = backgroundColor; return; } // Otherwise, the item's background is overlayed on top of the menu background. backgroundColor = style().visitedDependentColor(CSSPropertyBackgroundColor).blend(backgroundColor); - if (!backgroundColor.hasAlpha()) { + if (backgroundColor.isOpaque()) { itemBackgroundColor = backgroundColor; return; } @@ -565,8 +563,12 @@ void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackg PopupMenuStyle RenderMenuList::menuStyle() const { const RenderStyle& styleToUse = m_innerBlock ? m_innerBlock->style() : style(); - return PopupMenuStyle(styleToUse.visitedDependentColor(CSSPropertyColor), styleToUse.visitedDependentColor(CSSPropertyBackgroundColor), styleToUse.font(), styleToUse.visibility() == VISIBLE, - styleToUse.display() == NONE, styleToUse.textIndent(), style().direction(), isOverride(style().unicodeBidi())); + IntRect absBounds = absoluteBoundingBoxRectIgnoringTransforms(); + return PopupMenuStyle(styleToUse.visitedDependentColor(CSSPropertyColor), styleToUse.visitedDependentColor(CSSPropertyBackgroundColor), + styleToUse.fontCascade(), styleToUse.visibility() == VISIBLE, styleToUse.display() == NONE, + style().hasAppearance() && style().appearance() == MenulistPart, styleToUse.textIndent(), + style().direction(), isOverride(style().unicodeBidi()), PopupMenuStyle::DefaultBackgroundColor, + PopupMenuStyle::SelectPopup, theme().popupMenuSize(styleToUse, absBounds)); } HostWindow* RenderMenuList::hostWindow() const @@ -574,15 +576,12 @@ HostWindow* RenderMenuList::hostWindow() const return view().frameView().hostWindow(); } -PassRefPtr<Scrollbar> RenderMenuList::createScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) +Ref<Scrollbar> RenderMenuList::createScrollbar(ScrollableArea& scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) { - RefPtr<Scrollbar> widget; bool hasCustomScrollbarStyle = style().hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) - widget = RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, &selectElement()); - else - widget = Scrollbar::createNativeScrollbar(scrollableArea, orientation, controlSize); - return widget.release(); + return RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, &selectElement()); + return Scrollbar::createNativeScrollbar(scrollableArea, orientation, controlSize); } int RenderMenuList::clientInsetLeft() const @@ -595,24 +594,27 @@ int RenderMenuList::clientInsetRight() const return 0; } -LayoutUnit RenderMenuList::clientPaddingLeft() const -{ - return paddingLeft() + m_innerBlock->paddingLeft(); -} - const int endOfLinePadding = 2; -LayoutUnit RenderMenuList::clientPaddingRight() const + +LayoutUnit RenderMenuList::clientPaddingLeft() const { - if (style().appearance() == MenulistPart || style().appearance() == MenulistButtonPart) { + if ((style().appearance() == MenulistPart || style().appearance() == MenulistButtonPart) && style().direction() == RTL) { // 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 paddingLeft() + m_innerBlock->paddingLeft(); +} + +LayoutUnit RenderMenuList::clientPaddingRight() const +{ + if ((style().appearance() == MenulistPart || style().appearance() == MenulistButtonPart) && style().direction() == LTR) + return endOfLinePadding; + return paddingRight() + m_innerBlock->paddingRight(); } @@ -642,7 +644,7 @@ bool RenderMenuList::itemIsSeparator(unsigned listIndex) const bool RenderMenuList::itemIsLabel(unsigned listIndex) const { const Vector<HTMLElement*>& listItems = selectElement().listItems(); - return listIndex < listItems.size() && isHTMLOptGroupElement(listItems[listIndex]); + return listIndex < listItems.size() && is<HTMLOptGroupElement>(*listItems[listIndex]); } bool RenderMenuList::itemIsSelected(unsigned listIndex) const @@ -651,7 +653,7 @@ bool RenderMenuList::itemIsSelected(unsigned listIndex) const if (listIndex >= listItems.size()) return false; HTMLElement* element = listItems[listIndex]; - return isHTMLOptionElement(element) && toHTMLOptionElement(element)->selected(); + return is<HTMLOptionElement>(*element) && downcast<HTMLOptionElement>(*element).selected(); } void RenderMenuList::setTextFromItem(unsigned listIndex) @@ -661,7 +663,7 @@ void RenderMenuList::setTextFromItem(unsigned listIndex) FontSelector* RenderMenuList::fontSelector() const { - return document().ensureStyleResolver().fontSelector(); + return &document().fontSelector(); } } |