📄 render_box.cpp
字号:
/** * This file is part of the DOM implementation for KDE. * * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2002-2003 Apple Computer, Inc. * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.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. * */// -------------------------------------------------------------------------//#define DEBUG_LAYOUT//#define CLIP_DEBUG#include <qpainter.h>#include "misc/loader.h"#include "rendering/render_replaced.h"#include "rendering/render_canvas.h"#include "rendering/render_table.h"#include "rendering/render_inline.h"#include "rendering/render_block.h"#include "rendering/render_line.h"#include "rendering/render_layer.h"#include "misc/htmlhashes.h"#include "xml/dom_nodeimpl.h"#include "xml/dom_docimpl.h"#include "html/html_elementimpl.h"#include <khtmlview.h>#include <kdebug.h>#include <kglobal.h>#include <assert.h>using namespace DOM;using namespace khtml;#define TABLECELLMARGIN -0x4000RenderBox::RenderBox(DOM::NodeImpl* node) : RenderContainer(node){ m_minWidth = -1; m_maxWidth = -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_placeHolderBox = 0; m_layer = 0;}RenderBlock* RenderBox::createAnonymousBlock(){ RenderStyle *newStyle = new RenderStyle(); newStyle->inheritFrom(style()); newStyle->setDisplay(BLOCK); RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous*/); newBox->setStyle(newStyle); return newBox;}void RenderBox::restructureParentFlow() { if (!parent() || parent()->childrenInline() == isInline()) return; // We have gone from not affecting the inline status of the parent flow to suddenly // having an impact. See if there is a mismatch between the parent flow's // childrenInline() state and our state. if (!isInline()) { if (parent()->isRenderInline()) { // We have to split the parent flow. RenderInline* parentInline = static_cast<RenderInline*>(parent()); RenderBlock* newBox = parentInline->createAnonymousBlock(); RenderFlow* oldContinuation = parent()->continuation(); parentInline->setContinuation(newBox); RenderObject* beforeChild = nextSibling(); parent()->removeChildNode(this); parentInline->splitFlow(beforeChild, newBox, this, oldContinuation); } else if (parent()->isRenderBlock()) static_cast<RenderBlock*>(parent())->makeChildrenNonInline(); } else { // An anonymous block must be made to wrap this inline. RenderBlock* box = createAnonymousBlock(); parent()->insertChildNode(box, this); box->appendChildNode(parent()->removeChildNode(this)); }}void RenderBox::setStyle(RenderStyle *_style){ bool affectsParent = style() && isFloatingOrPositioned() && (!_style->isFloating() && _style->position() != ABSOLUTE && _style->position() != FIXED) && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow()); RenderContainer::setStyle(_style); // The root always paints its background/border. if (isRoot()) setShouldPaintBackgroundOrBorder(true); switch(_style->display()) { case INLINE: case INLINE_BLOCK: case INLINE_TABLE: setInline(true); break; case RUN_IN: if (isInline() && parent() && parent()->childrenInline()) break; default: setInline(false); } switch(_style->position()) { case ABSOLUTE: case FIXED: setPositioned(true); break; default: setPositioned(false); if( !isTableCell() && _style->isFloating() ) setFloating(true); if( _style->position() == RELATIVE ) setRelPositioned(true); } if (requiresLayer()) { if (!m_layer) { m_layer = new (renderArena()) RenderLayer(this); m_layer->insertOnlyThisLayer(); } } else if (m_layer && !isCanvas()) { m_layer->removeOnlyThisLayer(); m_layer = 0; } if (m_layer) { // Make sure our z-index values are only applied if we're positioned or // relpositioned. if (!isPositioned() && !isRelPositioned()) { // Set the auto z-index flag. if (isRoot()) style()->setZIndex(0); else style()->setHasAutoZIndex(); } m_layer->styleChanged(); } // ### outlineSize() and outlineOffset() not merged yet if (style()->outlineWidth() > 0 && style()->outlineWidth() > maximalOutlineSize(PaintActionOutline)) static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineWidth()); if (affectsParent) restructureParentFlow();}RenderBox::~RenderBox(){ //kdDebug( 6040 ) << "Element destructor: this=" << nodeName().string() << endl;}void RenderBox::detach(){ RenderLayer* layer = m_layer; RenderArena* arena = renderArena(); RenderContainer::detach(); if (layer) layer->detach(arena);}InlineBox* RenderBox::createInlineBox(bool /*makePlaceHolderBox*/, bool /*isRootLineBox*/){ if (m_placeHolderBox) m_placeHolderBox->detach(renderArena()); return (m_placeHolderBox = new (renderArena()) InlineBox(this));}void RenderBox::deleteInlineBoxes(RenderArena* arena){ if (m_placeHolderBox) { m_placeHolderBox->detach( arena ? arena : renderArena() ); m_placeHolderBox = 0; }}short RenderBox::contentWidth() const{ short w = m_width - style()->borderLeftWidth() - style()->borderRightWidth(); w -= paddingLeft() + paddingRight(); if (m_layer && style()->scrollsOverflow()) w -= m_layer->verticalScrollbarWidth(); //kdDebug( 6040 ) << "RenderBox::contentWidth(2) = " << w << endl; return w;}int RenderBox::contentHeight() const{ int h = m_height - style()->borderTopWidth() - style()->borderBottomWidth(); h -= paddingTop() + paddingBottom(); if (m_layer && style()->scrollsOverflow()) h -= m_layer->horizontalScrollbarHeight(); return h;}void RenderBox::setPos( int xPos, int yPos ){ m_x = xPos; m_y = yPos;}short RenderBox::width() const{ return m_width;}int RenderBox::height() const{ return m_height;}void RenderBox::setWidth( int width ){ m_width = width;}void RenderBox::setHeight( int height ){ m_height = height;}int RenderBox::calcBoxHeight(int h) const{ if (style()->boxSizing() == CONTENT_BOX) h += borderTop() + borderBottom() + paddingTop() + paddingBottom(); return h;}int RenderBox::calcBoxWidth(int w) const{ if (style()->boxSizing() == CONTENT_BOX) w += borderLeft() + borderRight() + paddingLeft() + paddingRight(); return w;}int RenderBox::calcContentHeight(int h) const{ if (style()->boxSizing() == BORDER_BOX) h -= borderTop() + borderBottom() + paddingTop() + paddingBottom(); return kMax(0, h);}int RenderBox::calcContentWidth(int w) const{ if (style()->boxSizing() == BORDER_BOX) w -= borderLeft() + borderRight() + paddingLeft() + paddingRight(); return kMax(0, w);}// --------------------- painting stuff -------------------------------void RenderBox::paint(PaintInfo& i, int _tx, int _ty){ _tx += m_x; _ty += m_y; if (style()->hidesOverflow() && m_layer) m_layer->subtractScrollOffset(_tx, _ty); // default implementation. Just pass things through to the children for(RenderObject* child = firstChild(); child; child = child->nextSibling()) child->paint(i, _tx, _ty);}void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty){ //kdDebug( 6040 ) << renderName() << "::paintRootBoxDecorations()" << _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(); } } if( !bgColor.isValid() && canvas()->view()) bgColor = canvas()->view()->palette().active().color(QColorGroup::Base); 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()->docWidth(); rh = canvas()->docHeight(); } // kdDebug(0) << "rw = " << rw <<endl; int bx = _tx - marginLeft(); int by = _ty - marginTop(); int bw = QMAX(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw); int bh = QMAX(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, paintInfo.r.y()); paintBackgrounds(paintInfo.p, bgColor, bgLayer, my, paintInfo.r.height(), bx, by, bw, bh); if(style()->hasBorder()) paintBorder( paintInfo.p, _tx, _ty, w, h, style() );}void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty){ //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl; if(isRoot()) return paintRootBoxDecorations(paintInfo, _tx, _ty); int w = width(); int h = height() + borderTopExtra() + borderBottomExtra(); _ty -= borderTopExtra(); int my = kMax(_ty,paintInfo.r.y()); int end = kMin( paintInfo.r.y() + paintInfo.r.height(), _ty + h ); int mh = end - my; // 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(paintInfo.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h); if(style()->hasBorder()) { paintBorder(paintInfo.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){ if ( cliph < 0 ) return; CachedImage* bg = bgLayer->backgroundImage(); bool shouldPaintBackgroundImage = bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage(); QColor bgColor = c; // Paint the color first underneath all images. if (!bgLayer->next() && bgColor.isValid() && qAlpha(bgColor.rgb()) > 0) p->fillRect(_tx, clipy, w, cliph, bgColor); // no progressive loading of the background image if (shouldPaintBackgroundImage) { int sx = 0; int sy = 0; int cw,ch; int cx,cy; int vpab = bleft + bright; int hpab = borderTop() + borderBottom();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -