📄 render_object.cpp
字号:
return !document()->view()->needsFullRepaint() && !layer();
}
void RenderObject::repaintObjectsBeforeLayout()
{
if (!needsLayout() || isText())
return;
bool blockWithInlineChildren = (isRenderBlock() && !isTable() && normalChildNeedsLayout() && childrenInline());
if (selfNeedsLayout()) {
repaint();
if (blockWithInlineChildren)
return;
}
for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
if (!current->isPositioned()) // RenderBlock subclass method handles walking the positioned objects.
current->repaintObjectsBeforeLayout();
}
}
QRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow)
{
QRect r(getAbsoluteRepaintRect());
r.setRect(r.x()-ow, r.y()-ow, r.width()+ow*2, r.height()+ow*2);
if (continuation() && !isInline())
r.setRect(r.x(), r.y()-collapsedMarginTop(), r.width(), r.height()+collapsedMarginTop()+collapsedMarginBottom());
if (isInlineFlow()) {
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isText()) {
QRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow);
r = r.unite(childRect);
}
}
}
return r;
}
QRect RenderObject::getAbsoluteRepaintRect()
{
if (parent())
return parent()->getAbsoluteRepaintRect();
return QRect();
}
void RenderObject::getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& fullBounds)
{
bounds = fullBounds = getAbsoluteRepaintRect();
}
void RenderObject::computeAbsoluteRepaintRect(QRect& r, bool f)
{
if (parent())
return parent()->computeAbsoluteRepaintRect(r, f);
}
void RenderObject::dirtyLinesFromChangedChild(RenderObject* child, bool adding)
{
}
#ifndef NDEBUG
QString RenderObject::information() const
{
QString str;
QTextStream ts( &str, IO_WriteOnly );
ts << renderName()
<< "(" << (style() ? style()->refCount() : 0) << ")"
<< ": " << (void*)this << " ";
if (isInline()) ts << "il ";
if (childrenInline()) ts << "ci ";
if (isFloating()) ts << "fl ";
if (isAnonymous()) ts << "an ";
if (isRelPositioned()) ts << "rp ";
if (isPositioned()) ts << "ps ";
if (needsLayout()) ts << "nl ";
if (m_recalcMinMax) ts << "rmm ";
if (mouseInside()) ts << "mi ";
if (style() && style()->zIndex()) ts << "zI: " << style()->zIndex();
if (element() && element()->active()) ts << "act ";
if (element() && element()->hasAnchor()) ts << "anchor ";
if (element() && element()->focused()) ts << "focus ";
if (element()) ts << " <" << getTagName(element()->id()).string() << ">";
ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")"
<< (isTableCell() ?
( QString::fromLatin1(" [r=") +
QString::number( static_cast<const RenderTableCell *>(this)->row() ) +
QString::fromLatin1(" c=") +
QString::number( static_cast<const RenderTableCell *>(this)->col() ) +
QString::fromLatin1(" rs=") +
QString::number( static_cast<const RenderTableCell *>(this)->rowSpan() ) +
QString::fromLatin1(" cs=") +
QString::number( static_cast<const RenderTableCell *>(this)->colSpan() ) +
QString::fromLatin1("]") ) : QString::null );
return str;
}
void RenderObject::printTree(int indent) const
{
QString ind;
ind.fill(' ', indent);
kdDebug() << ind << information() << endl;
RenderObject *child = firstChild();
while( child != 0 )
{
child->printTree(indent+2);
child = child->nextSibling();
}
}
void RenderObject::dump(QTextStream *stream, QString ind) const
{
if (isAnonymous()) { *stream << " anonymous"; }
if (isFloating()) { *stream << " floating"; }
if (isPositioned()) { *stream << " positioned"; }
if (isRelPositioned()) { *stream << " relPositioned"; }
if (isText()) { *stream << " text"; }
if (isInline()) { *stream << " inline"; }
if (isReplaced()) { *stream << " replaced"; }
if (shouldPaintBackgroundOrBorder()) { *stream << " paintBackground"; }
if (needsLayout()) { *stream << " needsLayout"; }
if (minMaxKnown()) { *stream << " minMaxKnown"; }
*stream << endl;
RenderObject *child = firstChild();
while( child != 0 )
{
*stream << ind << child->renderName() << ": ";
child->dump(stream,ind+" ");
child = child->nextSibling();
}
}
#endif
static NodeImpl *selectStartNode(const RenderObject *object)
{
DOM::NodeImpl *node = 0;
bool forcedOn = false;
for (const RenderObject *curr = object; curr; curr = curr->parent()) {
if (curr->style()->userSelect() == SELECT_TEXT)
forcedOn = true;
if (!forcedOn && curr->style()->userSelect() == SELECT_NONE)
return 0;
if (!node)
node = curr->element();
}
// somewhere up the render tree there must be an element!
assert(node);
return node;
}
bool RenderObject::canSelect() const
{
return selectStartNode(this) != 0;
}
bool RenderObject::shouldSelect() const
{
NodeImpl *node = selectStartNode(this);
if (!node)
return false;
return node->dispatchHTMLEvent(DOM::EventImpl::SELECTSTART_EVENT, true, true);
}
QColor RenderObject::selectionColor(QPainter *p) const
{
QColor color;
if (style()->userSelect() != SELECT_NONE) {
RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
if (pseudoStyle && pseudoStyle->backgroundColor().isValid())
color = pseudoStyle->backgroundColor();
else
color = p->selectedTextBackgroundColor();
}
return color;
}
DOM::NodeImpl* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
{
if (!dhtmlOK && !uaOK)
return 0;
const RenderObject* curr = this;
while (curr) {
DOM::NodeImpl *elt = curr->element();
if (elt && elt->nodeType() == Node::TEXT_NODE) {
// Since there's no way for the author to address the -khtml-user-drag style for a text node,
// we use our own judgement.
if (uaOK && canvas()->view()->part()->shouldDragAutoNode(curr->node(), x, y)) {
dhtmlWillDrag = false;
return curr->node();
} else if (curr->shouldSelect()) {
// In this case we have a click in the unselected portion of text. If this text is
// selectable, we want to start the selection process instead of looking for a parent
// to try to drag.
return 0;
}
} else {
EUserDrag dragMode = curr->style()->userDrag();
if (dhtmlOK && dragMode == DRAG_ELEMENT) {
dhtmlWillDrag = true;
return curr->node();
} else if (uaOK && dragMode == DRAG_AUTO
&& canvas()->view()->part()->shouldDragAutoNode(curr->node(), x, y))
{
dhtmlWillDrag = false;
return curr->node();
}
}
curr = curr->parent();
}
return 0;
}
void RenderObject::selectionStartEnd(int& spos, int& epos)
{
canvas()->selectionStartEnd(spos, epos);
}
RenderBlock* RenderObject::createAnonymousBlock()
{
RenderStyle *newStyle = new (renderArena()) RenderStyle();
newStyle->inheritFrom(m_style);
newStyle->setDisplay(BLOCK);
RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
newBox->setStyle(newStyle);
return newBox;
}
void RenderObject::handleDynamicFloatPositionChange()
{
// We have gone from not affecting the inline status of the parent flow to suddenly
// having an impact. See if there is a mismatch between the parent flow's
// childrenInline() state and our state.
setInline(style()->isDisplayInlineType());
if (isInline() != parent()->childrenInline()) {
if (!isInline()) {
if (parent()->isRenderInline()) {
// We have to split the parent flow.
RenderInline* parentInline = static_cast<RenderInline*>(parent());
RenderBlock* newBox = parentInline->createAnonymousBlock();
RenderFlow* oldContinuation = parent()->continuation();
parentInline->setContinuation(newBox);
RenderObject* beforeChild = nextSibling();
parent()->removeChildNode(this);
parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
}
else if (parent()->isRenderBlock())
static_cast<RenderBlock*>(parent())->makeChildrenNonInline();
}
else {
// An anonymous block must be made to wrap this inline.
RenderBlock* box = createAnonymousBlock();
parent()->insertChildNode(box, this);
box->appendChildNode(parent()->removeChildNode(this));
}
}
}
void RenderObject::setStyle(RenderStyle *style)
{
if (m_style == style)
return;
bool affectsParentBlock = false;
RenderStyle::Diff d = RenderStyle::Equal;
if (m_style) {
// If our z-index changes value or our visibility changes,
// we need to dirty our stacking context's z-order list.
if (style) {
#if APPLE_CHANGES
if (m_style->visibility() != style->visibility() ||
m_style->zIndex() != style->zIndex() ||
m_style->hasAutoZIndex() != style->hasAutoZIndex())
document()->setDashboardRegionsDirty(true);
#endif
if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
m_style->zIndex() != style->zIndex() ||
m_style->visibility() != style->visibility()) && layer()) {
layer()->stackingContext()->dirtyZOrderLists();
if (m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
m_style->visibility() != style->visibility())
layer()->dirtyZOrderLists();
}
}
d = m_style->diff(style);
// If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
if (d == RenderStyle::RepaintLayer && !layer())
d = RenderStyle::Repaint;
// The background of the root element or the body element could propagate up to
// the canvas. Just dirty the entire canvas when our style changes substantially.
if (d >= RenderStyle::Repaint && element() &&
(element()->id() == ID_HTML || element()->id() == ID_BODY))
canvas()->repaint();
else if (m_parent && !isText()) {
// Do a repaint with the old style first, e.g., for example if we go from
// having an outline to not having an outline.
if (d == RenderStyle::RepaintLayer) {
layer()->repaintIncludingDescendants();
if (!(m_style->clip() == style->clip()))
layer()->clearClipRects();
}
else if (d == RenderStyle::Repaint)
repaint();
}
// When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
// end up being destroyed.
if (d == RenderStyle::Layout && layer() &&
(m_style->position() != style->position() ||
m_style->zIndex() != style->zIndex() ||
m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
!(m_style->clip() == style->clip()) ||
m_style->hasClip() != style->hasClip() ||
m_style->opacity() != style->opacity()))
layer()->repaintIncludingDescendants();
// When a layout hint happens and an object's position style changes, we have to do a layout
// to dirty the render tree using the old position value now.
if (d == RenderStyle::Layout && m_parent && m_style->position() != style->position())
setNeedsLayoutAndMinMaxRecalc();
if (isFloating() && (m_style->floating() != style->floating()))
// For changes in float styles, we need to conceivably remove ourselves
// from the floating objects list.
removeFromObjectLists();
else if (isPositioned() && (style->position() != ABSOLUTE && style->position() != FIXED))
// For changes in positioning styles, we need to conceivably remove ourselves
// from the positioned objects list.
removeFromObjectLists();
affectsParentBlock = m_style && isFloatingOrPositioned() &&
(!style->isFloating() && style->position() != ABSOLUTE && style->position() != FIXED)
&& parent() && (parent()->isBlockFlow() || parent()->isInlineFlow());
// reset style flags
m_floating = false;
m_positioned = false;
m_relPositioned = false;
m_paintBackground = false;
m_hasOverflowClip = false;
}
RenderStyle *oldStyle = m_style;
m_style = style;
updateBackgroundImages(oldStyle);
if (m_style)
m_style->ref();
if (oldStyle)
oldStyle->deref(renderArena());
setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground());
if (affectsParentBlock)
handleDynamicFloatPositionChange();
// No need to ever schedule repaints from a style change of a text run, since
// we already did this for the parent of the text run.
if (d == RenderStyle::Layout && m_parent)
setNeedsLayoutAndMinMaxRecalc();
else if (m_parent && !isText() && (d == RenderStyle::RepaintLayer || d == RenderStyle::Repaint))
// Do a repaint with the new style now, e.g., for example if we go from
// not having an outline to having an outline.
repaint();
}
void RenderObject::setStyleInternal(RenderStyle* st)
{
if (m_style == st)
return;
if (m_style)
m_style->deref(renderArena());
m_style = st;
if (m_style)
m_style->ref();
}
void RenderObject::updateBackgroundImages(RenderStyle* oldStyle)
{
// FIXME: This will be slow when a large number of images is used. Fix by using a dict.
const BackgroundLayer* oldLayers = oldStyle ? oldStyle->backgroundLayers() : 0;
const BackgroundLayer* newLayers = m_style ? m_style->backgroundLayers() : 0;
for (const BackgroundLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage())))
currOld->backgroundImage()->deref(this);
}
for (const BackgroundLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage())))
currNew->backgroundImage()->ref(this);
}
}
QRect RenderObject::viewRect() const
{
return canvas()->viewRect();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -