📄 render_layer.cpp
字号:
{
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;
// Dirty the clip rects.
clearClipRects();
// 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);
// Clear out all the clip rects.
clearClipRects();
}
void
RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
{
if (ancestorLayer == this)
return;
if (m_object->style()->position() == FIXED) {
// Add in the offset of the view. We can obtain this by calling
// absolutePosition() on the RenderCanvas.
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, bool repaint)
{
if (renderer()->style()->overflow() != OMARQUEE) {
if (x < 0) x = 0;
if (y < 0) y = 0;
// Call the scrollWidth/Height functions so that the dimensions will be computed if they need
// to be (for overflow:hidden blocks).
int maxX = scrollWidth() - m_object->clientWidth();
int maxY = scrollHeight() - m_object->clientHeight();
if (x > maxX) x = maxX;
if (y > maxY) y = maxY;
}
// FIXME: Eventually, we will want to perform a blit. For now never
// blit, since the check for blitting is going to be very
// complicated (since it will involve testing whether our layer
// is either occluded by another layer or clipped by an enclosing
// layer or contains fixed backgrounds, etc.).
m_scrollX = x;
m_scrollY = y;
// Update the positions of our child layers.
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(false, false);
#if APPLE_CHANGES
// Move our widgets.
m_object->updateWidgetPositions();
// Update dashboard regions, scrolling may change the clip of a
// particular region.
RenderCanvas *canvas = renderer()->canvas();
if (canvas)
canvas->view()->updateDashboardRegions();
#endif
// Fire the scroll DOM event.
m_object->element()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, true, false);
// Just schedule a full repaint of our object.
if (repaint)
m_object->repaint();
if (updateScrollbars) {
if (m_hBar)
m_hBar->setValue(m_scrollX);
if (m_vBar)
m_vBar->setValue(m_scrollY);
}
}
void RenderLayer::scrollRectToVisible(const QRect &rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
RenderLayer* parentLayer = 0;
QRect newRect = rect;
int xOffset = 0, yOffset = 0;
if (m_object->hasOverflowClip()) {
QRect layerBounds = QRect(m_x + m_scrollX, m_y + m_scrollY, m_width, m_height);
QRect exposeRect = QRect(rect.x() + m_scrollX, rect.y() + m_scrollY, rect.width(), rect.height());
QRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
xOffset = r.x() - m_x;
yOffset = r.y() - m_y;
// Adjust offsets if they're outside of the allowable range.
xOffset = kMax(0, kMin(m_scrollWidth - m_width, xOffset));
yOffset = kMax(0, kMin(m_scrollHeight - m_height, yOffset));
if (xOffset != m_scrollX || yOffset != m_scrollY) {
int diffX = m_scrollX;
int diffY = m_scrollY;
scrollToOffset(xOffset, yOffset);
diffX = m_scrollX - diffX;
diffY = m_scrollY - diffY;
newRect.setX(rect.x() - diffX);
newRect.setY(rect.y() - diffY);
}
if (m_object->parent())
parentLayer = m_object->parent()->enclosingLayer();
} else {
QScrollView* view = m_object->document()->view();
if (view) {
QRect viewRect = QRect(view->scrollXOffset(), view->scrollYOffset(), view->visibleWidth(), view->visibleHeight());
QRect r = getRectToExpose(viewRect, rect, alignX, alignY);
xOffset = r.x();
yOffset = r.y();
// Adjust offsets if they're outside of the allowable range.
xOffset = kMax(0, kMin(view->contentsWidth(), xOffset));
yOffset = kMax(0, kMin(view->contentsHeight(), yOffset));
if (m_object->document() && m_object->document()->ownerElement() && m_object->document()->ownerElement()->renderer()) {
view->setContentsPos(xOffset, yOffset);
parentLayer = m_object->document()->ownerElement()->renderer()->enclosingLayer();
newRect.setX(rect.x() - view->contentsX() + view->viewport()->x());
newRect.setY(rect.y() - view->contentsY() + view->viewport()->y());
}
else {
// If this is the outermost view that RenderLayer needs to scroll, then we should scroll the view recursively
// Other apps, like Mail, rely on this feature.
view->scrollPointRecursively(xOffset, yOffset);
}
}
}
if (parentLayer)
parentLayer->scrollRectToVisible(newRect, alignX, alignY);
}
QRect RenderLayer::getRectToExpose(const QRect &visibleRect, const QRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) {
int x, y, w, h;
x = exposeRect.x();
y = exposeRect.y();
w = exposeRect.width();
h = exposeRect.height();
// Find the appropriate X coordinate to scroll to.
ScrollBehavior scrollX = getHiddenBehavior(alignX);
int intersectWidth = visibleRect.intersect(exposeRect).width();
// If the rectangle is fully visible, use the specified visible behavior.
// If the rectangle is partially visible, but over a certain threshold, then treat it as fully visible to avoid unnecessary horizontal scrolling
if (intersectWidth == w || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
scrollX = getVisibleBehavior(alignX);
else if (intersectWidth == visibleRect.width()) {
// If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
if (getVisibleBehavior(alignX) == alignCenter)
scrollX = noScroll;
else
scrollX = getVisibleBehavior(alignX);
}
// If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
else if (intersectWidth > 0)
scrollX = getPartialBehavior(alignX);
if (scrollX == noScroll)
x = visibleRect.x();
// If we're trying to align to the closest edge, and the exposeRect is further right than the visibleRect, and not bigger than the visible area, then alignRight.
else if ((scrollX == alignRight) || ((scrollX == alignToClosestEdge) && exposeRect.right() > visibleRect.right() && w < visibleRect.width()))
x = exposeRect.right() - visibleRect.width();
else if (scrollX == alignCenter)
x -= (visibleRect.width() - w) / 2;
// By default, x is set to the left of the exposeRect, so for the alignLeft case,
// or the alignToClosestEdge case where the closest edge is the left edge, then x does not need to be changed.
w = visibleRect.width();
// Find the appropriate Y coordinate to scroll to.
ScrollBehavior scrollY = getHiddenBehavior(alignY);
int intersectHeight = visibleRect.intersect(exposeRect).height();
// If the rectangle is fully visible, use the specified visible behavior.
if (intersectHeight == h)
scrollY = getVisibleBehavior(alignY);
else if (intersectHeight == visibleRect.height()) {
// If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
if (getVisibleBehavior(alignY) == alignCenter)
scrollY = noScroll;
else
scrollY = getVisibleBehavior(alignY);
}
// If the rectangle is partially visible, use the specified partial behavior
else if (intersectHeight > 0)
scrollY = getPartialBehavior(alignY);
if (scrollY == noScroll)
y = visibleRect.y();
// If we're trying to align to the closest edge, and the exposeRect is further down than the visibleRect, and not bigger than the visible area, then alignBottom.
else if ((scrollY == alignBottom) || ((scrollY == alignToClosestEdge) && exposeRect.bottom() > visibleRect.bottom() && h < visibleRect.height()))
y = exposeRect.bottom() - visibleRect.height();
else if (scrollY == alignCenter)
y -= (visibleRect.height() - h) / 2;
// By default, y is set to the top of the exposeRect, so for the alignTop case,
// or the alignToEdgeY case where the closest edge is the top edge, then y does not need to be changed.
h = visibleRect.height();
return QRect(x, y, w, h);
}
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, 0);
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) {
QScrollView* scrollView = m_object->element()->getDocument()->view();
scrollView->removeChild (m_hBar);
m_scrollMediator->disconnect(m_hBar, SIGNAL(valueChanged(int)),
m_scrollMediator, SLOT(slotValueChanged(int)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -