📄 render_flow.cpp
字号:
/** * This file is part of the html renderer for KDE. * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * * 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. * * $Id: render_flow.cpp,v 1.2 2002/01/28 04:31:02 leon Exp $ */// -------------------------------------------------------------------------//#define DEBUG//#define DEBUG_LAYOUT//#define BOX_DEBUG#include <assert.h>#include "render_interface.h"#include "mgcolor.h"#include "mgpen.h"#include "mgbrush.h"#include "mgsize.h"#include "mgrect.h"#include "mgfontmetrics.h"#include "mgpainter.h"#include "mghtml_part.h"#include "dom_string.h"#include "render_flow.h"#include "render_text.h"#include "render_style.h"#include "render_root.h"#include "render_replaced.h"#include "htmlhashes.h"#include "kdebug.h"using namespace DOM;using namespace khtml;#define DEBUG_BY_XHTANG 1static inline int collapseMargins(int a, int b){ if(a >= 0 && b >= 0) return (a > b ? a : b ); if(a > 0 && b < 0) return a + b; if(a < 0 && b > 0) return b + a; return ( a > b ? b : a);}void RenderFlow::mysetLayouted(bool f){ RenderObject *child = firstChild(); while(child){// child->mysetLayouted(false); child->setLayouted(false); child = child->nextSibling(); }}RenderFlow::RenderFlow() : RenderBox(){ m_inline = true; m_childrenInline = true; m_haveAnonymous = false; specialObjects = 0;}void RenderFlow::setStyle(RenderStyle *style){// kdDebug( 6040 ) << (void*)this<< " renderFlow::setstyle()" << endl; RenderBox::setStyle(style); if(m_positioned) m_style->setDisplay(BLOCK); if( m_floating || !style->display() == INLINE) m_inline = false; if (m_inline == true && m_childrenInline==false) m_inline = false; m_pre = false; if(m_style->whiteSpace() == PRE) m_pre = true; if (haveAnonymousBox()) { RenderObject *child = firstChild(); while(child != 0) { if(child->isAnonymousBox()) { if (child->style()) delete child->style(); RenderStyle* newStyle = new RenderStyle(style); newStyle->setDisplay(BLOCK); child->setPart(m_part); child->setStyle(newStyle); child->setIsAnonymousBox(true); } child = child->nextSibling(); } }}RenderFlow::~RenderFlow(){ if (specialObjects) delete specialObjects; if(isAnonymousBox()) // usually the style object is deleted by the DOM tree, but // since anonymous boxes don't have a corresponding DOM element... delete m_style;}void RenderFlow::print(MGPainter *p, int _x, int _y, int _w, int _h, int _tx, int _ty){#ifdef DEBUG_LAYOUT //kdDebug( 6040 ) << renderName() << "(RenderFlow) " << this << " ::print() x/y/w/h = (" << xPos() << "/" << yPos() << "/" << width() << "/" << height() << ")" << endl;#endif if(!isInline()) { _tx += m_x; _ty += m_y; } // check if we need to do anything at all... if(!isInline() && !containsPositioned() && !isRelPositioned() && !isPositioned() ) { int h = m_height; if(specialObjects && floatBottom() > h) h = floatBottom(); if((_ty > _y + _h) || (_ty + h < _y)) { //kdDebug( 6040 ) << "cut!" << endl; return; } } printObject(p, _x, _y, _w, _h, _tx, _ty);}void RenderFlow::printObject(MGPainter *p, int _x, int _y, int _w, int _h, int _tx, int _ty){#ifdef DEBUG_LAYOUT //kdDebug( 6040 ) << renderName() << "(RenderFlow) " << this << " ::printObject() w/h = (" << width() << "/" << height() << ")" << endl;#endif // add offset for relative positioning if(isRelPositioned()) { relativePositionOffset(_tx, _ty);// kdDebug(0) << "flow " << _tx << ", " << _ty << endl; } // 1. print background, borders etc if(m_printSpecial && !isInline() && m_visible) printBoxDecorations(p, _x, _y, _w, _h, _tx, _ty); // 2. print contents RenderObject *child = firstChild(); while(child != 0) { if(!child->isFloating() && !child->isPositioned()) { child->print(p, _x, _y, _w, _h, _tx, _ty); } child = child->nextSibling(); } // 3. print floats and other non-flow objects if(specialObjects) { SpecialObject* r; QListIterator<SpecialObject> it(*specialObjects); for ( ; (r = it.current()); ++it ) { if (r->node->containingBlock()==this) { RenderObject *o = r->node; //kdDebug(0) << renderName() << "printing positioned at " << _tx + o->xPos() << "/" << _ty + o->yPos()<< endl; o->print(p, _x, _y, _w, _h, _tx , _ty); } } }#ifdef BOX_DEBUG if(isAnonymousBox()) outlineBox(p, _tx, _ty, "green"); else outlineBox(p, _tx, _ty);#endif}void RenderFlow::setPos( int xPos, int yPos ){ m_y = yPos; setXPos(xPos);}void RenderFlow::setXPos( int xPos ){ m_x = xPos;}void RenderFlow::layout(){ //kdDebug( 6040 ) << renderName() << " " << this << "::layout() start" << endl; //QTime t; //t.start(); assert(!isInline()); int oldWidth = m_width; calcWidth();// kdDebug( 6040 ) << specialObjects << "," << oldWidth << ","// << m_width << ","<< layouted() << "," << isAnonymousBox() << endl; if ( (!specialObjects || (isListItem() && specialObjects->count() == 1) ) && oldWidth == m_width && layouted() && !isAnonymousBox() && !containsPositioned() && !isPositioned()) return;#ifdef DEBUG_LAYOUT //kdDebug( 6040 ) << renderName() << "(RenderFlow) " << this << " ::layout() width=" << m_width << ", layouted=" << layouted() << endl; //if(containingBlock() == static_cast<RenderObject *>(this)) //kdDebug( 6040 ) << renderName() << ": containingBlock == this" << endl;#endif if(m_width<=0) { if(m_y < 0) m_y = 0; setLayouted(); return; } clearFloats(); m_height = 0; m_clearStatus = CNONE;// kdDebug( 6040 ) << "childrenInline()=" << childrenInline() << endl; if(childrenInline()) layoutInlineChildren(); else layoutBlockChildren(); calcHeight(); if(hasOverhangingFloats()) { if(isFloating() || isTableCell()) { m_height = floatBottom(); m_height += borderBottom() + paddingBottom(); } } else if (isTableCell() && m_last && m_last->hasOverhangingFloats()) { m_height = m_last->yPos() + static_cast<RenderFlow*>(m_last)->floatBottom(); m_height += borderBottom() + paddingBottom(); } layoutSpecialObjects(); //kdDebug() << renderName() << " layout width=" << m_width << " height=" << m_height << endl; setLayouted();}void RenderFlow::layoutSpecialObjects(){ if(specialObjects) { //kdDebug( 6040 ) << renderName() << " " << this << "::layoutSpecialObjects() start" << endl; SpecialObject* r; QListIterator<SpecialObject> it(*specialObjects); for ( ; (r = it.current()); ++it ) { //kdDebug(6040) << "have a positioned object" << endl; if (r->type == SpecialObject::Positioned) r->node->layout(); } specialObjects->sort(); }}void RenderFlow::layoutBlockChildren(){#ifdef DEBUG_LAYOUT //kdDebug( 6040 ) << renderName() << " layoutBlockChildren( )" << endl;#endif bool _layouted = true; int xPos = 0; int toAdd = 0; m_height = 0; if(m_style->hasBorder()) { xPos += borderLeft(); m_height += borderTop(); toAdd += borderBottom(); } if(m_style->hasPadding()) { xPos += paddingLeft(); m_height += paddingTop(); toAdd += paddingBottom(); } if( m_style->direction() == RTL ) { xPos = marginLeft() + m_width - paddingRight() - borderRight(); } RenderObject *child = firstChild(); RenderFlow *prevFlow = 0; int prevMargin = 0; if(isTableCell() && child) prevMargin = -child->marginTop(); //QTime t; //t.start(); while( child != 0 ) { //kdDebug( 6040 ) << " " << child->renderName() << " loop " << child << ", " << child->isInline() << ", " << child->layouted() << endl; //kdDebug( 6040 ) << t.elapsed() << endl; // ### might be some layouts are done two times... FIX that. if (child->isPositioned()) { child->layout(); static_cast<RenderFlow*>(child->containingBlock())->insertPositioned(child); //kdDebug() << "RenderFlow::layoutBlockChildren inserting positioned into " << child->containingBlock()->renderName() << endl; child = child->nextSibling(); continue; } else if ( child->isReplaced() ) child->layout(); if(checkClear(child)) prevMargin = 0; // ### should only be 0 // if oldHeight+prevMargin < newHeight int margin = child->marginTop(); //kdDebug(0) << "margin = " << margin << " prevMargin = " << prevMargin << endl; margin = collapseMargins(margin, prevMargin); m_height += margin; //kdDebug(0) << "margin = " << margin << " yPos = " << m_height << endl; if(prevFlow) { if (prevFlow->yPos()+prevFlow->floatBottom() > m_height) child->setLayouted(false); else prevFlow=0; } child->setYPos(m_height); child->layout(); int chPos = xPos + child->marginLeft(); if( m_style->textAlign() == KONQ_CENTER && !child->style()->marginLeft().isVariable()) { //kdDebug() << "should align to center" << endl; chPos += ( width() - child->width() )/2; } else if(m_style->direction() == LTR) { // html blocks flow around floats if (style()->htmlHacks() && child->style()->flowAroundFloats() ) chPos = leftOffset(m_height) + child->marginLeft(); } else { chPos -= child->width() + child->marginLeft() + child->marginRight(); if (style()->htmlHacks() && child->style()->flowAroundFloats() ) chPos -= leftOffset(m_height); } child->setXPos(chPos); m_height += child->height(); prevMargin = child->marginBottom(); if (child->isFlow()) prevFlow = static_cast<RenderFlow*>(child); //kdDebug() << "In function: RenderFlow::layoutBlockChildren" << endl; //kdDebug() << "child name is " << child->renderName() << endl; child = child->nextSibling(); } if(!isTableCell()) m_height += prevMargin; m_height += toAdd; setLayouted(_layouted); // kdDebug( 6040 ) << "layouted = " << layouted_ << endl;}bool RenderFlow::checkClear(RenderObject *child){ //kdDebug( 6040 ) << "checkClear oldheight=" << m_height << endl; RenderObject *o = child->previousSibling(); while(o && !o->isFlow()) o = o->previousSibling(); if(!o) o = this; RenderFlow *prev = static_cast<RenderFlow *>(o); switch(child->style()->clear()) { case CNONE: return false; case CLEFT: { int bottom = prev->leftBottom() + prev->yPos(); if(m_height < bottom) m_height = bottom; //### + lastFloat()->marginBotton()? break; } case CRIGHT: { int bottom = prev->rightBottom() + prev->yPos(); if(m_height < bottom) m_height = bottom; //### + lastFloat()->marginBotton()? break; } case CBOTH: { int bottom = prev->floatBottom() + prev->yPos(); if(m_height < bottom) m_height = bottom; //### + lastFloat()->marginBotton()? break; } } //kdDebug( 6040 ) << " newHeight = " << m_height << endl; return true;}voidRenderFlow::insertPositioned(RenderObject *o){ //kdDebug() << renderName() << "::insertPositioned " << this<< isAnonymousBox() << " " << o << endl; if(!specialObjects) { specialObjects = new QSortedList<SpecialObject>; specialObjects->setAutoDelete(true); } // don't insert it twice! QListIterator<SpecialObject> it(*specialObjects); SpecialObject* f; while ( (f = it.current()) ) { if (f->node == o) return; ++it; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -