📄 render_box.cpp
字号:
if (cw<0) cw = 0;
m_marginLeft = 0;
m_marginRight = 0;
if (isInline() && !isInlineBlockOrInlineTable())
{
// just calculate margins
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
if (treatAsReplaced)
{
m_width = w.width(cw);
m_width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
if(m_width < m_minWidth) m_width = m_minWidth;
}
return;
}
else {
LengthType widthType, minWidthType, maxWidthType;
if (treatAsReplaced) {
m_width = w.width(cw);
m_width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
widthType = w.type;
} else {
m_width = calcWidthUsing(Width, cw, widthType);
int minW = calcWidthUsing(MinWidth, cw, minWidthType);
int maxW = style()->maxWidth().value == UNDEFINED ?
m_width : calcWidthUsing(MaxWidth, cw, maxWidthType);
if (m_width > maxW) {
m_width = maxW;
widthType = maxWidthType;
}
if (m_width < minW) {
m_width = minW;
widthType = minWidthType;
}
}
if (widthType == Variable) {
// kdDebug( 6040 ) << "variable" << endl;
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
}
else
{
// kdDebug( 6040 ) << "non-variable " << w.type << ","<< w.value << endl;
calcHorizontalMargins(ml,mr,cw);
}
}
if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline() &&
!cb->isFlexibleBox())
{
if (cb->style()->direction()==LTR)
m_marginRight = cw - m_width - m_marginLeft;
else
m_marginLeft = cw - m_width - m_marginRight;
}
}
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << "RenderBox::calcWidth(): m_width=" << m_width << " containingBlockWidth()=" << containingBlockWidth() << endl;
kdDebug( 6040 ) << "m_marginLeft=" << m_marginLeft << " m_marginRight=" << m_marginRight << endl;
#endif
}
int RenderBox::calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType)
{
int width = m_width;
Length w;
if (widthType == Width)
w = style()->width();
else if (widthType == MinWidth)
w = style()->minWidth();
else
w = style()->maxWidth();
lengthType = w.type;
if (lengthType == Variable) {
int marginLeft = style()->marginLeft().minWidth(cw);
int marginRight = style()->marginRight().minWidth(cw);
if (cw) width = cw - marginLeft - marginRight;
if (sizesToMaxWidth()) {
if (width < m_minWidth)
width = m_minWidth;
if (width > m_maxWidth)
width = m_maxWidth;
}
}
else
{
width = w.width(cw);
width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
}
return width;
}
void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
{
if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased.
{
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
}
else
{
if ( (ml.type == Variable && mr.type == Variable && m_width<cw) ||
(ml.type != Variable && mr.type != Variable &&
containingBlock()->style()->textAlign() == KHTML_CENTER) )
{
m_marginLeft = (cw - m_width)/2;
if (m_marginLeft<0) m_marginLeft=0;
m_marginRight = cw - m_width - m_marginLeft;
}
else if ( (mr.type == Variable && m_width<cw) ||
(ml.type != Variable && containingBlock()->style()->direction() == RTL &&
containingBlock()->style()->textAlign() == KHTML_LEFT))
{
m_marginLeft = ml.width(cw);
m_marginRight = cw - m_width - m_marginLeft;
}
else if ( (ml.type == Variable && m_width<cw) ||
(mr.type != Variable && containingBlock()->style()->direction() == LTR &&
containingBlock()->style()->textAlign() == KHTML_RIGHT))
{
m_marginRight = mr.width(cw);
m_marginLeft = cw - m_width - m_marginRight;
}
else
{
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
}
}
}
void RenderBox::calcHeight()
{
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << "RenderBox::calcHeight()" << endl;
#endif
// Cell height is managed by the table and inline non-replaced elements do not support a height property.
if (isTableCell() || (isInline() && !isReplaced()))
return;
if (isPositioned())
calcAbsoluteVertical();
else
{
calcVerticalMargins();
// For tables, calculate margins only
if (isTable())
return;
Length h;
bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
bool stretching = parent()->style()->boxAlign() == BSTRETCH;
bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() && (!inHorizontalBox || !stretching);
bool checkMinMaxHeight = false;
// The parent box is flexing us, so it has increased or decreased our height. We have to
// grab our cached flexible height.
if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
&& parent()->isFlexingChildren())
h = Length(m_overrideSize - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
else if (treatAsReplaced)
h = Length(calcReplacedHeight(), Fixed);
else {
h = style()->height();
checkMinMaxHeight = true;
}
// Block children of horizontal flexible boxes fill the height of the box.
if (h.isVariable() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
&& parent()->isStretchingChildren()) {
h = Length(parent()->contentHeight() - marginTop() - marginBottom() -
borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
checkMinMaxHeight = false;
}
int height;
if (checkMinMaxHeight) {
height = calcHeightUsing(style()->height());
int minH = calcHeightUsing(style()->minHeight());
int maxH = style()->maxHeight().value == UNDEFINED ? height : calcHeightUsing(style()->maxHeight());
height = kMin(maxH, height);
height = kMax(minH, height);
}
else
// The only times we don't check min/max height are when a fixed length has
// been given as an override. Just use that.
height = h.value + borderTop() + paddingTop() + borderBottom() + paddingBottom();
m_height = height;
}
// Unfurling marquees override with the furled height.
if (style()->overflow() == OMARQUEE && m_layer && m_layer->marquee() &&
m_layer->marquee()->isUnfurlMarquee() && !m_layer->marquee()->isHorizontal()) {
m_layer->marquee()->setEnd(m_height);
m_height = kMin(m_height, m_layer->marquee()->unfurlPos());
}
// WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
// <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
// is specified.
if (style()->htmlHacks() && style()->height().isVariable() &&
!isFloatingOrPositioned() && (isRoot() || isBody())) {
int margins = collapsedMarginTop() + collapsedMarginBottom();
int visHeight = canvas()->view()->visibleHeight();
if (isRoot())
m_height = kMax(m_height, visHeight - margins);
else
m_height = kMax(m_height, visHeight -
(margins + parent()->marginTop() + parent()->marginBottom() +
parent()->borderTop() + parent()->borderBottom() +
parent()->paddingTop() + parent()->paddingBottom()));
}
}
int RenderBox::calcHeightUsing(const Length& h)
{
if (!h.isVariable()) {
int height = -1;
if (h.isFixed())
height = h.value;
else if (h.isPercent())
height = calcPercentageHeight(h);
if (height != -1) {
height += borderTop() + paddingTop() + borderBottom() + paddingBottom();
return height;
}
}
return m_height;
}
int RenderBox::calcPercentageHeight(const Length& height)
{
int result = -1;
bool includeBorderPadding = isTable();
RenderBlock* cb = containingBlock();
if (style()->htmlHacks()) {
// In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
// block that may have a specified height and then use it. In strict mode, this violates the
// specification, which states that percentage heights just revert to auto if the containing
// block has an auto height.
for ( ; !cb->isCanvas() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() &&
cb->style()->height().isVariable(); cb = cb->containingBlock());
}
// Table cells violate what the CSS spec says to do with heights. Basically we
// don't care if the cell specified a height or not. We just always make ourselves
// be a percentage of the cell's current content height.
if (cb->isTableCell()) {
result = cb->overrideSize();
if (result == -1) {
// Normally we would let the cell size intrinsically, but scrolling overflow has to be
// treated differently, since WinIE lets scrolled overflow regions shrink as needed.
// While we can't get all cases right, we can at least detect when the cell has a specified
// height or when the table has a specified height. In these cases we want to initially have
// no size and allow the flexing of the table or the cell to its specified height to cause us
// to grow to fill the space. This could end up being wrong in some cases, but it is
// preferable to the alternative (sizing intrinsically and making the row end up too big).
RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
if (scrollsOverflow() &&
(!cell->style()->height().isVariable() || !cell->table()->style()->height().isVariable()))
return 0;
return -1;
}
includeBorderPadding = true;
}
// Otherwise we only use our percentage height if our containing block had a specified
// height.
else if (cb->style()->height().isFixed())
result = cb->style()->height().value;
else if (cb->style()->height().isPercent())
// We need to recur and compute the percentage height for our containing block.
result = cb->calcPercentageHeight(cb->style()->height());
else if (cb->isCanvas() || (cb->isBody() && style()->htmlHacks())) {
// Don't allow this to affect the block' m_height member variable, since this
// can get called while the block is still laying out its kids.
int oldHeight = cb->height();
cb->calcHeight();
result = cb->contentHeight();
cb->setHeight(oldHeight);
}
if (result != -1) {
result = height.width(result);
if (includeBorderPadding) {
// It is necessary to use the border-box to match WinIE's broken
// box model. This is essential for sizing inside
// table cells using percentage heights.
result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
result = kMax(0, result);
}
}
return result;
}
int RenderBox::calcReplacedWidth() const
{
int width = calcReplacedWidthUsing(Width);
int minW = calcReplacedWidthUsing(MinWidth);
int maxW = style()->maxWidth().value == UNDEFINED ? width : calcReplacedWidthUsing(MaxWidth);
if (width > maxW)
width = maxW;
if (width < minW)
width = minW;
return width;
}
int RenderBox::calcReplacedWidthUsing(WidthType widthType) const
{
Length w;
if (widthType == Width)
w = style()->width();
else if (widthType == MinWidth)
w = style()->minWidth();
else
w = style()->maxWidth();
switch (w.type) {
case Fixed:
return w.value;
case Percent:
{
const int cw = containingBlockWidth();
if (cw > 0) {
int result = w.minWidth(cw);
return result;
}
}
// fall through
default:
return intrinsicWidth();
}
}
int RenderBox::calcReplacedHeight() const
{
int height = calcReplacedHeightUsing(Height);
int minH = calcReplacedHeightUsing(MinHeight);
int maxH = style()->maxHeight().value == UNDEFINED ? height : calcReplacedHeightUsing(MaxHeight);
if (height > maxH)
height = maxH;
if (height < minH)
height = minH;
return height;
}
int RenderBox::calcReplacedHeightUsing(HeightType heightType) const
{
Length h;
if (heightType == Height)
h = style()->height();
else if (heightType == MinHeight)
h = style()->minHeight();
else
h = style()->maxHeight();
switch( h.type ) {
case Percent:
return availableHeightUsing(h);
case Fixed:
return h.value;
default:
return intrinsicHeight();
};
}
int RenderBox::availableHeight() const
{
return availableHeightUsing(style()->height());
}
int RenderBox::availableHeightUsing(const Length& h) const
{
if (h.isFixed())
return h.value;
if (isCanvas())
return static_cast<const RenderCanvas*>(this)->viewportHeight();
// We need to stop here, since we don't want to increase the height of the table
// artificially. We're going to rely on this cell getting expanded to some new
// height, and then when we lay out again we'll use the calculation below.
if (isTableCell() && (h.isVariable() || h.isPercent())) {
return overrideSize() - (borderLeft()+borderRight()+paddingLeft()+paddingRight());
}
if (h.isPercent())
return h.width(containingBlock()->availableHeight());
return containingBlock()->availableHeight();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -