#include "render_layer.h"
#include <kdebug.h>
#include <assert.h>
#include "khtmlview.h"
#include "render_block.h"
#include "render_arena.h"
#include "xml/dom_docimpl.h"
using namespace DOM;
using namespace khtml;
QWidget* RenderLayer::gScrollBar = 0;
#ifndef NDEBUG
static bool inRenderLayerDetach;
static bool inRenderLayerElementDetach;
static bool inRenderZTreeNodeDetach;
#endif
void
RenderScrollMediator::slotValueChanged(int val)
{
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_height( 0 ),
m_y( 0 ),
m_x( 0 ),
m_width( 0 ),
m_scrollX( 0 ),
m_scrollY( 0 ),
m_scrollWidth( 0 ),
m_scrollHeight( 0 ),
m_hBar( 0 ),
m_vBar( 0 ),
m_scrollMediator( 0 )
{
}
RenderLayer::~RenderLayer()
{
m_parent = m_previous = m_next = m_first = m_last = 0;
delete m_hBar;
delete m_vBar;
delete m_scrollMediator;
}
void RenderLayer::updateLayerPosition()
{
if (renderer()->isCanvas())
return;
int x = m_object->xPos();
int y = m_object->yPos();
if (!m_object->isPositioned()) {
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);
if (parent())
parent()->subtractScrollOffset(x, y);
setPos(x,y);
setWidth(m_object->width());
setHeight(m_object->height());
if (!m_object->style()->hidesOverflow()) {
if (m_object->overflowWidth() > m_object->width())
setWidth(m_object->overflowWidth());
if (m_object->overflowHeight() > m_object->height())
setHeight(m_object->overflowHeight());
}
}
RenderLayer*
RenderLayer::enclosingPositionedAncestor()
{
RenderLayer* curr = parent();
for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isRoot() &&
!curr->m_object->isPositioned() && !curr->m_object->isRelPositioned();
curr = curr->parent());
return curr;
}
RenderLayer*
RenderLayer::transparentAncestor()
{
RenderLayer* curr = parent();
for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent());
return curr;
}
bool
RenderLayer::isTransparent()
{
return m_object->style()->opacity() < 1.0f;
}
static RenderLayer* commonTransparentAncestor(RenderLayer* layer1, RenderLayer* layer2)
{
if (!layer1 || !layer2)
return 0;
for (RenderLayer* currLayer1 = layer1; currLayer1; currLayer1 = currLayer1->transparentAncestor())
for (RenderLayer* currLayer2 = layer2; currLayer2; currLayer2 = currLayer2->transparentAncestor())
if (currLayer1 == currLayer2)
return currLayer1;
return 0;
}
void RenderLayer::updateTransparentState(QPainter* painter, RenderLayer* newLayer, RenderLayer*& currLayer)
{
RenderLayer* transparentLayer = (!newLayer || newLayer->isTransparent()) ? newLayer :
newLayer->transparentAncestor();
if (transparentLayer == currLayer)
return;
RenderLayer* commonAncestor = commonTransparentAncestor(currLayer, transparentLayer);
endTransparencyLayers(painter, currLayer, commonAncestor);
beginTransparencyLayers(painter, transparentLayer, commonAncestor);
currLayer = transparentLayer;
}
void RenderLayer::beginTransparencyLayers(QPainter* painter, RenderLayer* newLayer, RenderLayer* ancestorLayer)
{
if (!newLayer || newLayer == ancestorLayer)
return;
beginTransparencyLayers(painter, newLayer->transparentAncestor(), ancestorLayer);
#ifdef APPLE_CHANGES
painter->beginTransparencyLayer(newLayer->renderer()->style()->opacity());
#endif
}
void RenderLayer::endTransparencyLayers(QPainter* painter, RenderLayer* newLayer, RenderLayer* ancestorLayer)
{
if (!newLayer || newLayer == ancestorLayer)
return;
#ifdef APPLE_CHANGES
painter->endTransparencyLayer();
#endif
endTransparencyLayers(painter, newLayer->transparentAncestor(), ancestorLayer);
}
void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
{
return renderArena->allocate(sz);
}
void RenderLayer::operator delete(void* ptr, size_t sz)
{
assert(inRenderLayerDetach);
*(size_t *)ptr = sz;
}
void RenderLayer::detach(RenderArena* renderArena)
{
#ifndef NDEBUG
inRenderLayerDetach = true;
#endif
delete this;
#ifndef NDEBUG
inRenderLayerDetach = false;
#endif
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);
}
RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
{
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();
oldChild->setPreviousSibling(0);
oldChild->setNextSibling(0);
oldChild->setParent(0);
return oldChild;
}
void RenderLayer::removeOnlyThisLayer()
{
if (!m_parent)
return;
RenderLayer* parent = m_parent;
RenderLayer* nextSib = nextSibling();
parent->removeChild(this);
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()) {
RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
if (parentLayer)
parentLayer->addChild(this,
renderer()->parent()->findNextLayer(parentLayer, renderer()));
}
for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
curr->moveLayers(m_parent, this);
}
void
RenderLayer::convertToLayerCoords(RenderLayer* ancestorLayer, int& x, int& y)
{
if (ancestorLayer == this)
return;
if (m_object->style()->position() == FIXED) {
int xOff, yOff;
m_object->absolutePosition(xOff, yOff, true);
x += xOff;
y += yOff;
return;
}
RenderLayer* parentLayer;
if (m_object->style()->position() == ABSOLUTE)
parentLayer = enclosingPositionedAncestor();
else
parentLayer = parent();
if (!parentLayer) return;
parentLayer->convertToLayerCoords(ancestorLayer, x, y);
x += xPos();
y += yPos();
}
void
RenderLayer::scrollOffset(int& x, int& y)
{
x += scrollXOffset();
y += scrollYOffset();
}
void
RenderLayer::subtractScrollOffset(int& x, int& y)
{
x -= scrollXOffset();
y -= scrollYOffset();
}
void
RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars)
{
if (x < 0) x = 0;
if (y < 0) y = 0;
int maxX = m_scrollWidth - m_object->clientWidth();
int maxY = m_scrollHeight - m_object->clientHeight();
if (x > maxX) x = maxX;
if (y > maxY) y = maxY;
m_scrollX = x;
m_scrollY = y;
m_object->repaint(true);
if (updateScrollbars) {
if (m_hBar)
m_hBar->setValue(m_scrollX);
if (m_vBar)
m_vBar->setValue(m_scrollY);
}
}
void
RenderLayer::updateScrollPositionFromScrollbars()
{
bool needUpdate = false;
int newX = m_scrollX;
int newY = m_scrollY;
if (m_hBar) {
newX = m_hBar->value();
if (newX != m_scrollX)
needUpdate = true;
}
if (m_vBar) {
newY = m_vBar->value();
if (newY != m_scrollY)
needUpdate = true;
}
if (needUpdate)
scrollToOffset(newX, newY, false);
}
void
RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
{
if (hasScrollbar && !m_hBar) {
QScrollView* scrollView = m_object->element()->getDocument()->view();
m_hBar = new QScrollBar(Qt::Horizontal, scrollView);
scrollView->addChild(m_hBar, 0, -50000);
if (!m_scrollMediator)
m_scrollMediator = new RenderScrollMediator(this);
m_scrollMediator->connect(m_hBar, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)));
}
else if (!hasScrollbar && m_hBar) {
m_scrollMediator->disconnect(m_hBar, SIGNAL(valueChanged(int)),
m_scrollMediator, SLOT(slotValueChanged(int)));
delete m_hBar;
m_hBar = 0;
}
}
void
RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
{
if (hasScrollbar && !m_vBar) {
QScrollView* scrollView = m_object->element()->getDocument()->view();
m_vBar = new QScrollBar(Qt::Vertical, scrollView);
scrollView->addChild(m_vBar, 0, -50000);
if (!m_scrollMediator)
m_scrollMediator = new RenderScrollMediator(this);
m_scrollMediator->connect(m_vBar, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)));
}
else if (!hasScrollbar && m_vBar) {
m_scrollMediator->disconnect(m_vBar, SIGNAL(valueChanged(int)),
m_scrollMediator, SLOT(slotValueChanged(int)));
delete m_vBar;
m_vBar = 0;
}
}
int
RenderLayer::verticalScrollbarWidth()
{
if (!m_vBar)
return 0;
return m_vBar->width();
}
int
RenderLayer::horizontalScrollbarHeight()
{
if (!m_hBar)
return 0;
return m_hBar->height();
}
void
RenderLayer::moveScrollbarsAside()
{
if (m_hBar)
m_hBar->move(0, -50000);
if (m_vBar)
m_vBar->move(0, -50000);
}
void
RenderLayer::positionScrollbars(const QRect& absBounds)
{
if (m_vBar) {
m_vBar->move(absBounds.x()+absBounds.width()-m_object->borderRight()-m_vBar->width(),
absBounds.y()+m_object->borderTop());
m_vBar->resize(m_vBar->width(), absBounds.height() -
(m_object->borderTop()+m_object->borderBottom()) -
(m_hBar ? m_hBar->height()-1 : 0));
}
if (m_hBar) {
m_hBar->move(absBounds.x()+m_object->borderLeft(),
absBounds.y()+absBounds.height()-m_object->borderBottom()-m_hBar->height());
m_hBar->resize(absBounds.width() - (m_object->borderLeft()+m_object->borderRight()) -
(m_vBar ? m_vBar->width()-1 : 0),
m_hBar->height());
}
}
#define LINE_STEP 10
#define PAGE_KEEP 40
void
RenderLayer::checkScrollbarsAfterLayout()
{
updateLayerPosition();
int rightPos = m_object->rightmostPosition();
int bottomPos = m_object->lowestPosition();
int clientWidth = m_object->clientWidth();
int clientHeight = m_object->clientHeight();
m_scrollWidth = clientWidth;
m_scrollHeight = clientHeight;
if (rightPos - m_object->borderLeft() > m_scrollWidth)
m_scrollWidth = rightPos - m_object->borderLeft();
if (bottomPos - m_object->borderTop() > m_scrollHeight)
m_scrollHeight = bottomPos - m_object->borderTop();
bool needHorizontalBar = rightPos > m_width;
bool needVerticalBar = bottomPos > m_height;
bool haveHorizontalBar = m_hBar;
bool haveVerticalBar = m_vBar;
if (m_object->style()->overflow() == OSCROLL) {
m_hBar->setEnabled(needHorizontalBar);
m_vBar->setEnabled(needVerticalBar);
}
bool scrollbarsChanged = (m_object->style()->overflow() == OAUTO) &&
(haveHorizontalBar != needHorizontalBar || haveVerticalBar != needVerticalBar);
if (scrollbarsChanged) {
setHasHorizontalScrollbar(needHorizontalBar);
setHasVerticalScrollbar(needVerticalBar);
m_object->setNeedsLayout(true);
if (m_object->isRenderBlock())
static_cast<RenderBlock*>(m_object)->layoutBlock(true);
else
m_object->layout();
return;
}
if (m_hBar) {
int pageStep = (clientWidth-PAGE_KEEP);
if (pageStep < 0) pageStep = clientWidth;
m_hBar->setSteps(LINE_STEP, pageStep);
#ifdef APPLE_CHANGES
m_hBar->setKnobProportion(clientWidth, m_scrollWidth);
#else
m_hBar->setRange(0, m_scrollWidth-clientWidth);
#endif
}
if (m_vBar) {
int pageStep = (clientHeight-PAGE_KEEP);
if (pageStep < 0) pageStep = clientHeight;
m_vBar->setSteps(LINE_STEP, pageStep);
#ifdef APPLE_CHANGES
m_vBar->setKnobProportion(clientHeight, m_scrollHeight);
#else
m_vBar->setRange(0, m_scrollHeight-clientHeight);
#endif
}
}
void
RenderLayer::paintScrollbars(QPainter* p, int x, int y, int w, int h)
{
#if APPLE_CHANGES
if (m_hBar)
m_hBar->paint(p, QRect(x, y, w, h));
if (m_vBar)
m_vBar->paint(p, QRect(x, y, w, h));
#endif
}
void
RenderLayer::paint(QPainter *p, int x, int y, int w, int h, bool selectionOnly)
{
QRect damageRect(x,y,w,h);
RenderZTreeNode* node = constructZTree(damageRect, damageRect, this);
if (!node)
return;
QPtrVector<RenderLayerElement> layerList;
constructLayerList(node, &layerList);
QRect paintRect(x, y, w, h);
QRect currRect(paintRect);
RenderLayer* currentTransparentLayer = 0;
uint count = layerList.count();
for (uint i = 0; i < count; i++) {
RenderLayerElement* elt = layerList.at(i);
bool updatedTransparentState = false;
if (elt->clipOriginator) {
if (elt->backgroundClipRect != currRect) {
if (currRect != paintRect)
p->restore();
updateTransparentState(p, elt->layer, currentTransparentLayer);
updatedTransparentState = true;
currRect = elt->backgroundClipRect;
QRect clippedRect = p->xForm(currRect);
#if APPLE_CHANGES
p->save();
p->addClip(clippedRect);
#else
QRegion creg(cr);
QRegion old = p->clipRegion();
if (!old.isNull())
creg = old.intersect(creg);
p->save();
p->setClipRegion(creg);
#endif
}
elt->layer->renderer()->paintBoxDecorations(p, x, y, w, h,
elt->absBounds.x(),
elt->absBounds.y());
elt->layer->positionScrollbars(elt->absBounds);
#if APPLE_CHANGES
elt->layer->paintScrollbars(p, x, y, w, h);
#endif
}
if (elt->clipRect != currRect) {
if (currRect != paintRect)
p->restore();
if (!updatedTransparentState) {
updateTransparentState(p, elt->layer, currentTransparentLayer);
updatedTransparentState = true;
}
currRect = elt->clipRect;
if (currRect != paintRect) {
QRect clippedRect = p->xForm(currRect);
#if APPLE_CHANGES
p->save();
p->addClip(clippedRect);
#else
QRegion creg(cr);
QRegion old = p->clipRegion();
if (!old.isNull())
creg = old.intersect(creg);
p->save();
p->setClipRegion(creg);
#endif
}
}
if (!updatedTransparentState) {
updateTransparentState(p, elt->layer, currentTransparentLayer);
updatedTransparentState = true;
}
if (currRect.isEmpty())
continue;
if (selectionOnly) {
if (elt->layerElementType == RenderLayerElement::Normal ||
elt->layerElementType == RenderLayerElement::Foreground)
elt->layer->renderer()->paint(p, x, y, w, h,
elt->absBounds.x() - elt->layer->renderer()->xPos(),
elt->absBounds.y() - elt->layer->renderer()->yPos(),
PaintActionSelection);
} else {
if (elt->layerElementType == RenderLayerElement::Normal ||
elt->layerElementType == RenderLayerElement::Background)
elt->layer->renderer()->paint(p, x, y, w, h,
elt->absBounds.x() - elt->layer->renderer()->xPos(),
elt->absBounds.y() - elt->layer->renderer()->yPos(),
PaintActionElementBackground);
if (elt->layerElementType == RenderLayerElement::Normal ||
elt->layerElementType == RenderLayerElement::Foreground) {
elt->layer->renderer()->paint(p, x, y, w, h,
elt->absBounds.x() - elt->layer->renderer()->xPos(),
elt->absBounds.y() - elt->layer->renderer()->yPos(),
PaintActionChildBackgrounds);
elt->layer->renderer()->paint(p, x, y, w, h,
elt->absBounds.x() - elt->layer->renderer()->xPos(),
elt->absBounds.y() - elt->layer->renderer()->yPos(),
PaintActionFloat);
elt->layer->renderer()->paint(p, x, y, w, h,
elt->absBounds.x() - elt->layer->renderer()->xPos(),
elt->absBounds.y() - elt->layer->renderer()->yPos(),
PaintActionForeground);
}
}
}
if (currRect != paintRect)
p->restore();
updateTransparentState(p, 0, currentTransparentLayer);
node->detach(renderer()->renderArena());
}
void
RenderLayer::clearOtherLayersHoverActiveState()
{
if (!m_parent)
return;
for (RenderLayer* curr = m_parent->firstChild(); curr; curr = curr->nextSibling()) {
if (curr == this)
continue;
curr->clearHoverAndActiveState(curr->renderer());
}
m_parent->clearOtherLayersHoverActiveState();
}
void
RenderLayer::clearHoverAndActiveState(RenderObject* obj)
{
if (!obj->mouseInside())
return;
obj->setMouseInside(false);
if (obj->element()) {
obj->element()->setActive(false);
if (obj->style()->affectedByHoverRules() || obj->style()->affectedByActiveRules())
obj->element()->setChanged(true);
}
for (RenderObject* child = obj->firstChild(); child; child = child->nextSibling())
if (child->mouseInside())
clearHoverAndActiveState(child);
}
bool
RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y)
{
gScrollBar = 0;
bool inside = false;
RenderLayer* insideLayer = 0;
QRect damageRect(m_x, m_y, m_width, m_height);
RenderZTreeNode* node = constructZTree(damageRect, damageRect, this, true, x, y);
if (!node)
return false;
QPtrVector<RenderLayerElement> layerList;
constructLayerList(node, &layerList);
uint count = layerList.count();
for (int i = count-1; i >= 0; i--) {
RenderLayerElement* elt = layerList.at(i);
inside = elt->layer->renderer()->nodeAtPoint(info, x, y,
elt->absBounds.x() - elt->layer->renderer()->xPos(),
elt->absBounds.y() - elt->layer->renderer()->yPos());
if (inside) {
if (elt->layerElementType == RenderLayerElement::Foreground &&
info.innerNode() == elt->layer->renderer()->element()) {
inside = false;
info.setInnerNode(0);
info.setInnerNonSharedNode(0);
info.setURLElement(0);
continue;
}
insideLayer = elt->layer;
break;
}
}
node->detach(renderer()->renderArena());
if (insideLayer) {
insideLayer->clearOtherLayersHoverActiveState();
for (RenderLayer* child = insideLayer->firstChild();
child; child = child->nextSibling())
child->clearHoverAndActiveState(child->renderer());
}
return inside;
}
RenderLayer::RenderZTreeNode*
RenderLayer::constructZTree(QRect overflowClipRect, QRect posClipRect,
RenderLayer* rootLayer,
bool eventProcessing, int xMousePos, int yMousePos)
{
RenderArena* renderArena = renderer()->renderArena();
RenderZTreeNode* returnNode = 0;
if (renderer()->style()->visibility() != VISIBLE)
return 0;
updateLayerPosition();
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
QRect layerBounds(x, y, width(), height());
returnNode = new (renderArena) RenderZTreeNode(this);
QRect clipRectToApply = m_object->isPositioned() ? posClipRect : overflowClipRect;
QRect damageRect = clipRectToApply.intersect(layerBounds);
if (m_object->hasClip())
damageRect = damageRect.intersect(m_object->getClipRect(x,y));
bool clipOriginator = false;
if (m_object->hasOverflowClip() || m_object->hasClip()) {
clipOriginator = true;
if (m_object->hasOverflowClip()) {
QRect newOverflowClip = m_object->getOverflowClipRect(x,y);
overflowClipRect = newOverflowClip.intersect(overflowClipRect);
clipRectToApply = clipRectToApply.intersect(newOverflowClip);
if (m_object->isPositioned() || m_object->isRelPositioned())
posClipRect = newOverflowClip.intersect(posClipRect);
}
if (m_object->hasClip()) {
QRect newPosClip = m_object->getClipRect(x,y);
posClipRect = newPosClip.intersect(posClipRect);
overflowClipRect = overflowClipRect.intersect(posClipRect);
clipRectToApply = clipRectToApply.intersect(newPosClip);
}
}
RenderZTreeNode* lastChildNode = 0;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
if (child->zIndex() < 0)
continue;
RenderZTreeNode* childNode = child->constructZTree(overflowClipRect, posClipRect,
rootLayer, eventProcessing,
xMousePos, yMousePos);
if (childNode) {
if (lastChildNode)
lastChildNode->next = childNode;
else
returnNode->child = childNode;
lastChildNode = childNode;
}
}
if (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
renderer()->hasOverhangingFloats() ||
(renderer()->isInline() && !renderer()->isReplaced()) ||
(eventProcessing && damageRect.contains(xMousePos,yMousePos)) ||
(!eventProcessing && layerBounds.intersects(damageRect))) {
RenderLayerElement* layerElt = new (renderArena) RenderLayerElement(this, layerBounds,
damageRect, clipRectToApply,
clipOriginator, x, y);
if (returnNode->child) {
RenderZTreeNode* leaf = new (renderArena) RenderZTreeNode(layerElt);
leaf->next = returnNode->child;
returnNode->child = leaf;
if (!layerElt->zauto)
layerElt->zindex = 0;
}
else
returnNode->layerElement = layerElt;
}
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
if (child->zIndex() >= 0)
continue;
RenderZTreeNode* childNode = child->constructZTree(overflowClipRect, posClipRect,
rootLayer, eventProcessing,
xMousePos, yMousePos);
if (childNode) {
if (returnNode->layerElement) {
RenderZTreeNode* leaf = returnNode;
returnNode = new (renderArena) RenderZTreeNode(this);
returnNode->child = leaf;
}
childNode->next = returnNode->child;
returnNode->child = childNode;
}
}
return returnNode;
}
void
RenderLayer::constructLayerList(RenderZTreeNode* ztree, QPtrVector<RenderLayerElement>* result)
{
QPtrVector<RenderLayerElement> mergeBuffer;
ztree->constructLayerList(&mergeBuffer, result);
}
static void sortByZOrder(QPtrVector<RenderLayer::RenderLayerElement>* buffer,
QPtrVector<RenderLayer::RenderLayerElement>* mergeBuffer,
uint start,
uint end)
{
if (start >= end)
return;
if (end - start <= 6) {
for (uint i = end-1; i > start; i--) {
bool sorted = true;
for (uint j = start; j < i; j++) {
RenderLayer::RenderLayerElement* elt = buffer->at(j);
RenderLayer::RenderLayerElement* elt2 = buffer->at(j+1);
if (elt->zindex > elt2->zindex) {
sorted = false;
buffer->insert(j, elt2);
buffer->insert(j+1, elt);
}
}
if (sorted)
return;
}
}
else {
uint mid = (start+end)/2;
sortByZOrder(buffer, mergeBuffer, start, mid);
sortByZOrder(buffer, mergeBuffer, mid, end);
RenderLayer::RenderLayerElement* elt = buffer->at(mid-1);
RenderLayer::RenderLayerElement* elt2 = buffer->at(mid);
if (elt->zindex <= elt2->zindex)
return;
mergeBuffer->resize(end - start);
uint i1 = start;
uint i2 = mid;
elt = buffer->at(i1);
elt2 = buffer->at(i2);
while (i1 < mid || i2 < end) {
if (i1 < mid && (i2 == end || elt->zindex <= elt2->zindex)) {
mergeBuffer->insert(mergeBuffer->count(), elt);
i1++;
if (i1 < mid)
elt = buffer->at(i1);
}
else {
mergeBuffer->insert(mergeBuffer->count(), elt2);
i2++;
if (i2 < end)
elt2 = buffer->at(i2);
}
}
for (uint i = start; i < end; i++)
buffer->insert(i, mergeBuffer->at(i-start));
mergeBuffer->clear();
}
}
void RenderLayer::RenderZTreeNode::constructLayerList(QPtrVector<RenderLayerElement>* mergeTmpBuffer,
QPtrVector<RenderLayerElement>* buffer)
{
bool autoZIndex = layer->parent() ? layer->hasAutoZIndex() : false;
int explicitZIndex = layer->zIndex();
if (layerElement) {
if (buffer->count() == buffer->size())
buffer->resize(2*(buffer->size()+1));
buffer->insert(buffer->count(), layerElement);
return;
}
uint startIndex = buffer->count();
for (RenderZTreeNode* current = child; current; current = current->next)
current->constructLayerList(mergeTmpBuffer, buffer);
uint endIndex = buffer->count();
if (autoZIndex || !(endIndex-startIndex))
return;
sortByZOrder(buffer, mergeTmpBuffer, startIndex, endIndex);
RenderLayerElement* elt = buffer->at(startIndex);
if (elt->zindex < 0) {
for (uint i = startIndex; i < endIndex; i++) {
elt = buffer->at(i);
if (elt->layer == layer) {
RenderLayerElement* bgLayer =
new (layer->renderer()->renderArena()) RenderLayerElement(*elt);
elt->layerElementType = RenderLayerElement::Foreground;
bgLayer->layerElementType = RenderLayerElement::Background;
if (buffer->count() == buffer->size())
buffer->resize(2*(buffer->size()+1));
for (uint j = buffer->count(); j > startIndex; j--)
buffer->insert(j, buffer->at(j-1));
buffer->insert(startIndex, bgLayer);
endIndex++;
break;
}
}
}
for (uint i = startIndex; i < endIndex; i++) {
elt = buffer->at(i);
elt->zindex = explicitZIndex;
}
}
void* RenderLayer::RenderLayerElement::operator new(size_t sz, RenderArena* renderArena) throw()
{
void* result = renderArena->allocate(sz);
if (result)
memset(result, 0, sz);
return result;
}
void RenderLayer::RenderLayerElement::operator delete(void* ptr, size_t sz)
{
assert(inRenderLayerElementDetach);
*(size_t *)ptr = sz;
}
void RenderLayer::RenderLayerElement::detach(RenderArena* renderArena)
{
#ifndef NDEBUG
inRenderLayerElementDetach = true;
#endif
delete this;
#ifndef NDEBUG
inRenderLayerElementDetach = false;
#endif
renderArena->free(*(size_t *)this, this);
}
void* RenderLayer::RenderZTreeNode::operator new(size_t sz, RenderArena* renderArena) throw()
{
void* result = renderArena->allocate(sz);
if (result)
memset(result, 0, sz);
return result;
}
void RenderLayer::RenderZTreeNode::operator delete(void* ptr, size_t sz)
{
assert(inRenderZTreeNodeDetach);
*(size_t *)ptr = sz;
}
void RenderLayer::RenderZTreeNode::detach(RenderArena* renderArena)
{
assert(!next);
RenderZTreeNode *n;
for (RenderZTreeNode *c = child; c; c = n) {
n = c->next;
c->next = 0;
c->detach(renderArena);
}
if (layerElement)
layerElement->detach(renderArena);
#ifndef NDEBUG
inRenderZTreeNodeDetach = true;
#endif
delete this;
#ifndef NDEBUG
inRenderZTreeNodeDetach = false;
#endif
renderArena->free(*(size_t *)this, this);
}
QPtrVector<RenderLayer::RenderLayerElement> RenderLayer::elementList(RenderZTreeNode *&node)
{
QPtrVector<RenderLayerElement> list;
QRect damageRect(m_x, m_y, m_width, m_height);
node = constructZTree(damageRect, damageRect, this);
if (node) {
constructLayerList(node, &list);
}
return list;
}