📄 render_inline.cpp
字号:
/* * This file is part of the render object implementation for KHTML. * * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) * (C) 2002-2003 Dirk Mueller (mueller@kde.org) * (C) 2003 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include <kglobal.h>#include "rendering/render_arena.h"#include "rendering/render_inline.h"#include "rendering/render_block.h"#include "xml/dom_docimpl.h"#include <qvaluevector.h>using namespace khtml;void RenderInline::setStyle(RenderStyle* _style){ RenderFlow::setStyle(_style); setInline(true); // Ensure that all of the split inlines pick up the new style. We // only do this if we're an inline, since we don't want to propagate // a block's style to the other inlines. // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before // and after the block share the same style, but the block doesn't // need to pass its style on to anyone else. RenderFlow* currCont = continuation(); while (currCont) { if (currCont->isInline()) { RenderFlow* nextCont = currCont->continuation(); currCont->setContinuation(0); currCont->setStyle(style()); currCont->setContinuation(nextCont); } currCont = currCont->continuation(); } // Update pseudos for ::before and ::after now. updatePseudoChildren();}bool RenderInline::isInlineContinuation() const{ return m_isContinuation;}void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild){ // Make sure we don't append things after :after-generated content if we have it. if (!beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER) beforeChild = lastChild(); if (!newChild->isText() && newChild->style()->position() != STATIC) setOverhangingContents(); if (!newChild->isInline() && !newChild->isFloatingOrPositioned() ) { // We are placing a block inside an inline. We have to perform a split of this // inline into continuations. This involves creating an anonymous block box to hold // |newChild|. We then make that block box a continuation of this inline. We take all of // the children after |beforeChild| and put them in a clone of this object. RenderBlock *newBox = createAnonymousBlock(); RenderFlow* oldContinuation = continuation(); setContinuation(newBox); // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content // has to move into the inline continuation. Call updatePseudoChild to ensure that our :after // content gets properly destroyed. bool isLastChild = (beforeChild == lastChild()); updatePseudoChild(RenderStyle::AFTER, lastChild()); if (isLastChild && beforeChild != lastChild()) beforeChild = 0; // We destroyed the last child, so now we need to update our insertion // point to be 0. It's just a straight append now. splitFlow(beforeChild, newBox, newChild, oldContinuation); return; } RenderBox::addChild(newChild,beforeChild); newChild->setNeedsLayoutAndMinMaxRecalc();}RenderInline* RenderInline::cloneInline(RenderFlow* src){ RenderInline *o = new (src->renderArena()) RenderInline(src->element()); o->m_isContinuation = true; o->setStyle(src->style()); return o;}void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock, RenderObject* beforeChild, RenderFlow* oldCont){ // Create a clone of this inline. RenderInline* clone = cloneInline(this); clone->setContinuation(oldCont); // Now take all of the children from beforeChild to the end and remove // then from |this| and place them in the clone. RenderObject* o = beforeChild; while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); clone->addChildToFlow(removeChildNode(tmp), 0); tmp->setNeedsLayoutAndMinMaxRecalc(); } // Hook |clone| up as the continuation of the middle block. middleBlock->setContinuation(clone); // We have been reparented and are now under the fromBlock. We need // to walk up our inline parent chain until we hit the containing block. // Once we hit the containing block we're done. RenderFlow* curr = static_cast<RenderFlow*>(parent()); RenderFlow* currChild = this; while (curr && curr != fromBlock) { // Create a new clone. RenderInline* cloneChild = clone; clone = cloneInline(curr); // Insert our child clone as the first child. clone->addChildToFlow(cloneChild, 0); // Hook the clone up as a continuation of |curr|. RenderFlow* oldCont = curr->continuation(); curr->setContinuation(clone); clone->setContinuation(oldCont); // Now we need to take all of the children starting from the first child // *after* currChild and append them all to the clone. o = currChild->nextSibling(); while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); clone->appendChildNode(curr->removeChildNode(tmp)); tmp->setNeedsLayoutAndMinMaxRecalc(); } // Keep walking up the chain. currChild = curr; curr = static_cast<RenderFlow*>(curr->parent()); } // Now we are at the block level. We need to put the clone into the toBlock. toBlock->appendChildNode(clone); // Now take all the children after currChild and remove them from the fromBlock // and put them in the toBlock. o = currChild->nextSibling(); while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); toBlock->appendChildNode(fromBlock->removeChildNode(tmp)); }}void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild, RenderFlow* oldCont){ RenderBlock* pre = 0; RenderBlock* block = containingBlock(); bool madeNewBeforeBlock = false; if (block->isAnonymousBlock()) { // We can reuse this block and make it the preBlock of the next continuation. pre = block; block = block->containingBlock(); } else { // No anonymous block available for use. Make one. pre = block->createAnonymousBlock(); madeNewBeforeBlock = true; } RenderBlock* post = block->createAnonymousBlock(); RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); if (madeNewBeforeBlock) block->insertChildNode(pre, boxFirst); block->insertChildNode(newBlockBox, boxFirst); block->insertChildNode(post, boxFirst); block->setChildrenInline(false); if (madeNewBeforeBlock) { RenderObject* o = boxFirst; while (o) { RenderObject* no = o; o = no->nextSibling(); pre->appendChildNode(block->removeChildNode(no)); no->setNeedsLayoutAndMinMaxRecalc(); } } splitInlines(pre, post, newBlockBox, beforeChild, oldCont); // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting // time in makeChildrenNonInline by just setting this explicitly up front. newBlockBox->setChildrenInline(false); // We don't just call addChild, since it would pass things off to the // continuation, so we call addChildToFlow explicitly instead. We delayed // adding the newChild until now so that the |newBlockBox| would be fully // connected, thus allowing newChild access to a renderArena should it need // to wrap itself in additional boxes (e.g., table construction). newBlockBox->addChildToFlow(newChild, 0); // XXXdwh is any of this even necessary? I don't think it is. pre->close(); pre->setPos(0, -500000); pre->setNeedsLayout(true); newBlockBox->close(); newBlockBox->setPos(0, -500000); newBlockBox->setNeedsLayout(true); post->close(); post->setPos(0, -500000); post->setNeedsLayout(true); block->setNeedsLayoutAndMinMaxRecalc();}void RenderInline::paint(PaintInfo& i, int _tx, int _ty){#ifdef DEBUG_LAYOUT // kdDebug( 6040 ) << renderName() << "(RenderInline) " << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")" << endl;#endif if ( i.phase == PaintActionElementBackground ) return; // let the children their backgrounds PaintAction oldphase = i.phase; if ( i.phase == PaintActionChildBackgrounds ) i.phase = PaintActionChildBackground; paintLineBoxBackgroundBorder(i, _tx, _ty); for( RenderObject *child = firstChild(); child; child = child->nextSibling()) if(!child->layer() && !child->isFloating()) child->paint(i, _tx, _ty); paintLineBoxDecorations(i, _tx, _ty); i.phase = oldphase; if (style()->visibility() == VISIBLE && i.phase == PaintActionOutline) { paintOutlines(i.p, _tx, _ty); }}/** * Appends the given coordinate-pair to the point-array if it is not * equal to the last element. * @param pointArray point-array * @param pnt point to append * @return \c true if \c pnt has actually been appended */inline static bool appendIfNew(QValueVector<QPoint> &pointArray, const QPoint &pnt){// if (!pointArray.isEmpty()) kdDebug(6040) << "appifnew: " << pointArray.back() << " == " << pnt << ": " << (pointArray.back() == pnt) << endl;// else kdDebug(6040) << "appifnew: " << pnt << " (unconditional)" << endl; if (!pointArray.isEmpty() && pointArray.back() == pnt) return false; pointArray.append(pnt); return true;}/** * Does spike-reduction on the given point-array's stack-top. * * Spikes are path segments of which one goes forward, and the sucessor * goes backward on the predecessor's segment: * * 2 0 1 * x------x<-----x * (0 is stack-top in point-array) * * This will be reduced to * 1 0 * x------x * * Preconditions: * - No other spikes exist in the whole point-array except at most * one at the end * - No two succeeding points are ever equal * - For each two succeeding points either p1.x == p2.x or p1.y == p2.y holds * true * - No such spike exists where 2 is situated between 0 and 1. * * Postcondition: * - No spikes exist in the whole point-array * * If no spike is found, the point-array is left unchanged. * @return \c true if an actual reduction was done */inline static bool reduceSpike(QValueVector<QPoint> &pointArray)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -