📄 render_layer.cpp
字号:
/* * Copyright (C) 2003 Apple Computer, Inc. * * Portions are Copyright (C) 1998 Netscape Communications Corporation. * * Other contributors: * Robert O'Callahan <roc+@cs.cmu.edu> * David Baron <dbaron@fas.harvard.edu> * Christian Biesinger <cbiesinger@web.de> * Randall Jesup <rjesup@wgate.com> * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> * Josh Soref <timeless@mac.com> * Boris Zbarsky <bzbarsky@mit.edu> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Alternatively, the contents of this file may be used under the terms * of either the Mozilla Public License Version 1.1, found at * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html * (the "GPL"), in which case the provisions of the MPL or the GPL are * applicable instead of those above. If you wish to allow use of your * version of this file only under the terms of one of those two * licenses (the MPL or the GPL) and not to allow others to use your * version of this file under the LGPL, indicate your decision by * deletingthe provisions above and replace them with the notice and * other provisions required by the MPL or the GPL, as the case may be. * If you do not delete the provisions above, a recipient may use your * version of this file under any of the LGPL, the MPL or the GPL. *///#define BOX_DEBUG#include "render_layer.h"#include <kdebug.h>#include <assert.h>#include "khtmlview.h"#include "render_canvas.h"#include "render_arena.h"#include "render_replaced.h"#include "xml/dom_docimpl.h"#include "xml/dom2_eventsimpl.h"#include "misc/htmltags.h"#include "html/html_blockimpl.h"#include <qscrollbar.h>#include <qptrvector.h>#include <qstyle.h>using namespace DOM;using namespace khtml;#ifdef APPLE_CHANGESQScrollBar* RenderLayer::gScrollBar = 0;#endif#ifndef NDEBUGstatic bool inRenderLayerDetach;#endifvoidRenderScrollMediator::slotValueChanged(){ m_layer->updateScrollPositionFromScrollbars();}RenderLayer::RenderLayer(RenderObject* object): m_object( object ),m_parent( 0 ),m_previous( 0 ),m_next( 0 ),m_first( 0 ),m_last( 0 ),m_x( 0 ),m_y( 0 ),m_scrollX( 0 ),m_scrollY( 0 ),m_scrollWidth( 0 ),m_scrollHeight( 0 ),m_hBar( 0 ),m_vBar( 0 ),m_scrollMediator( 0 ),m_posZOrderList( 0 ),m_negZOrderList( 0 ),m_zOrderListsDirty( true ),m_markedForRepaint( false ),m_marquee( 0 ){}RenderLayer::~RenderLayer(){ // Child layers will be deleted by their corresponding render objects, so // our destructor doesn't have to do anything. delete m_hBar; delete m_vBar; delete m_scrollMediator; delete m_posZOrderList; delete m_negZOrderList; delete m_marquee;}void RenderLayer::updateLayerPosition(){ // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we // don't need to ever update our layer position here. if (renderer()->isCanvas()) return; int x = m_object->xPos(); int y = m_object->yPos(); if (!m_object->isPositioned()) { // We must adjust our position by walking up the render tree looking for the // nearest enclosing object with a layer. RenderObject* curr = m_object->parent(); while (curr && !curr->layer()) { x += curr->xPos(); y += curr->yPos(); curr = curr->parent(); } } if (m_object->isRelPositioned()) static_cast<RenderBox*>(m_object)->relativePositionOffset(x, y); // Subtract our parent's scroll offset. if (m_object->isPositioned() && enclosingPositionedAncestor()) { RenderLayer* positionedParent = enclosingPositionedAncestor(); // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. positionedParent->subtractScrollOffset(x, y); if (positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isInlineFlow()) { // When we have an enclosing relpositioned inline, we need to add in the offset of the first line // box from the rest of the content, but only in the cases where we know we're positioned // relative to the inline itself. RenderFlow* flow = static_cast<RenderFlow*>(positionedParent->renderer()); int sx = 0, sy = 0; if (flow->firstLineBox()) { if (flow->style()->direction() == LTR) sx = flow->firstLineBox()->xPos(); else sx = flow->lastLineBox()->xPos(); sy = flow->firstLineBox()->yPos(); } else { sx = flow->staticX(); // ### sy = flow->staticY(); } bool isInlineType = m_object->style()->isOriginalDisplayInlineType(); if (!m_object->hasStaticX()) x += sx; // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers // do. if (m_object->hasStaticX() && !isInlineType) // Avoid adding in the left border/padding of the containing block twice. Subtract it out. x += sx - (m_object->containingBlock()->borderLeft() + m_object->containingBlock()->paddingLeft()); if (!m_object->hasStaticY()) y += sy; } } else if (parent()) parent()->subtractScrollOffset(x, y); setPos(x,y);}void RenderLayer::repaint( bool markForRepaint ){ if (markForRepaint && m_markedForRepaint) return; for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->repaint( markForRepaint ); QRect layerBounds, damageRect, fgrect; calculateRects(renderer()->canvas()->layer(), renderer()->viewRect(), layerBounds, damageRect, fgrect); m_visibleRect = damageRect.intersect( layerBounds ); if (m_visibleRect.isValid()) renderer()->canvas()->repaintViewRectangle( m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height() ); if (markForRepaint) m_markedForRepaint = true;}void RenderLayer::updateLayerPositions(RenderLayer* rootLayer, bool doFullRepaint, bool checkForRepaint){ if (doFullRepaint) { m_object->repaint(); checkForRepaint = doFullRepaint = false; } updateLayerPosition(); // For relpositioned layers or non-positioned layers, // we need to keep in sync, since we may have shifted relative // to our parent layer. if (m_hBar || m_vBar) { // Need to position the scrollbars. int x = 0; int y = 0; convertToLayerCoords(rootLayer, x, y); QRect layerBounds = QRect(x,y,width(),height()); positionScrollbars(layerBounds); }#ifdef APPLE_CHANGES // FIXME: Child object could override visibility. if (checkForRepaint && (m_object->style()->visibility() == VISIBLE)) m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_fullRepaintRect);#else if (checkForRepaint && m_markedForRepaint) { QRect layerBounds, damageRect, fgrect; calculateRects(rootLayer, renderer()->viewRect(), layerBounds, damageRect, fgrect); QRect vr = damageRect.intersect( layerBounds ); if (vr != m_visibleRect && vr.isValid()) renderer()->canvas()->repaintViewRectangle( vr.x(), vr.y(), vr.width(), vr.height() ); } m_markedForRepaint = false; #endif for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->updateLayerPositions(rootLayer, doFullRepaint, checkForRepaint); // With all our children positioned, now update our marquee if we need to. if (m_marquee) m_marquee->updateMarqueePosition();}short RenderLayer::width() const{ int w = m_object->width(); if (!m_object->style()->hidesOverflow()) w = kMax(m_object->overflowWidth(), w); return w;}int RenderLayer::height() const{ int h = m_object->height(); if (!m_object->style()->hidesOverflow()) h = kMax(m_object->overflowHeight(), h); return h;}RenderLayer *RenderLayer::stackingContext() const{ RenderLayer* curr = parent(); for ( ; curr && !curr->m_object->isCanvas() && curr->m_object->style()->hasAutoZIndex(); curr = curr->parent()); return curr;}RenderLayer* RenderLayer::enclosingPositionedAncestor() const{ RenderLayer* curr = parent(); for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned(); curr = curr->parent()); return curr;}#ifdef APPLE_CHANGESbool RenderLayer::isTransparent(){ return m_object->style()->opacity() < 1.0f;}RenderLayer* RenderLayer::transparentAncestor(){ RenderLayer* curr = parent(); for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent()); return curr;}#endifvoid* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw(){ return renderArena->allocate(sz);}void RenderLayer::operator delete(void* ptr, size_t sz){ assert(inRenderLayerDetach); // Stash size where detach can find it. *(size_t *)ptr = sz;}void RenderLayer::detach(RenderArena* renderArena){#ifndef NDEBUG inRenderLayerDetach = true;#endif delete this;#ifndef NDEBUG inRenderLayerDetach = false;#endif // Recover the size left there for us by operator delete and free the memory. renderArena->free(*(size_t *)this, this);}void RenderLayer::addChild(RenderLayer *child, RenderLayer* beforeChild){ RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild(); if (prevSibling) { child->setPreviousSibling(prevSibling); prevSibling->setNextSibling(child); } else setFirstChild(child); if (beforeChild) { beforeChild->setPreviousSibling(child); child->setNextSibling(beforeChild); } else setLastChild(child); child->setParent(this); // Dirty the z-order list in which we are contained. The stackingContext() can be null in the // case where we're building up generated content layers. This is ok, since the lists will start // off dirty in that case anyway. RenderLayer* stackingContext = child->stackingContext(); if (stackingContext) stackingContext->dirtyZOrderLists();}RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild){ // remove the child if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); if (m_first == oldChild) m_first = oldChild->nextSibling(); if (m_last == oldChild) m_last = oldChild->previousSibling(); // Dirty the z-order list in which we are contained. When called via the // reattachment process in removeOnlyThisLayer, the layer may already be disconnected // from the main layer tree, so we need to null-check the |stackingContext| value. RenderLayer* stackingContext = oldChild->stackingContext(); if (stackingContext) oldChild->stackingContext()->dirtyZOrderLists(); oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); return oldChild;}void RenderLayer::removeOnlyThisLayer(){ if (!m_parent) return; // Remove us from the parent. RenderLayer* parent = m_parent; RenderLayer* nextSib = nextSibling(); parent->removeChild(this); // Now walk our kids and reattach them to our parent. RenderLayer* current = m_first; while (current) { RenderLayer* next = current->nextSibling(); removeChild(current); parent->addChild(current, nextSib); current = next; } detach(renderer()->renderArena());}void RenderLayer::insertOnlyThisLayer(){ if (!m_parent && renderer()->parent()) { // We need to connect ourselves when our renderer() has a parent. // Find our enclosingLayer and add ourselves. RenderLayer* parentLayer = renderer()->parent()->enclosingLayer(); if (parentLayer) parentLayer->addChild(this, renderer()->parent()->findNextLayer(parentLayer, renderer())); } // Remove all descendant layers from the hierarchy and add them to the new position. for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) curr->moveLayers(m_parent, this);}void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const{ if (ancestorLayer == this) return; if (m_object->style()->position() == FIXED) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -