📄 render_box.cpp
字号:
static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
RenderObject* po = parent();
for (; po && po != cb; po = po->parent())
static_distance += po->xPos();
if (l == AUTO || style()->left().isStatic())
l = static_distance;
}
else if ((parent()->style()->direction()==RTL && (l==AUTO && r==AUTO ))
|| style()->right().isStatic())
{
RenderObject* po = parent();
static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
while (po && po!=containingBlock()) {
static_distance+=po->xPos();
po=po->parent();
}
if (r==AUTO || style()->right().isStatic())
r = static_distance;
}
calcAbsoluteHorizontalValues(Width, cb, cw, pab, static_distance, l, r, m_width, m_marginLeft, m_marginRight, m_x);
// Avoid doing any work in the common case (where the values of min-width and max-width are their defaults).
int minW = m_width, minML, minMR, minX;
calcAbsoluteHorizontalValues(MinWidth, cb, cw, pab, static_distance, l, r, minW, minML, minMR, minX);
int maxW = m_width, maxML, maxMR, maxX;
if (style()->maxWidth().value != UNDEFINED)
calcAbsoluteHorizontalValues(MaxWidth, cb, cw, static_distance, pab, l, r, maxW, maxML, maxMR, maxX);
if (m_width > maxW) {
m_width = maxW;
m_marginLeft = maxML;
m_marginRight = maxMR;
m_x = maxX;
}
if (m_width < minW) {
m_width = minW;
m_marginLeft = minML;
m_marginRight = minMR;
m_x = minX;
}
}
void RenderBox::calcAbsoluteHorizontalValues(WidthType widthType, RenderObject* cb, int cw, int pab, int static_distance,
int l, int r, int& w, int& ml, int& mr, int& x)
{
const int AUTO = -666666;
w = ml = mr = AUTO;
if (!style()->marginLeft().isVariable())
ml = style()->marginLeft().width(cw);
if (!style()->marginRight().isVariable())
mr = style()->marginRight().width(cw);
Length width;
if (widthType == Width)
width = style()->width();
else if (widthType == MinWidth)
width = style()->minWidth();
else
width = style()->maxWidth();
if (!width.isVariable())
w = width.width(cw);
else if (isReplaced())
w = intrinsicWidth();
if (l != AUTO && w != AUTO && r != AUTO) {
// left, width, right all given, play with margins
int ot = l + w + r + pab;
if (ml==AUTO && mr==AUTO) {
// both margins auto, solve for equality
ml = (cw - ot)/2;
mr = cw - ot - ml;
}
else if (ml==AUTO)
// solve for left margin
ml = cw - ot - mr;
else if (mr==AUTO)
// solve for right margin
mr = cw - ot - ml;
else {
// overconstrained, solve according to dir
if (style()->direction() == LTR)
r = cw - ( l + w + ml + mr + pab);
else
l = cw - ( r + w + ml + mr + pab);
}
}
else
{
// one or two of (left, width, right) missing, solve
// auto margins are ignored
if (ml==AUTO) ml = 0;
if (mr==AUTO) mr = 0;
//1. solve left & width.
if (l == AUTO && w == AUTO && r != AUTO) {
// From section 10.3.7 of the CSS2.1 specification.
// "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
w = kMin(kMax(m_minWidth - pab, cw - (r + ml + mr + pab)), m_maxWidth - pab);
l = cw - (r + w + ml + mr + pab);
}
else
//2. solve left & right. use static positioning.
if (l == AUTO && w != AUTO && r == AUTO) {
if (style()->direction()==RTL) {
r = static_distance;
l = cw - (r + w + ml + mr + pab);
}
else {
l = static_distance;
r = cw - (l + w + ml + mr + pab);
}
} //3. solve width & right.
else if (l != AUTO && w == AUTO && r == AUTO) {
// From section 10.3.7 of the CSS2.1 specification.
// "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
w = kMin(kMax(m_minWidth - pab, cw - (l + ml + mr + pab)), m_maxWidth - pab);
r = cw - (l + w + ml + mr + pab);
}
else
//4. solve left
if (l==AUTO && w!=AUTO && r!=AUTO)
l = cw - (r + w + ml + mr + pab);
else
//5. solve width
if (l!=AUTO && w==AUTO && r!=AUTO)
w = cw - (r + l + ml + mr + pab);
else
//6. solve right
if (l!=AUTO && w!=AUTO && r==AUTO)
r = cw - (l + w + ml + mr + pab);
}
w += pab;
x = l + ml + cb->borderLeft();
}
void RenderBox::calcAbsoluteVertical()
{
// css2 spec 10.6.4 & 10.6.5
// based on
// http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata
// (actually updated 2000-10-24)
// that introduces static-position value for top, left & right
const int AUTO = -666666;
int t, b, ch;
t = b = AUTO;
int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
// We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
RenderObject* cb = container();
if (cb->isRoot()) // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
// position as though the root fills the viewport.
ch = cb->availableHeight();
else
ch = cb->height() - cb->borderTop() - cb->borderBottom();
if (!style()->top().isVariable())
t = style()->top().width(ch);
if (!style()->bottom().isVariable())
b = style()->bottom().width(ch);
int h, mt, mb, y;
calcAbsoluteVerticalValues(Height, cb, ch, pab, t, b, h, mt, mb, y);
// Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
int minH = h, minMT, minMB, minY;
calcAbsoluteVerticalValues(MinHeight, cb, ch, pab, t, b, minH, minMT, minMB, minY);
int maxH = h, maxMT, maxMB, maxY;
if (style()->maxHeight().value != UNDEFINED)
calcAbsoluteVerticalValues(MaxHeight, cb, ch, pab, t, b, maxH, maxMT, maxMB, maxY);
if (h > maxH) {
h = maxH;
mt = maxMT;
mb = maxMB;
y = maxY;
}
if (h < minH) {
h = minH;
mt = minMT;
mb = minMB;
y = minY;
}
// If our natural height exceeds the new height once we've set it, then we need to make sure to update
// overflow to track the spillout.
if (m_height > h)
setOverflowHeight(m_height);
// Set our final values.
m_height = h;
m_marginTop = mt;
m_marginBottom = mb;
m_y = y;
}
void RenderBox::calcAbsoluteVerticalValues(HeightType heightType, RenderObject* cb, int ch, int pab,
int t, int b, int& h, int& mt, int& mb, int& y)
{
const int AUTO = -666666;
h = mt = mb = AUTO;
if (!style()->marginTop().isVariable())
mt = style()->marginTop().width(ch);
if (!style()->marginBottom().isVariable())
mb = style()->marginBottom().width(ch);
Length height;
if (heightType == Height)
height = style()->height();
else if (heightType == MinHeight)
height = style()->minHeight();
else
height = style()->maxHeight();
int ourHeight = m_height;
if (isTable() && height.isVariable())
// Height is never unsolved for tables. "auto" means shrink to fit. Use our
// height instead.
h = ourHeight - pab;
else if (!height.isVariable())
{
h = height.width(ch);
if (ourHeight - pab > h)
ourHeight = h + pab;
}
else if (isReplaced())
h = intrinsicHeight();
int static_top=0;
if ((t == AUTO && b == AUTO) || style()->top().isStatic()) {
// calc hypothetical location in the normal flow
// used for 1) top=static-position
// 2) top, bottom, height are all auto -> calc top -> 3.
// 3) precalc for case 2 below
static_top = m_staticY - cb->borderTop(); // Should already have been set through layout of the parent().
RenderObject* po = parent();
for (; po && po != cb; po = po->parent())
static_top += po->yPos();
if (h == AUTO || style()->top().isStatic())
t = static_top;
}
if (t != AUTO && h != AUTO && b != AUTO) {
// top, height, bottom all given, play with margins
int ot = h + t + b + pab;
if (mt == AUTO && mb == AUTO) {
// both margins auto, solve for equality
mt = (ch - ot)/2;
mb = ch - ot - mt;
}
else if (mt==AUTO)
// solve for top margin
mt = ch - ot - mb;
else if (mb==AUTO)
// solve for bottom margin
mb = ch - ot - mt;
else
// overconstrained, solve for bottom
b = ch - (h + t + mt + mb + pab);
}
else {
// one or two of (top, height, bottom) missing, solve
// auto margins are ignored
if (mt == AUTO)
mt = 0;
if (mb == AUTO)
mb = 0;
//1. solve top & height. use content height.
if (t == AUTO && h == AUTO && b != AUTO) {
h = ourHeight - pab;
t = ch - (h + b + mt + mb + pab);
}
else if (t == AUTO && h != AUTO && b == AUTO) //2. solve top & bottom. use static positioning.
{
t = static_top;
b = ch - (h + t + mt + mb + pab);
}
else if (t != AUTO && h == AUTO && b == AUTO) //3. solve height & bottom. use content height.
{
h = ourHeight - pab;
b = ch - (h + t + mt + mb + pab);
}
else
//4. solve top
if (t == AUTO && h != AUTO && b != AUTO)
t = ch - (h + b + mt + mb + pab);
else
//5. solve height
if (t != AUTO && h == AUTO && b != AUTO)
h = ch - (t + b + mt + mb + pab);
else
//6. solve bottom
if (t != AUTO && h != AUTO && b == AUTO)
b = ch - (h + t + mt + mb + pab);
}
if (ourHeight < h + pab) //content must still fit
ourHeight = h + pab;
if (hasOverflowClip() && ourHeight > h + pab)
ourHeight = h + pab;
// Do not allow the height to be negative. This can happen when someone specifies both top and bottom
// but the containing block height is less than top, e.g., top:20px, bottom:0, containing block height 16.
ourHeight = kMax(0, ourHeight);
h = ourHeight;
y = t + mt + cb->borderTop();
}
QRect RenderBox::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
{
// FIXME: Is it OK to check only first child instead of picking
// right child based on offset? Is it OK to pass the same offset
// along to the child instead of offset 0 or whatever?
// propagate it downwards to its children, someone will feel responsible
RenderObject *child = firstChild();
if (child) {
QRect result = child->caretRect(offset, affinity, extraWidthToEndOfLine);
// FIXME: in-band signalling!
if (result.isEmpty())
return result;
}
int _x, _y, height;
// if not, use the extents of this box
// offset 0 means left, offset 1 means right
_x = xPos() + (offset == 0 ? 0 : m_width);
InlineBox *box = inlineBoxWrapper();
if (box) {
height = box->root()->bottomOverflow() - box->root()->topOverflow();
_y = box->root()->topOverflow();
}
else {
_y = yPos();
height = m_height;
}
// If height of box is smaller than font height, use the latter one,
// otherwise the caret might become invisible.
//
// Also, if the box is not a replaced element, always use the font height.
// This prevents the "big caret" bug described in:
// <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
//
// FIXME: ignoring :first-line, missing good reason to take care of
int fontHeight = style()->fontMetrics().height();
if (fontHeight > height || !isReplaced())
height = fontHeight;
int absx, absy;
RenderObject *cb = containingBlock();
if (cb && cb != this && cb->absolutePosition(absx,absy)) {
_x += absx;
_y += absy;
}
else {
// we don't know our absolute position, and there is no point returning
// just a relative one
return QRect();
}
if (extraWidthToEndOfLine)
*extraWidthToEndOfLine = m_width - _x;
return QRect(_x, _y, 1, height);
}
int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
{
if (!includeSelf || !m_width)
return 0;
int bottom = m_height;
if (isRelPositioned())
bottom += relativePositionOffsetY();
return bottom;
}
int RenderBox::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
if (!includeSelf || !m_height)
return 0;
int right = m_width;
if (isRelPositioned())
right += relativePositionOffsetX();
return right;
}
int RenderBox::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
if (!includeSelf || !m_height)
return m_width;
int left = 0;
if (isRelPositioned())
left += relativePositionOffsetX();
return left;
}
#undef DEBUG_LAYOUT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -