⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 render_block.cpp

📁 手机浏览器源码程序,功能强大
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    // See if we have a compact element.  If we do, then try to tuck the compact element into the margin space of the next block.
    next = handleCompactChild(child, compactInfo, handled);
    if (handled) return next;

    // Finally, see if we have a run-in element.
    return handleRunInChild(child, handled);
}


RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled)
{
    if (child->isPositioned()) {
        handled = true;
        child->containingBlock()->insertPositionedObject(child);
        adjustPositionedBlock(child, marginInfo);
        return child->nextSibling();
    }

    return 0;
}

RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled)
{
    if (child->isFloating()) {
        handled = true;
        insertFloatingObject(child);
        adjustFloatingBlock(marginInfo);
        return child->nextSibling();
    }

    return 0;
}

RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, bool& handled)
{
    // FIXME: We only deal with one compact at a time.  It is unclear what should be
    // done if multiple contiguous compacts are encountered.  For now we assume that
    // compact A followed by another compact B should simply be treated as block A.
    if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) {
        // Get the next non-positioned/non-floating RenderBlock.
        RenderObject* next = child->nextSibling();
        RenderObject* curr = next;
        while (curr && curr->isFloatingOrPositioned())
            curr = curr->nextSibling();
        if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) {
            curr->calcWidth(); // So that horizontal margins are correct.

            child->setInline(true); // Need to compute the margins/width for the child as though it is an inline, so that it won't try to puff up the margins to
                                    // fill the containing block width.
            child->calcWidth();
            int childMargins = child->marginLeft() + child->marginRight();
            int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight();
            if (margin >= (childMargins + child->maxWidth())) {
                // The compact will fit in the margin.
                handled = true;
                compactInfo.set(child, curr);
                child->setPos(0,0); // This position will be updated to reflect the compact's
                                    // desired position and the line box for the compact will
                                    // pick that position up.

                // Remove the child.
                RenderObject* next = child->nextSibling();
                removeChildNode(child);

                // Now insert the child under |curr|.
                curr->insertChildNode(child, curr->firstChild());
                return next;
            }
            else
                child->setInline(false); // We didn't fit, so we remain a block-level element.
        }
    }
    return 0;
}

void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo)
{
    if (compactInfo.matches(child)) {
        // We have a compact child to squeeze in.
        RenderObject* compactChild = compactInfo.compact();
        int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft();
        if (style()->direction() == RTL) {
            compactChild->calcWidth(); // have to do this because of the capped maxwidth
            compactXPos = width() - borderRight() - paddingRight() - marginRight() -
                compactChild->width() - compactChild->marginRight();
        }
        compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space.
        compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position.
        compactInfo.clear();
    }
}

RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled)
{
    // See if we have a run-in element with inline children.  If the
    // children aren't inline, then just treat the run-in as a normal
    // block.
    if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) {
        // Get the next non-positioned/non-floating RenderBlock.
        RenderObject* curr = child->nextSibling();
        while (curr && curr->isFloatingOrPositioned())
            curr = curr->nextSibling();
        if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) {
            // The block acts like an inline, so just null out its
            // position.
            handled = true;
            child->setInline(true);
            child->setPos(0,0);

            // Remove the child.
            RenderObject* next = child->nextSibling();
            removeChildNode(child);

            // Now insert the child under |curr|.
            curr->insertChildNode(child, curr->firstChild());
            return next;
        }
    }
    return 0;
}

void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate)
{
    // Get our max pos and neg top margins.
    int posTop = child->maxTopMargin(true);
    int negTop = child->maxTopMargin(false);

    // For self-collapsing blocks, collapse our bottom margins into our
    // top to get new posTop and negTop values.
    if (child->isSelfCollapsingBlock()) {
        posTop = kMax(posTop, child->maxBottomMargin(true));
        negTop = kMax(negTop, child->maxBottomMargin(false));
    }

    // See if the top margin is quirky. We only care if this child has
    // margins that will collapse with us.
    bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD;

    if (marginInfo.canCollapseWithTop()) {
        // This child is collapsing with the top of the
        // block.  If it has larger margin values, then we need to update
        // our own maximal values.
        if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) {
            m_maxTopPosMargin = kMax(posTop, m_maxTopPosMargin);
            m_maxTopNegMargin = kMax(negTop, m_maxTopNegMargin);
        }

        // The minute any of the margins involved isn't a quirk, don't
        // collapse it away, even if the margin is smaller (www.webreference.com
        // has an example of this, a <dt> with 0.8em author-specified inside
        // a <dl> inside a <td>.
        if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) {
            m_topMarginQuirk = false;
            marginInfo.setDeterminedTopQuirk(true);
        }

        if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0)
            // We have no top margin and our top child has a quirky margin.
            // We will pick up this quirky margin and pass it through.
            // This deals with the <td><div><p> case.
            // Don't do this for a block that split two inlines though.  You do
            // still apply margins in this case.
            m_topMarginQuirk = true;
    }

    if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop))
        marginInfo.setTopQuirk(topQuirk);

    int ypos = m_height;
    if (child->isSelfCollapsingBlock()) {
        // This child has no height.  We need to compute our
        // position before we collapse the child's margins together,
        // so that we can get an accurate position for the zero-height block.
        int collapsedTopPos = kMax(marginInfo.posMargin(), child->maxTopMargin(true));
        int collapsedTopNeg = kMax(marginInfo.negMargin(), child->maxTopMargin(false));
        marginInfo.setMargin(collapsedTopPos, collapsedTopNeg);

        // Now collapse the child's margins together, which means examining our
        // bottom margin values as well.
        marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true));
        marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false));

        if (!marginInfo.canCollapseWithTop())
            // We need to make sure that the position of the self-collapsing block
            // is correct, since it could have overflowing content
            // that needs to be positioned correctly (e.g., a block that
            // had a specified height of 0 but that actually had subcontent).
            ypos = m_height + collapsedTopPos - collapsedTopNeg;
    }
    else {
        if (child->style()->marginTopCollapse() == MSEPARATE) {
            m_height += marginInfo.margin() + child->marginTop();
            ypos = m_height;
        }
        else if (!marginInfo.atTopOfBlock() ||
            (!marginInfo.canCollapseTopWithChildren()
             && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) {
            // We're collapsing with a previous sibling's margins and not
            // with the top of the block.
            m_height += kMax(marginInfo.posMargin(), posTop) - kMax(marginInfo.negMargin(), negTop);
            ypos = m_height;
        }

        marginInfo.setPosMargin(child->maxBottomMargin(true));
        marginInfo.setNegMargin(child->maxBottomMargin(false));

        if (marginInfo.margin())
            marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD);

        marginInfo.setSelfCollapsingBlockClearedFloat(false);
    }

    child->setPos(child->xPos(), ypos);
    if (ypos != yPosEstimate) {
        if (child->style()->width().isPercent() && child->usesLineWidth())
            // The child's width is a percentage of the line width.
            // When the child shifts to clear an item, its width can
            // change (because it has more available line width).
            // So go ahead and mark the item as dirty.
            child->setChildNeedsLayout(true);

        if (!child->avoidsFloats() && child->containsFloats())
            child->markAllDescendantsWithFloatsForLayout();

        // Our guess was wrong. Make the child lay itself out again.
        child->layoutIfNeeded();
    }
}

void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin)
{
    int heightIncrease = getClearDelta(child);
    if (heightIncrease) {
        // The child needs to be lowered.  Move the child so that it just clears the float.
        child->setPos(child->xPos(), child->yPos() + heightIncrease);

        // Increase our height by the amount we had to clear.
        if (!child->isSelfCollapsingBlock())
            m_height += heightIncrease;
        else {
            // For self-collapsing blocks that clear, they may end up collapsing
            // into the bottom of the parent block.  We simulate this behavior by
            // setting our positive margin value to compensate for the clear.
            marginInfo.setPosMargin(kMax(0, child->yPos() - m_height));
            marginInfo.setNegMargin(0);
            marginInfo.setSelfCollapsingBlockClearedFloat(true);
        }

        if (marginInfo.canCollapseWithTop()) {
            // We can no longer collapse with the top of the block since a clear
            // occurred.  The empty blocks collapse into the cleared block.
            // FIXME: This isn't quite correct.  Need clarification for what to do
            // if the height the cleared block is offset by is smaller than the
            // margins involved.
            m_maxTopPosMargin = oldTopPosMargin;
            m_maxTopNegMargin = oldTopNegMargin;
            marginInfo.setAtTopOfBlock(false);
        }

        // If our value of clear caused us to be repositioned vertically to be
        // underneath a float, we might have to do another layout to take into account
        // the extra space we now have available.
        if (child->style()->width().isPercent() && child->usesLineWidth())
            // The child's width is a percentage of the line width.
            // When the child shifts to clear an item, its width can
            // change (because it has more available line width).
            // So go ahead and mark the item as dirty.
            child->setChildNeedsLayout(true);
        if (!child->avoidsFloats() && child->containsFloats())
            child->markAllDescendantsWithFloatsForLayout();
        child->layoutIfNeeded();
    }
}

int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo)
{
    // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
    // relayout if there are intruding floats.
    int yPosEstimate = m_height;
    if (!marginInfo.canCollapseWithTop()) {
        int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop();
        yPosEstimate += kMax(marginInfo.margin(), childMarginTop);
    }
    return yPosEstimate;
}

void RenderBlock::determineHorizontalPosition(RenderObject* child)
{
    if (style()->direction() == LTR) {
        int xPos = borderLeft() + paddingLeft();

        // Add in our left margin.
        int chPos = xPos + child->marginLeft();

        // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats.  They need
        // to shift over as necessary to dodge any floats that might get in the way.
        if (child->avoidsFloats()) {
            int leftOff = leftOffset(m_height);
            if (style()->textAlign() != KHTML_CENTER && child->style()->marginLeft().type != Variable) {
                if (child->marginLeft() < 0)
                    leftOff += child->marginLeft();
                chPos = kMax(chPos, leftOff); // Let the float sit in the child's margin if it can fit.
            }
            else if (leftOff != xPos) {
                // The object is shifting right. The object might be centered, so we need to
                // recalculate our horizontal margins. Note that the containing block content

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -