📄 render_block.cpp
字号:
BoxInfo* sel = new BoxInfo;
sel->renderObject = this;
sel->absoluteXPos = deltaX;
sel->absoluteYPos = deltaY;
sel->width = m_width;
sel->height = m_height;
sel->area = 0;
boxInfoList.append(sel);
for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
if(!child->isFloating() && !child->layer())
child->getRenderersInRect(boxInfoList, deltaX, deltaY,rect);
}
//handle floats
if (!m_floatingObjects)
return;
FloatingObject* r;
QPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it) {
int tx = deltaX + r->left - r->node->xPos() + r->node->marginLeft();
int ty = deltaY + r->startY - r->node->yPos() + r->node->marginTop();
r->node->getRenderersInRect(boxInfoList, tx, ty,rect);
}
}
#endif
void RenderBlock::paint(PaintInfo& i, int _tx, int _ty)
{
_tx += m_x;
_ty += m_y;
// Check if we need to do anything at all.
if (!isInlineFlow() && !isRoot()) {
QRect overflowBox = overflowRect(false);
overflowBox.inflate(maximalOutlineSize(i.phase));
overflowBox.setX(overflowBox.x() + _tx);
overflowBox.setY(overflowBox.y() + _ty);
bool intersectsOverflowBox = overflowBox.intersects(i.r);
if (!intersectsOverflowBox) {
// Check floats next.
QRect floatBox = floatRect();
floatBox.inflate(maximalOutlineSize(i.phase));
floatBox.setX(floatBox.x() + _tx);
floatBox.setY(floatBox.y() + _ty);
if (!floatBox.intersects(i.r))
return;
}
}
return paintObject(i, _tx, _ty);
}
void RenderBlock::paintChildren(PaintInfo& i, int _tx, int _ty)
{
// We don't paint our own background, but we do let the kids paint their backgrounds.
PaintInfo paintInfo(i.p, i.r, i.phase == PaintActionChildBlockBackgrounds ? PaintActionChildBlockBackground : i.phase,
paintingRootForChildren(i));
bool isPrinting = (i.p->device()->devType() == QInternal::Printer);
for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
// Check for page-break-before: always, and if it's set, break and bail.
if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS &&
inRootBlockContext() && (_ty + child->yPos()) > i.r.y() &&
(_ty + child->yPos()) < i.r.y() + i.r.height()) {
canvas()->setBestTruncatedAt(_ty + child->yPos(), this, true);
return;
}
if (!child->layer() && !child->isFloating())
child->paint(paintInfo, _tx, _ty);
// Check for page-break-after: always, and if it's set, break and bail.
if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS &&
inRootBlockContext() && (_ty + child->yPos() + child->height()) > i.r.y() &&
(_ty + child->yPos() + child->height()) < i.r.y() + i.r.height()) {
canvas()->setBestTruncatedAt(_ty + child->yPos() + child->height() + child->collapsedMarginBottom(), this, true);
return;
}
}
}
void RenderBlock::paintCaret(PaintInfo& i, CaretType type)
{
const Selection &s = type == CursorCaret ? document()->part()->selection() : document()->part()->dragCaret();
NodeImpl *caretNode = s.start().node();
RenderObject *renderer = caretNode ? caretNode->renderer() : 0;
if (renderer && (renderer == this || renderer->containingBlock() == this) && caretNode && caretNode->isContentEditable()) {
if (type == CursorCaret) {
document()->part()->paintCaret(i.p, i.r);
} else {
document()->part()->paintDragCaret(i.p, i.r);
}
}
}
void RenderBlock::paintObject(PaintInfo& i, int _tx, int _ty)
{
PaintAction paintAction = i.phase;
// If we're a repositioned run-in or a compact, don't paint background/borders.
bool inlineFlow = isInlineFlow();
// 1. paint background, borders etc
if (!inlineFlow &&
(paintAction == PaintActionBlockBackground || paintAction == PaintActionChildBlockBackground) &&
shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE) {
paintBoxDecorations(i, _tx, _ty);
}
// We're done. We don't bother painting any children.
if (paintAction == PaintActionBlockBackground)
return;
// Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s
int scrolledX = _tx;
int scrolledY = _ty;
if (hasOverflowClip())
m_layer->subtractScrollOffset(scrolledX, scrolledY);
// 2. paint contents
if (childrenInline())
paintLines(i, scrolledX, scrolledY);
else
paintChildren(i, scrolledX, scrolledY);
// 3. paint selection
if (!inlineFlow)
paintSelection(i, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
// 4. paint floats.
if (!inlineFlow && (paintAction == PaintActionFloat || paintAction == PaintActionSelection))
paintFloats(i, scrolledX, scrolledY, paintAction == PaintActionSelection);
// 5. paint outline.
if (!inlineFlow && paintAction == PaintActionOutline &&
style()->outlineWidth() && style()->visibility() == VISIBLE)
paintOutline(i.p, _tx, _ty, width(), height(), style());
// 6. paint caret.
// If the caret's node's render object's containing block is this block, and the paint action is PaintActionForeground,
// then paint the caret.
if (!inlineFlow && paintAction == PaintActionForeground) {
paintCaret(i, CursorCaret);
paintCaret(i, DragCaret);
}
#ifdef BOX_DEBUG
if ( style() && style()->visibility() == VISIBLE ) {
if(isAnonymous())
outlineBox(i.p, _tx, _ty, "green");
if(isFloating())
outlineBox(i.p, _tx, _ty, "yellow");
else
outlineBox(i.p, _tx, _ty);
}
#endif
}
void RenderBlock::paintFloats(PaintInfo& i, int _tx, int _ty, bool paintSelection)
{
if (!m_floatingObjects)
return;
FloatingObject* r;
QPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it) {
// Only paint the object if our noPaint flag isn't set.
if (!r->noPaint && !r->node->layer()) {
PaintInfo info(i.p, i.r, paintSelection ? PaintActionSelection : PaintActionBlockBackground, i.paintingRoot);
int tx = _tx + r->left - r->node->xPos() + r->node->marginLeft();
int ty = _ty + r->startY - r->node->yPos() + r->node->marginTop();
r->node->paint(info, tx, ty);
if (!paintSelection) {
info.phase = PaintActionChildBlockBackgrounds;
r->node->paint(info, tx, ty);
info.phase = PaintActionFloat;
r->node->paint(info, tx, ty);
info.phase = PaintActionForeground;
r->node->paint(info, tx, ty);
info.phase = PaintActionOutline;
r->node->paint(info, tx, ty);
}
}
}
}
void RenderBlock::paintEllipsisBoxes(PaintInfo& i, int _tx, int _ty)
{
if (!shouldPaintWithinRoot(i) || !firstLineBox())
return;
if (style()->visibility() == VISIBLE && i.phase == PaintActionForeground) {
// We can check the first box and last box and avoid painting if we don't
// intersect.
int yPos = _ty + firstLineBox()->yPos();;
int h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos();
if( (yPos >= i.r.y() + i.r.height()) || (yPos + h <= i.r.y()))
return;
// See if our boxes intersect with the dirty rect. If so, then we paint
// them. Note that boxes can easily overlap, so we can't make any assumptions
// based off positions of our first line box or our last line box.
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
yPos = _ty + curr->yPos();
h = curr->height();
if (curr->ellipsisBox() && (yPos < i.r.y() + i.r.height()) && (yPos + h > i.r.y()))
curr->paintEllipsisBox(i, _tx, _ty);
}
}
}
void RenderBlock::setSelectionState(SelectionState s)
{
if (m_selectionState == s)
return;
if (s == SelectionInside && m_selectionState != SelectionNone)
return;
if ((s == SelectionStart && m_selectionState == SelectionEnd) ||
(s == SelectionEnd && m_selectionState == SelectionStart))
m_selectionState = SelectionBoth;
else
m_selectionState = s;
RenderBlock* cb = containingBlock();
if (cb && !cb->isCanvas())
cb->setSelectionState(s);
}
bool RenderBlock::shouldPaintSelectionGaps() const
{
return m_selectionState != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
}
bool RenderBlock::isSelectionRoot() const
{
// FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
return (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable());
}
GapRects RenderBlock::selectionGapRects()
{
if (!shouldPaintSelectionGaps())
return GapRects();
int tx, ty;
absolutePosition(tx, ty);
int lastTop = -borderTopExtra();
int lastLeft = leftSelectionOffset(this, lastTop);
int lastRight = rightSelectionOffset(this, lastTop);
return fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight);
}
void RenderBlock::paintSelection(PaintInfo& i, int tx, int ty)
{
if (shouldPaintSelectionGaps() && i.phase == PaintActionForeground) {
int lastTop = -borderTopExtra();
int lastLeft = leftSelectionOffset(this, lastTop);
int lastRight = rightSelectionOffset(this, lastTop);
fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &i);
}
}
GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, int& lastTop, int& lastLeft, int& lastRight,
const PaintInfo* i)
{
// FIXME: overflow: auto/scroll regions need more math here, since painting in the border box is different from painting in the padding box (one is scrolled, the other is
// fixed).
GapRects result;
if (!isBlockFlow())
return result;
if (childrenInline())
result = fillInlineSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, i);
else
result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, i);
// Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
if (rootBlock == this && (m_selectionState != SelectionBoth && m_selectionState != SelectionEnd))
result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height() + borderBottomExtra(),
rootBlock, blockX, blockY, i));
return result;
}
GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* i)
{
GapRects result;
RenderObject* selStart = canvas()->selectionStart();
// If there is no selection, don't try to get the selection's containing block.
// If we do, we'll crash.
bool containsStart = (selStart && (selStart == this || selStart->containingBlock() == this));
if (!firstLineBox()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -