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

📄 render_box.cpp

📁 手机浏览器源码程序,功能强大
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/**
 * This file is part of the DOM implementation for KDE.
 *
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 * Copyright (C) 2004 Apple Computer, Inc.
 *
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */
// -------------------------------------------------------------------------
//#define DEBUG_LAYOUT


#include <qpainter.h>
#include "rendering/render_box.h"
#include "rendering/render_replaced.h"
#include "rendering/render_canvas.h"
#include "rendering/render_table.h"
#include "render_flexbox.h"
#include "render_arena.h"

#include "misc/htmlhashes.h"
#include "xml/dom_nodeimpl.h"
#include "xml/dom_docimpl.h"
#include "html/html_elementimpl.h"

#include "render_line.h"

#include <khtmlview.h>
#include <kdebug.h>
#include <assert.h>


using namespace DOM;
using namespace khtml;

#define TABLECELLMARGIN -0x4000

RenderBox::RenderBox(DOM::NodeImpl* node)
    : RenderObject(node)
{
    m_minWidth = -1;
    m_maxWidth = -1;
    m_overrideSize = -1;
    m_width = m_height = 0;
    m_x = 0;
    m_y = 0;
    m_marginTop = 0;
    m_marginBottom = 0;
    m_marginLeft = 0;
    m_marginRight = 0;
    m_staticX = 0;
    m_staticY = 0;
    m_layer = 0;
    m_inlineBoxWrapper = 0;
}

void RenderBox::setStyle(RenderStyle *_style)
{
    RenderObject::setStyle(_style);

    // The root always paints its background/border.
    if (isRoot())
        setShouldPaintBackgroundOrBorder(true);

    setInline(_style->isDisplayInlineType());

    switch(_style->position())
    {
    case ABSOLUTE:
    case FIXED:
        setPositioned(true);
        break;
    default:
        setPositioned(false);

        if (_style->isFloating())
            setFloating(true);

        if (_style->position() == RELATIVE)
            setRelPositioned(true);
    }

    // FIXME: Note that we restrict overflow to blocks for now.  One day table bodies and cells
    // will need to support overflow.
    // We also deal with the body scroll quirk here, since it sets the scrollbars for the document.
    if (_style->overflow() != OVISIBLE && isBlockFlow() && !isTableCell() &&
        (!document()->isHTMLDocument() || !isBody()))
        setHasOverflowClip();

    if (requiresLayer()) {
        if (!m_layer) {
            m_layer = new (renderArena()) RenderLayer(this);
            m_layer->insertOnlyThisLayer();
            if (containingBlock())
                m_layer->updateLayerPositions();
        }
    }
    else if (m_layer && !isRoot() && !isCanvas()) {
        m_layer->removeOnlyThisLayer();
        m_layer = 0;
    }

    if (m_layer)
        m_layer->styleChanged();

    // Set the text color if we're the body.
    if (isBody())
        element()->getDocument()->setTextColor(_style->color());

    if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintActionOutline))
        static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
}

RenderBox::~RenderBox()
{
    //kdDebug( 6040 ) << "Element destructor: this=" << nodeName().string() << endl;
}

void RenderBox::detach()
{
    RenderLayer* layer = m_layer;
    RenderArena* arena = renderArena();

    // This must be done before we detach the RenderObject.
    if (layer)
        layer->clearClipRect();

    if (m_inlineBoxWrapper) {
        if (!documentBeingDestroyed())
            m_inlineBoxWrapper->remove();
        m_inlineBoxWrapper->detach(arena);
        m_inlineBoxWrapper = 0;
    }

    RenderObject::detach();

    if (layer)
        layer->detach(arena);
}

int RenderBox::contentWidth() const
{
    int w = m_width - borderLeft() - borderRight();
    w -= paddingLeft() + paddingRight();

    if (includeScrollbarSize())
        w -= m_layer->verticalScrollbarWidth();

    //kdDebug( 6040 ) << "RenderBox::contentWidth(2) = " << w << endl;
    return w;
}

int RenderBox::contentHeight() const
{
    int h = m_height - borderTop() - borderBottom();
    h -= paddingTop() + paddingBottom();

    if (includeScrollbarSize())
        h -= m_layer->horizontalScrollbarHeight();

    return h;
}

int RenderBox::overrideWidth() const
{
    return m_overrideSize == -1 ? m_width : m_overrideSize;
}

int RenderBox::overrideHeight() const
{
    return m_overrideSize == -1 ? m_height : m_overrideSize;
}

void RenderBox::setPos( int xPos, int yPos )
{
    if (xPos == m_x && yPos == m_y)
        return; // Optimize for the case where we don't move at all.

    m_x = xPos; m_y = yPos;
}

int RenderBox::width() const
{
    return m_width;
}

int RenderBox::height() const
{
    return m_height;
}

// Hit Testing
bool RenderBox::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
                            HitTestAction hitTestAction)
{
    // Check kids first.
    _tx += m_x;
    _ty += m_y;
    for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
        // FIXME: We have to skip over inline flows, since they can show up inside table rows at the moment (a demoted inline <form> for example).  If we ever implement a
        // table-specific hit-test method (which we should do for performance reasons anyway), then we can remove this check.
        if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction)) {
            setInnerNode(info);
            return true;
        }
    }

    // Check our bounds next.  For this purpose always assume that we can only be hit in the
    // foreground phase (which is true for replaced elements like images).
    if (hitTestAction != HitTestForeground)
        return false;

    QRect boundsRect(_tx, _ty, m_width, m_height);
    if (boundsRect.contains(_x, _y)) {
        setInnerNode(info);
        return true;
    }
    return false;
}

// --------------------- painting stuff -------------------------------

void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
{
    _tx += m_x;
    _ty += m_y;

    // default implementation. Just pass paint through to the children
    for (RenderObject* child = firstChild(); child; child = child->nextSibling())
        child->paint(i, _tx, _ty);
}

#ifdef NOKIA_CHANGES
void RenderBox::getRenderersInRect(QPtrList<BoxInfo>& boxInfoList,int deltaX,int deltaY,const QRect& rect)
{
	deltaX += m_x;
	deltaY += m_y;

	BoxInfo* sel = new BoxInfo;
	sel->renderObject = this;
	sel->absoluteXPos = deltaX;
	sel->absoluteYPos = deltaY;
	sel->width = m_width;
	sel->height = m_height;
	sel->area = 0;
	boxInfoList.append(sel);

    for (RenderObject *child = firstChild(); child; child = child->nextSibling())
	     child->getRenderersInRect(boxInfoList, deltaX, deltaY,rect);
}
#endif

void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
{
    //kdDebug( 6040 ) << renderName() << "::paintBoxDecorations()" << _tx << "/" << _ty << endl;
    const BackgroundLayer* bgLayer = style()->backgroundLayers();
    QColor bgColor = style()->backgroundColor();
    if (document()->isHTMLDocument() && !style()->hasBackground()) {
        // Locate the <body> element using the DOM.  This is easier than trying
        // to crawl around a render tree with potential :before/:after content and
        // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
        // render object very easily via the DOM.
        HTMLElementImpl* body = document()->body();
        RenderObject* bodyObject = (body && body->id() == ID_BODY) ? body->renderer() : 0;
        if (bodyObject) {
            bgLayer = bodyObject->style()->backgroundLayers();
            bgColor = bodyObject->style()->backgroundColor();
        }
    }

    int w = width();
    int h = height();

    //    kdDebug(0) << "width = " << w <<endl;

    int rw, rh;
    if (canvas()->view()) {
        rw = canvas()->view()->contentsWidth();
        rh = canvas()->view()->contentsHeight();
    }
    else {
        rw = canvas()->width();
        rh = canvas()->height();
    }

    //    kdDebug(0) << "rw = " << rw <<endl;

    int bx = _tx - marginLeft();
    int by = _ty - marginTop();
    int bw = kMax(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
    int bh = kMax(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);

    // CSS2 14.2:
    // " The background of the box generated by the root element covers the entire canvas."
    // hence, paint the background even in the margin areas (unlike for every other element!)
    // I just love these little inconsistencies .. :-( (Dirk)
    int my = kMax(by, i.r.y());

    paintBackgrounds(i.p, bgColor, bgLayer, my, i.r.height(), bx, by, bw, bh);

    if (style()->hasBorder() && style()->display() != INLINE)
        paintBorder( i.p, _tx, _ty, w, h, style() );
}

void RenderBox::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
{
    if (!shouldPaintWithinRoot(i))
        return;

    //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl;
    if (isRoot())
        return paintRootBoxDecorations(i, _tx, _ty);

    int w = width();
    int h = height() + borderTopExtra() + borderBottomExtra();
    _ty -= borderTopExtra();

    int my = kMax(_ty, i.r.y());
    int mh;
    if (_ty < i.r.y())
        mh= kMax(0, h - (i.r.y() - _ty));
    else
        mh = kMin(i.r.height(), h);

    // The <body> only paints its background if the root element has defined a background
    // independent of the body.  Go through the DOM to get to the root element's render object,
    // since the root could be inline and wrapped in an anonymous block.
    if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground())
        paintBackgrounds(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);

    if (style()->hasBorder())
        paintBorder(i.p, _tx, _ty, w, h, style());
}

void RenderBox::paintBackgrounds(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
{
    if (!bgLayer) return;
    paintBackgrounds(p, c, bgLayer->next(), clipy, cliph, _tx, _ty, w, height);
    paintBackground(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height);
}

void RenderBox::paintBackground(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
{
    paintBackgroundExtended(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height,
                            borderLeft(), borderRight());
}

void RenderBox::paintBackgroundExtended(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
                                        int _tx, int _ty, int w, int h,
                                        int bleft, int bright)
{
    CachedImage* bg = bgLayer->backgroundImage();
    bool shouldPaintBackgroundImage = bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage();
    QColor bgColor = c;
    
    // When this style flag is set, change existing background colors and images to a solid white background.
    // If there's no bg color or image, leave it untouched to avoid affecting transparency.
    // We don't try to avoid loading the background images, because this style flag is only set
    // when printing, and at that point we've already loaded the background images anyway. (To avoid
    // loading the background images we'd have to do this check when applying styles rather than
    // while rendering.)
    if (style()->forceBackgroundsToWhite()) {
        // Note that we can't reuse this variable below because the bgColor might be changed
        bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && qAlpha(bgColor.rgb()) > 0;
        if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
            bgColor = Qt::white;
            shouldPaintBackgroundImage = false;
        }
    }

    // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
    // no background in the child document should show the parent's background.
    if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && qAlpha(bgColor.rgb()) > 0) && canvas()->view()) {
        bool isTransparent;
        DOM::NodeImpl* elt = document()->ownerElement();
        if (elt) {
            if (elt->id() == ID_FRAME)
                isTransparent = false;
            else {
                // Locate the <body> element using the DOM.  This is easier than trying
                // to crawl around a render tree with potential :before/:after content and
                // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
                // render object very easily via the DOM.
                HTMLElementImpl* body = document()->body();
                isTransparent = !body || body->id() != ID_FRAMESET; // Can't scroll a frameset document anyway.
            }
        } else
            isTransparent = canvas()->view()->isTransparent();

        if (isTransparent)
            canvas()->view()->useSlowRepaints(); // The parent must show behind the child.
        else
            bgColor = canvas()->view()->palette().active().color(QColorGroup::Base);
    }

⌨️ 快捷键说明

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