📄 render_block.cpp
字号:
// width computation will take into account the delta between |leftOff| and |xPos|
// so that we can just pass the content width in directly to the |calcHorizontalMargins|
// function.
static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
chPos = leftOff + child->marginLeft();
}
}
child->setPos(chPos, child->yPos());
} else {
int xPos = m_width - borderRight() - paddingRight() - (includeScrollbarSize() ? m_layer->verticalScrollbarWidth() : 0);
int chPos = xPos - (child->width() + child->marginRight());
if (child->avoidsFloats()) {
int rightOff = rightOffset(m_height);
if (style()->textAlign() != KHTML_CENTER && child->style()->marginRight().type != Variable) {
if (child->marginRight() < 0)
rightOff -= child->marginRight();
chPos = kMin(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit.
} else if (rightOff != xPos) {
// The object is shifting left. The object might be centered, so we need to
// recalculate our horizontal margins. Note that the containing block content
// width computation will take into account the delta between |rightOff| and |xPos|
// so that we can just pass the content width in directly to the |calcHorizontalMargins|
// function.
static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
chPos = rightOff - child->marginRight() - child->width();
}
}
child->setPos(chPos, child->yPos());
}
}
void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
{
if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) {
// Update our max pos/neg bottom margins, since we collapsed our bottom margins
// with our children.
m_maxBottomPosMargin = kMax(m_maxBottomPosMargin, marginInfo.posMargin());
m_maxBottomNegMargin = kMax(m_maxBottomNegMargin, marginInfo.negMargin());
if (!marginInfo.bottomQuirk())
m_bottomMarginQuirk = false;
if (marginInfo.bottomQuirk() && marginBottom() == 0)
// We have no bottom margin and our last child has a quirky margin.
// We will pick up this quirky margin and pass it through.
// This deals with the <td><div><p> case.
m_bottomMarginQuirk = true;
}
}
void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo)
{
// If our last flow was a self-collapsing block that cleared a float, then we don't
// collapse it with the bottom of the block.
if (!marginInfo.selfCollapsingBlockClearedFloat())
marginInfo.setAtBottomOfBlock(true);
// If we can't collapse with children then go ahead and add in the bottom margin.
if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()
&& (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk()))
m_height += marginInfo.margin();
// Now add in our bottom border/padding.
m_height += bottom;
// Negative margins can cause our height to shrink below our minimal height (border/padding).
// If this happens, ensure that the computed height is increased to the minimal height.
m_height = kMax(m_height, top + bottom);
// Always make sure our overflow height is at least our height.
m_overflowHeight = kMax(m_height, m_overflowHeight);
// Update our bottom collapsed margin info.
setCollapsedBottomMargin(marginInfo);
}
void RenderBlock::layoutBlockChildren(bool relayoutChildren)
{
int top = borderTop() + paddingTop();
int bottom = borderBottom() + paddingBottom() + (includeScrollbarSize() ? m_layer->horizontalScrollbarHeight() : 0);
m_height = m_overflowHeight = top;
// The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
MarginInfo marginInfo(this, top, bottom);
CompactInfo compactInfo;
// Fieldsets need to find their legend and position it inside the border of the object.
// The legend then gets skipped during normal layout.
RenderObject* legend = layoutLegend(relayoutChildren);
RenderObject* child = firstChild();
while (child) {
if (legend == child) {
child = child->nextSibling();
continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
}
int oldTopPosMargin = m_maxTopPosMargin;
int oldTopNegMargin = m_maxTopNegMargin;
// Make sure we layout children if they need it.
// FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
// an auto value. Add a method to determine this, so that we can avoid the relayout.
if (relayoutChildren || child->style()->height().isPercent())
child->setChildNeedsLayout(true);
// Handle the four types of special elements first. These include positioned content, floating content, compacts and
// run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
bool handled = false;
RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled);
if (handled) { child = next; continue; }
// The child is a normal flow object. Compute its vertical margins now.
child->calcVerticalMargins();
// Do not allow a collapse if the margin top collapse style is set to SEPARATE.
if (child->style()->marginTopCollapse() == MSEPARATE) {
marginInfo.setAtTopOfBlock(false);
marginInfo.clearMargin();
}
// Try to guess our correct y position. In most cases this guess will
// be correct. Only if we're wrong (when we compute the real y position)
// will we have to potentially relayout.
int yPosEstimate = estimateVerticalPosition(child, marginInfo);
// If an element might be affected by the presence of floats, then always mark it for
// layout.
if (!child->avoidsFloats() || child->usesLineWidth()) {
int fb = floatBottom();
if (fb > m_height || fb > yPosEstimate)
child->setChildNeedsLayout(true);
}
// Cache our old position so that we can dirty the proper repaint rects if the child moves.
int oldChildX = child->xPos();
int oldChildY = child->yPos();
// Go ahead and position the child as though it didn't collapse with the top.
child->setPos(child->xPos(), yPosEstimate);
child->layoutIfNeeded();
// Now determine the correct ypos based off examination of collapsing margin
// values.
collapseMargins(child, marginInfo, yPosEstimate);
// Now check for clear.
clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin);
// We are no longer at the top of the block if we encounter a non-empty child.
// This has to be done after checking for clear, so that margins can be reset if a clear occurred.
if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock())
marginInfo.setAtTopOfBlock(false);
// Now place the child in the correct horizontal position
determineHorizontalPosition(child);
// Update our top overflow in case the child spills out the top of the block.
m_overflowTop = kMin(m_overflowTop, child->yPos() + child->overflowTop(false));
// Update our height now that the child has been placed in the correct position.
m_height += child->height();
if (child->style()->marginBottomCollapse() == MSEPARATE) {
m_height += child->marginBottom();
marginInfo.clearMargin();
}
int overflowDelta = child->overflowHeight(false) - child->height();
if (m_height + overflowDelta > m_overflowHeight)
m_overflowHeight = m_height + overflowDelta;
// If the child has overhanging floats that intrude into following siblings (or possibly out
// of this block), then the parent gets notified of the floats now.
addOverhangingFloats(static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos());
// See if this child has made our overflow need to grow.
int rightChildPos = child->xPos() + kMax(child->overflowWidth(false), child->width());
m_overflowWidth = kMax(rightChildPos, m_overflowWidth);
m_overflowLeft = kMin(child->xPos() + child->overflowLeft(false), m_overflowLeft);
// Insert our compact into the block margin if we have one.
insertCompactIfNeeded(child, compactInfo);
// If the child moved, we have to repaint it as well as any floating/positioned
// descendants. An exception is if we need a layout. In this case, we know we're going to
// repaint ourselves (and the child) anyway.
if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
child->repaintDuringLayoutIfMoved(oldChildX, oldChildY);
child = child->nextSibling();
}
// Now do the handling of the bottom of the block, adding in our bottom border/padding and
// determining the correct collapsed bottom margin information.
handleBottomOfBlock(top, bottom, marginInfo);
// Finished. Clear the dirty layout bits.
setNeedsLayout(false);
}
void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
{
if (m_positionedObjects) {
//kdDebug( 6040 ) << renderName() << " " << this << "::layoutPositionedObjects() start" << endl;
RenderObject* r;
QPtrListIterator<RenderObject> it(*m_positionedObjects);
for ( ; (r = it.current()); ++it ) {
// When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
// non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
// objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
// positioned explicitly) this should not incur a performance penalty.
if (relayoutChildren || (r->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow()))
r->setChildNeedsLayout(true);
r->layoutIfNeeded();
}
}
}
void RenderBlock::markPositionedObjectsForLayout()
{
if (m_positionedObjects) {
RenderObject* r;
QPtrListIterator<RenderObject> it(*m_positionedObjects);
for (; (r = it.current()); ++it)
r->setChildNeedsLayout(true);
}
}
void RenderBlock::getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& fullBounds)
{
bounds = fullBounds = getAbsoluteRepaintRect();
// Include any overhanging floats (if we know we're the one to paint them).
// We null-check m_floatingObjects here to catch any cases where m_height ends up negative
// for some reason. I think I've caught all those cases, but this way we stay robust and don't
// crash.
if (hasOverhangingFloats() && m_floatingObjects) {
FloatingObject* r;
QPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it) {
// Only repaint the object if our noPaint flag isn't set and if it isn't in
// its own layer.
if (!r->noPaint && !r->node->layer()) {
QRect childRect, childFullRect;
r->node->getAbsoluteRepaintRectIncludingFloats(childRect, childFullRect);
fullBounds = fullBounds.unite(childFullRect);
}
}
}
}
void RenderBlock::repaintFloatingDescendants()
{
// Repaint any overhanging floats (if we know we're the one to paint them).
if (hasOverhangingFloats()) {
FloatingObject* r;
QPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it) {
// Only repaint the object if our noPaint flag isn't set and if it isn't in
// its own layer.
if (!r->noPaint && !r->node->layer()) {
r->node->repaint();
r->node->repaintFloatingDescendants();
}
}
}
}
void RenderBlock::repaintObjectsBeforeLayout()
{
RenderFlow::repaintObjectsBeforeLayout();
if (!needsLayout())
return;
// Walk our positioned objects.
if (m_positionedObjects) {
RenderObject* r;
QPtrListIterator<RenderObject> it(*m_positionedObjects);
for ( ; (r = it.current()); ++it )
r->repaintObjectsBeforeLayout();
}
}
#ifdef NOKIA_CHANGES
void RenderBlock::getRenderersInRect(QPtrList<BoxInfo>& boxInfoList,int deltaX,int deltaY,const QRect& rect)
{
if (!isTableCell()){
deltaX += m_x;
deltaY += m_y;
// Check if we need to do anything at all.
if (!isInlineFlow() && !isRoot() && !isCanvas() && !isRoot() && !isBody()) {
QRect overflowBox = overflowRect(false);
overflowBox.setX(overflowBox.x() + deltaX);
overflowBox.setY(overflowBox.y() + deltaY);
bool intersectsOverflowBox = overflowBox.intersects(rect);
if (!intersectsOverflowBox) {
// Check floats next.
QRect floatBox = floatRect();
floatBox.setX(floatBox.x() + deltaX);
floatBox.setY(floatBox.y() + deltaY);
if (!floatBox.intersects(rect))
return;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -