⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 renderlistbox.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * This file is part of the select element renderer in WebCore. * * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. *               2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1.  Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer.  * 2.  Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution.  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of *     its contributors may be used to endorse or promote products derived *     from this software without specific prior written permission.  * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "RenderListBox.h"#include "AXObjectCache.h"#include "CSSStyleSelector.h"#include "Document.h"#include "EventHandler.h"#include "EventNames.h"#include "FocusController.h"#include "Frame.h"#include "FrameView.h"#include "GraphicsContext.h"#include "HTMLNames.h"#include "HTMLSelectElement.h"#include "HitTestResult.h"#include "OptionGroupElement.h"#include "OptionElement.h"#include "Page.h"#include "RenderScrollbar.h"#include "RenderTheme.h"#include "RenderView.h"#include "Scrollbar.h"#include "SelectionController.h"#include "NodeRenderStyle.h"#include <math.h>using namespace std;namespace WebCore {using namespace HTMLNames; const int rowSpacing = 1;const int optionsSpacingHorizontal = 2;const int minSize = 4;const int maxDefaultSize = 10;// FIXME: This hardcoded baselineAdjustment is what we used to do for the old// widget, but I'm not sure this is right for the new control.const int baselineAdjustment = 7;RenderListBox::RenderListBox(HTMLSelectElement* element)    : RenderBlock(element)    , m_optionsChanged(true)    , m_scrollToRevealSelectionAfterLayout(false)    , m_inAutoscroll(false)    , m_optionsWidth(0)    , m_indexOffset(0){}RenderListBox::~RenderListBox(){    setHasVerticalScrollbar(false);}void RenderListBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle){    RenderBlock::styleDidChange(diff, oldStyle);    setReplaced(isInline());}void RenderListBox::updateFromElement(){    if (m_optionsChanged) {        const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(node())->listItems();        int size = numItems();                float width = 0;        for (int i = 0; i < size; ++i) {            HTMLElement* element = listItems[i];            String text;            Font itemFont = style()->font();            if (OptionElement* optionElement = toOptionElement(element))                text = optionElement->textIndentedToRespectGroupLabel();            else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) {                text = optionGroupElement->groupLabelText();                FontDescription d = itemFont.fontDescription();                d.setWeight(d.bolderWeight());                itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());                itemFont.update(document()->styleSelector()->fontSelector());            }                            if (!text.isEmpty()) {                float textWidth = itemFont.floatWidth(TextRun(text.impl(), 0, 0, 0, false, false, false, false));                width = max(width, textWidth);            }        }        m_optionsWidth = static_cast<int>(ceilf(width));        m_optionsChanged = false;                setHasVerticalScrollbar(true);        setNeedsLayoutAndPrefWidthsRecalc();    }}void RenderListBox::selectionChanged(){    repaint();    if (!m_inAutoscroll) {        if (m_optionsChanged || needsLayout())            m_scrollToRevealSelectionAfterLayout = true;        else            scrollToRevealSelection();    }        if (AXObjectCache::accessibilityEnabled())        document()->axObjectCache()->selectedChildrenChanged(this);}void RenderListBox::layout(){    RenderBlock::layout();    if (m_scrollToRevealSelectionAfterLayout)        scrollToRevealSelection();}void RenderListBox::scrollToRevealSelection(){        HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());    m_scrollToRevealSelectionAfterLayout = false;    int firstIndex = select->activeSelectionStartListIndex();    if (firstIndex >= 0 && !listIndexIsVisible(select->activeSelectionEndListIndex()))        scrollToRevealElementAtListIndex(firstIndex);}void RenderListBox::calcPrefWidths(){    ASSERT(!m_optionsChanged);    m_minPrefWidth = 0;    m_maxPrefWidth = 0;    if (style()->width().isFixed() && style()->width().value() > 0)        m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());    else {        m_maxPrefWidth = m_optionsWidth + 2 * optionsSpacingHorizontal;        if (m_vBar)            m_maxPrefWidth += m_vBar->width();    }    if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {        m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));        m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));    } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))        m_minPrefWidth = 0;    else        m_minPrefWidth = m_maxPrefWidth;    if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {        m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));        m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));    }    int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();    m_minPrefWidth += toAdd;    m_maxPrefWidth += toAdd;                                    setPrefWidthsDirty(false);}int RenderListBox::size() const{    int specifiedSize = static_cast<HTMLSelectElement*>(node())->size();    if (specifiedSize > 1)        return max(minSize, specifiedSize);    return min(max(minSize, numItems()), maxDefaultSize);}int RenderListBox::numVisibleItems() const{    // Only count fully visible rows. But don't return 0 even if only part of a row shows.    return max(1, (contentHeight() + rowSpacing) / itemHeight());}int RenderListBox::numItems() const{    return static_cast<HTMLSelectElement*>(node())->listItems().size();}int RenderListBox::listHeight() const{    return itemHeight() * numItems() - rowSpacing;}void RenderListBox::calcHeight(){    int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom();     int itemHeight = RenderListBox::itemHeight();    setHeight(itemHeight * size() - rowSpacing + toAdd);        RenderBlock::calcHeight();        if (m_vBar) {        bool enabled = numVisibleItems() < numItems();        m_vBar->setEnabled(enabled);        m_vBar->setSteps(1, min(1, numVisibleItems() - 1), itemHeight);        m_vBar->setProportion(numVisibleItems(), numItems());        if (!enabled)            m_indexOffset = 0;    }}int RenderListBox::baselinePosition(bool, bool) const{    return height() + marginTop() + marginBottom() - baselineAdjustment;}IntRect RenderListBox::itemBoundingBoxRect(int tx, int ty, int index){    return IntRect(tx + borderLeft() + paddingLeft(),                   ty + borderTop() + paddingTop() + itemHeight() * (index - m_indexOffset),                   contentWidth(), itemHeight());}    void RenderListBox::paintObject(PaintInfo& paintInfo, int tx, int ty){    if (style()->visibility() != VISIBLE)        return;        int listItemsSize = numItems();    if (paintInfo.phase == PaintPhaseForeground) {        int index = m_indexOffset;        while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) {            paintItemForeground(paintInfo, tx, ty, index);            index++;        }    }    // Paint the children.    RenderBlock::paintObject(paintInfo, tx, ty);    if (paintInfo.phase == PaintPhaseBlockBackground)        paintScrollbar(paintInfo, tx, ty);    else if (paintInfo.phase == PaintPhaseChildBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) {        int index = m_indexOffset;        while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) {            paintItemBackground(paintInfo, tx, ty, index);            index++;        }    }}void RenderListBox::paintScrollbar(PaintInfo& paintInfo, int tx, int ty){    if (m_vBar) {        IntRect scrollRect(tx + width() - borderRight() - m_vBar->width(),                           ty + borderTop(),                           m_vBar->width(),                           height() - (borderTop() + borderBottom()));        m_vBar->setFrameRect(scrollRect);        m_vBar->paint(paintInfo.context, paintInfo.rect);    }}void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, int listIndex){    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());    const Vector<HTMLElement*>& listItems = select->listItems();    HTMLElement* element = listItems[listIndex];    OptionElement* optionElement = toOptionElement(element);    String itemText;    if (optionElement)        itemText = optionElement->textIndentedToRespectGroupLabel();    else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element))        itemText = optionGroupElement->groupLabelText();          // Determine where the item text should be placed    IntRect r = itemBoundingBoxRect(tx, ty, listIndex);    r.move(optionsSpacingHorizontal, style()->font().ascent());    RenderStyle* itemStyle = element->renderStyle();    if (!itemStyle)        itemStyle = style();        Color textColor = element->renderStyle() ? element->renderStyle()->color() : style()->color();    if (optionElement && optionElement->selected()) {        if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node())            textColor = theme()->activeListBoxSelectionForegroundColor();        // Honor the foreground color for disabled items        else if (!element->disabled())            textColor = theme()->inactiveListBoxSelectionForegroundColor();    }    paintInfo.context->setFillColor(textColor);    Font itemFont = style()->font();    if (element->hasTagName(optgroupTag)) {        FontDescription d = itemFont.fontDescription();        d.setWeight(d.bolderWeight());        itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());        itemFont.update(document()->styleSelector()->fontSelector());    }    unsigned length = itemText.length();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -