📄 render_object.cpp
字号:
}
bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f)
{
RenderObject* o = parent();
if (o) {
o->absolutePosition(xPos, yPos, f);
if (o->hasOverflowClip())
o->layer()->subtractScrollOffset(xPos, yPos);
return true;
}
else
{
xPos = yPos = 0;
return false;
}
}
QRect RenderObject::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
{
if (extraWidthToEndOfLine)
*extraWidthToEndOfLine = 0;
return QRect();
}
int RenderObject::paddingTop() const
{
int w = 0;
Length padding = m_style->paddingTop();
if (padding.isPercent())
w = containingBlock()->contentWidth();
w = padding.minWidth(w);
if ( isTableCell() && padding.isVariable() )
w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
return w;
}
int RenderObject::paddingBottom() const
{
int w = 0;
Length padding = style()->paddingBottom();
if (padding.isPercent())
w = containingBlock()->contentWidth();
w = padding.minWidth(w);
if ( isTableCell() && padding.isVariable() )
w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
return w;
}
int RenderObject::paddingLeft() const
{
int w = 0;
Length padding = style()->paddingLeft();
if (padding.isPercent())
w = containingBlock()->contentWidth();
w = padding.minWidth(w);
if ( isTableCell() && padding.isVariable() )
w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
return w;
}
int RenderObject::paddingRight() const
{
int w = 0;
Length padding = style()->paddingRight();
if (padding.isPercent())
w = containingBlock()->contentWidth();
w = padding.minWidth(w);
if ( isTableCell() && padding.isVariable() )
w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
return w;
}
RenderCanvas* RenderObject::canvas() const
{
return static_cast<RenderCanvas*>(document()->renderer());
}
RenderObject *RenderObject::container() const
{
// This method is extremely similar to containingBlock(), but with a few notable
// exceptions.
// (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
// the object is not part of the primary document subtree yet.
// (2) For normal flow elements, it just returns the parent.
// (3) For absolute positioned elements, it will return a relative positioned inline.
// containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
// the layout of the positioned object. This does mean that calcAbsoluteHorizontal and
// calcAbsoluteVertical have to use container().
EPosition pos = m_style->position();
RenderObject *o = 0;
if (!isText() && pos == FIXED) {
// container() can be called on an object that is not in the
// tree yet. We don't call canvas() since it will assert if it
// can't get back to the canvas. Instead we just walk as high up
// as we can. If we're in the tree, we'll get the root. If we
// aren't we'll get the root of our little subtree (most likely
// we'll just return 0).
o = parent();
while (o && o->parent()) o = o->parent();
}
else if (!isText() && pos == ABSOLUTE) {
// Same goes here. We technically just want our containing block, but
// we may not have one if we're part of an uninstalled subtree. We'll
// climb as high as we can though.
o = parent();
while (o && o->style()->position() == STATIC && !o->isRoot() && !o->isCanvas())
o = o->parent();
}
else
o = parent();
return o;
}
bool RenderObject::isSelectionBorder() const
{
SelectionState st = selectionState();
return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
}
#if 0
static void checkFloats(RenderObject* o, RenderObject* f)
{
if (o->isRenderBlock()) {
RenderBlock* b = static_cast<RenderBlock*>(o);
if (b->containsFloat(f))
assert(false);
}
for (RenderObject* c = o->firstChild(); c; c = c->nextSibling())
checkFloats(c, f);
}
#endif
void RenderObject::removeFromObjectLists()
{
if (isFloating()) {
RenderBlock* outermostBlock = containingBlock();
for (RenderBlock* p = outermostBlock; p && !p->isCanvas(); p = p->containingBlock()) {
if (p->containsFloat(this))
outermostBlock = p;
}
if (outermostBlock)
outermostBlock->markAllDescendantsWithFloatsForLayout(this);
#if 0
// Debugging code for float checking.
checkFloats(canvas(), this);
#endif
}
if (isPositioned()) {
RenderObject *p;
for (p = parent(); p; p = p->parent()) {
if (p->isRenderBlock())
static_cast<RenderBlock*>(p)->removePositionedObject(this);
}
}
}
RenderArena* RenderObject::renderArena() const
{
DOM::DocumentImpl* doc = document();
return doc ? doc->renderArena() : 0;
}
void RenderObject::remove()
{
#if APPLE_CHANGES
// Delete our accessibility object if we have one.
document()->getAccObjectCache()->detach(this);
#endif
removeFromObjectLists();
if (parent())
//have parent, take care of the tree integrity
parent()->removeChild(this);
}
void RenderObject::detach()
{
remove();
// by default no refcounting
arenaDelete(document()->renderArena(), this);
}
#if NOKIA_CHANGES
void RenderObject::arenaDelete(RenderArena *arena, void *)
{
if (m_style->backgroundImage())
m_style->backgroundImage()->deref(this);
if (m_style)
m_style->deref(arena);
void *savedBase = baseOfRenderObjectBeingDeleted;
delete this;
void* base = baseOfRenderObjectBeingDeleted;
// Recover the size left there for us by operator delete and free the memory.
arena->free(*(size_t *)base, base);
baseOfRenderObjectBeingDeleted = savedBase;
}
#else
void RenderObject::arenaDelete(RenderArena *arena, void *base)
{
if (m_style->backgroundImage())
m_style->backgroundImage()->deref(this);
if (m_style)
m_style->deref(arena);
#ifndef NDEBUG
void *savedBase = baseOfRenderObjectBeingDeleted;
baseOfRenderObjectBeingDeleted = base;
#endif
delete this;
#ifndef NDEBUG
baseOfRenderObjectBeingDeleted = savedBase;
#endif
// Recover the size left there for us by operator delete and free the memory.
arena->free(*(size_t *)base, base);
}
#endif
VisiblePosition RenderObject::positionForCoordinates(int x, int y)
{
return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
}
bool RenderObject::mouseInside() const
{
if (!m_mouseInside && continuation())
return continuation()->mouseInside();
return m_mouseInside;
}
bool RenderObject::isDragging() const
{
return m_isDragging;
}
void RenderObject::updateDragState(bool dragOn)
{
bool valueChanged = (dragOn != m_isDragging);
m_isDragging = dragOn;
if (valueChanged && style()->affectedByDragRules())
element()->setChanged();
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
curr->updateDragState(dragOn);
if (continuation())
continuation()->updateDragState(dragOn);
}
bool RenderObject::hitTest(NodeInfo& info, int x, int y, int tx, int ty, HitTestFilter hitTestFilter)
{
bool inside = false;
if (hitTestFilter != HitTestSelf) {
// First test the foreground layer (lines and inlines).
inside = nodeAtPoint(info, x, y, tx, ty, HitTestForeground);
// Test floats next.
if (!inside)
inside = nodeAtPoint(info, x, y, tx, ty, HitTestFloat);
// Finally test to see if the mouse is in the background (within a child block's background).
if (!inside)
inside = nodeAtPoint(info, x, y, tx, ty, HitTestChildBlockBackgrounds);
}
// See if the mouse is inside us but not any of our descendants
if (hitTestFilter != HitTestDescendants && !inside)
inside = nodeAtPoint(info, x, y, tx, ty, HitTestBlockBackground);
return inside;
}
void RenderObject::setInnerNode(NodeInfo& info)
{
if (!info.innerNode() && !isInline() && continuation()) {
// We are in the margins of block elements that are part of a continuation. In
// this case we're actually still inside the enclosing inline element that was
// split. Go ahead and set our inner node accordingly.
info.setInnerNode(continuation()->element());
if (!info.innerNonSharedNode())
info.setInnerNonSharedNode(continuation()->element());
}
if (!info.innerNode() && element())
info.setInnerNode(element());
if(!info.innerNonSharedNode() && element())
info.setInnerNonSharedNode(element());
}
bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
HitTestAction hitTestAction)
{
return false;
}
short RenderObject::verticalPositionHint( bool firstLine ) const
{
short vpos = m_verticalPosition;
if ( m_verticalPosition == PositionUndefined || firstLine ) {
vpos = getVerticalPosition( firstLine );
if ( !firstLine )
m_verticalPosition = vpos;
}
return vpos;
}
short RenderObject::getVerticalPosition( bool firstLine ) const
{
if (!isInline())
return 0;
// This method determines the vertical position for inline elements.
int vpos = 0;
EVerticalAlign va = style()->verticalAlign();
if ( va == TOP ) {
vpos = PositionTop;
} else if ( va == BOTTOM ) {
vpos = PositionBottom;
} else if ( va == LENGTH ) {
vpos = -style()->verticalAlignLength().width( lineHeight( firstLine ) );
} else {
bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM;
vpos = checkParent ? parent()->verticalPositionHint( firstLine ) : 0;
// don't allow elements nested inside text-top to have a different valignment.
if ( va == BASELINE )
return vpos;
const QFont &f = parent()->font( firstLine );
int fontsize = f.pixelSize();
if (va == SUB)
vpos += fontsize/5 + 1;
else if (va == SUPER)
vpos -= fontsize/3 + 1;
else if (va == TEXT_TOP)
vpos += baselinePosition( firstLine ) - QFontMetrics(f).ascent();
else if (va == MIDDLE)
vpos += - (int)(QFontMetrics(f).xHeight()/2) - lineHeight( firstLine )/2 + baselinePosition( firstLine );
else if (va == TEXT_BOTTOM) {
vpos += QFontMetrics(f).descent();
if (!isReplaced())
vpos -= fontMetrics(firstLine).descent();
} else if ( va == BASELINE_MIDDLE )
vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine );
}
return vpos;
}
short RenderObject::lineHeight( bool firstLine, bool ) const
{
RenderStyle* s = style(firstLine);
Length lh = s->lineHeight();
#ifdef NOKIA_CHANGES
lh.value = lh.value * 100 / canvas()->view()->scalingFactor();
#endif
// its "unset", choose nice default
if (lh.value < 0)
return s->fontMetrics().lineSpacing();
if (lh.isPercent())
return lh.minWidth(s->font().pixelSize());
// its fixed
return lh.value;
}
short RenderObject::baselinePosition( bool firstLine, bool isRootLineBox ) const
{
const QFontMetrics &fm = fontMetrics( firstLine );
return fm.ascent() + ( lineHeight( firstLine, isRootLineBox ) - fm.height() ) / 2;
}
void RenderObject::invalidateVerticalPositions()
{
m_verticalPosition = PositionUndefined;
RenderObject *child = firstChild();
while( child ) {
child->invalidateVerticalPositions();
child = child->nextSibling();
}
}
void RenderObject::recalcMinMaxWidths()
{
KHTMLAssert( m_recalcMinMax );
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this <<endl;
#endif
if (m_recalcMinMax)
updateFirstLetter();
RenderObject *child = firstChild();
while( child ) {
// gcc sucks. if anybody knows a trick to get rid of the
// warning without adding an extra (unneeded) initialisation,
// go ahead
int cmin = 0;
int cmax = 0;
bool test = false;
if ( ( m_minMaxKnown && child->m_recalcMinMax ) || !child->m_minMaxKnown ) {
cmin = child->m
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -