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

📄 bidi.cpp

📁 最新Nokia手机浏览器全套源代码完美版。
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    // clip.
    // FIXME: CSS3 says that descendants that are clipped must also know how to truncate.  This is insanely
    // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense
    // anyway, so we won't worry about following the draft here.
    bool hasTextOverflow = style()->textOverflow() && hasOverflowClip();
    
    // Walk all the lines and delete our ellipsis line boxes if they exist.
    if (hasTextOverflow)
         deleteEllipsisLineBoxes();

    int oldLineBottom = lastRootBox() ? lastRootBox()->bottomOverflow() : m_height;
    int startLineBottom = 0;

    if (firstChild()) {
        // layout replaced elements
        bool endOfInline = false;
        RenderObject *o = first(this, bidi, false);
        bool hasFloat = false;
        while (o) {
            if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
                if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
                    o->setChildNeedsLayout(true, false);
                if (o->isPositioned())
                    o->containingBlock()->insertPositionedObject(o);
                else {
                    if (o->isFloating())
                        hasFloat = true;
                    else if (fullLayout || o->needsLayout()) // Replaced elements
                        o->dirtyLineBoxes(fullLayout);
                    o->layoutIfNeeded();
                }
            }
            else if (o->isText() || (o->isInlineFlow() && !endOfInline)) {
                if (fullLayout || o->selfNeedsLayout())
                    o->dirtyLineBoxes(fullLayout);
                o->setNeedsLayout(false);
            }
            o = Bidinext( this, o, bidi, false, &endOfInline);
        }

        if (hasFloat)
            fullLayout = true; // FIXME: Will need to find a way to optimize floats some day.
        
        if (fullLayout && !selfNeedsLayout()) {
            setNeedsLayout(true, false);  // Mark ourselves as needing a full layout. This way we'll repaint like
                                          // we're supposed to.
            if (!document()->view()->needsFullRepaint() && m_layer) {
                // Because we waited until we were already inside layout to discover
                // that the block really needed a full layout, we missed our chance to repaint the layer
                // before layout started.  Luckily the layer has cached the repaint rect for its original
                // position and size, and so we can use that to make a repaint happen now.
                RenderCanvas* c = canvas();
                if (c && !c->printingMode())
                    c->repaintViewRectangle(m_layer->repaintRect());
            }
        }

        BidiContext *startEmbed;
        if( style()->direction() == LTR ) {
            startEmbed = new BidiContext( 0, QChar::DirL );
            bidi.status.eor = QChar::DirL;
        } else {
            startEmbed = new BidiContext( 1, QChar::DirR );
            bidi.status.eor = QChar::DirR;
        }
        startEmbed->ref();

        bidi.status.lastStrong = startEmbed->dir;
        bidi.status.last = startEmbed->dir;
        bidi.context = startEmbed;
        
        if (!smidpoints)
            smidpoints = new QMemArray<BidiIterator>;
        
        sNumMidpoints = 0;
        sCurrMidpoint = 0;
        sCompactFirstBidiRun = sCompactLastBidiRun = 0;
        sCompactBidiRunCount = 0;
        
        // We want to skip ahead to the first dirty line
        BidiIterator start;
        RootInlineBox* startLine = determineStartPosition(fullLayout, start, bidi);
        
        // We also find the first clean line and extract these lines.  We will add them back
        // if we determine that we're able to synchronize after handling all our dirty lines.
        BidiIterator cleanLineStart;
        int endLineYPos;
        RootInlineBox* endLine = (fullLayout || !startLine) ? 
                                 0 : determineEndPosition(startLine, cleanLineStart, endLineYPos);
        if (startLine) {
            useRepaintRect = true;
            startLineBottom = startLine->bottomOverflow();
            repaintRect.setY(kMin(m_height, startLine->topOverflow()));
            RenderArena* arena = renderArena();
            RootInlineBox* box = startLine;
            while (box) {
                RootInlineBox* next = box->nextRootBox();
                box->deleteLine(arena);
                box = next;
            }
            startLine = 0;
        }
        
        BidiIterator end = start;

        bool endLineMatched = false;
        while (!end.atEnd()) {
            start = end;
            if (endLine && (endLineMatched = matchedEndLine(start, cleanLineStart, endLine, endLineYPos)))
                break;

            betweenMidpoints = false;
            isLineEmpty = true;
            if (m_firstLine && firstChild() && firstChild()->isCompact() && firstChild()->isRenderBlock()) {
                buildCompactRuns(firstChild(), bidi);
                start.obj = firstChild()->nextSibling();
                end = start;
            }
            end = findNextLineBreak(start, bidi);
            if( start.atEnd() ) break;
            if (!isLineEmpty) {
                bidiReorderLine(start, end, bidi);

                // Now that the runs have been ordered, we create the line boxes.
                // At the same time we figure out where border/padding/margin should be applied for
                // inline flow boxes.
                if (sCompactFirstBidiRun) {
                    // We have a compact line sharing this line.  Link the compact runs
                    // to our runs to create a single line of runs.
                    sCompactLastBidiRun->nextRun = sFirstBidiRun;
                    sFirstBidiRun = sCompactFirstBidiRun;
                    sBidiRunCount += sCompactBidiRunCount;
                }

                RootInlineBox* lineBox = 0;
                if (sBidiRunCount) {
                    lineBox = constructLine(start, end);
                    if (lineBox) {
                        lineBox->setEndsWithBreak(previousLineBrokeCleanly);
                        
                        // Now we position all of our text runs horizontally.
                        computeHorizontalPositionsForLine(lineBox, bidi);
        
                        // Now position our text runs vertically.
                        computeVerticalPositionsForLine(lineBox);
        
                        deleteBidiRuns(renderArena());
                    }
                }
                
                if (end == start || (!previousLineBrokeCleanly && end.obj && end.obj->style()->whiteSpace() == PRE && end.current() == QChar('\n'))) {
                    adjustEmbedding = true;
                    end.increment(bidi);
                    adjustEmbedding = false;
                }

                if (lineBox)
                    lineBox->setLineBreakInfo(end.obj, end.pos);
                
                m_firstLine = false;
                newLine();
            }
             
            sNumMidpoints = 0;
            sCurrMidpoint = 0;
            sCompactFirstBidiRun = sCompactLastBidiRun = 0;
            sCompactBidiRunCount = 0;
        }
        startEmbed->deref();
        //embed->deref();
        
        if (endLine) {
            if (endLineMatched) {
                // Note our current y-position for correct repainting when no lines move.  If no lines move, we still have to
                // repaint up to the maximum of the bottom overflow of the old start line or the bottom overflow of the new last line.
                int currYPos = kMax(startLineBottom, m_height);
                if (lastRootBox())
                    currYPos = kMax(currYPos, lastRootBox()->bottomOverflow());
                
                // Attach all the remaining lines, and then adjust their y-positions as needed.
                for (RootInlineBox* line = endLine; line; line = line->nextRootBox())
                    line->attachLine();
                
                // Now apply the offset to each line if needed.
                int delta = m_height - endLineYPos;
                if (delta) {
                    for (RootInlineBox* line = endLine; line; line = line->nextRootBox())
                        line->adjustPosition(0, delta);
                }
                m_height = lastRootBox()->blockHeight();
                m_overflowHeight = kMax(m_height, m_overflowHeight);
                int bottomOfLine = lastRootBox()->bottomOverflow();
                if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight)
                    m_overflowHeight = bottomOfLine;
                if (delta)
                    repaintRect.setHeight(kMax(m_overflowHeight-delta, m_overflowHeight) - repaintRect.y());
                else
                    repaintRect.setHeight(currYPos - repaintRect.y());
            }
            else {
                // Delete all the remaining lines.
                m_overflowHeight = kMax(m_height, m_overflowHeight);
                InlineRunBox* line = endLine;
                RenderArena* arena = renderArena();
                while (line) {
                    InlineRunBox* next = line->nextLineBox();
                    if (!next)
                        repaintRect.setHeight(kMax(m_overflowHeight, line->bottomOverflow()) - repaintRect.y());
                    line->deleteLine(arena);
                    line = next;
                }
            }
        }
    }

    sNumMidpoints = 0;
    sCurrMidpoint = 0;

    // in case we have a float on the last line, it might not be positioned up to now.
    // This has to be done before adding in the bottom border/padding, or the float will
    // include the padding incorrectly. -dwh
    positionNewFloats();
    
    // Now add in the bottom border/padding.
    m_height += toAdd;

    // Always make sure this is at least our height.
    m_overflowHeight = kMax(m_height, m_overflowHeight);
    
    // See if any lines spill out of the block.  If so, we need to update our overflow width.
    checkLinesForOverflow();

    if (useRepaintRect) {
        repaintRect.setWidth(kMax((int)m_width, m_overflowWidth));
        if (repaintRect.height() == 0)
            repaintRect.setHeight(kMax(oldLineBottom, m_overflowHeight) - repaintRect.y());
    }

    if (!firstLineBox() && element() && element()->isContentEditable() && element()->rootEditableElement() == element())
        m_height += lineHeight(true);

    // See if we have any lines that spill out of our block.  If we do, then we will possibly need to
    // truncate text.
    if (hasTextOverflow)
        checkLinesForTextOverflow();

    return repaintRect;

#if BIDI_DEBUG > 1
    kdDebug(6041) << " ------- bidi end " << this << " -------" << endl;
#endif
    //kdDebug() << "RenderBlock::layoutInlineChildren time used " << qt.elapsed() << endl;
    //kdDebug(6040) << "height = " << m_height <<endl;
}

RootInlineBox* RenderBlock::determineStartPosition(bool fullLayout, BidiIterator& start, BidiState& bidi)
{
    RootInlineBox* curr = 0;
    RootInlineBox* last = 0;
    RenderObject* startObj = 0;
    int pos = 0;
    
    if (fullLayout) {
        // Nuke all our lines.
        if (firstRootBox()) {
            RenderArena* arena = renderArena();
            curr = firstRootBox(); 
            while (curr) {
                RootInlineBox* next = curr->nextRootBox();
                curr->deleteLine(arena);
                curr = next;
            }
            KHTMLAssert(!m_firstLineBox && !m_lastLineBox);
        }
    }
    else {
        for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox());
        if (curr) {
            // We have a dirty line.
            if (curr->prevRootBox()) {
                // We have a previous line.
                if (!curr->prevRootBox()->endsWithBreak())
                    curr = curr->prevRootBox();  // The previous line didn't break cleanly, so treat it as dirty also.
            }
        }
        else {
            // No dirty lines were found.
            // If the last line didn't break cleanly, treat it as dirty.
            if (lastRootBox() && !lastRootBox()->endsWithBreak())
                curr = lastRootBox();
        }
        
        // If we have no dirty lines, then last is just the last root box.
        last = curr ? curr->prevRootBox() : lastRootBox();
    }
    
    m_firstLine = !last;
    previousLineBrokeCleanly = !last || last->endsWithBreak();
    if (last) {
        m_height = last->blockHeight();
        int bottomOfLine = last->bottomOverflow();
        if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight)
            m_overflowHeight = bottomOfLine;
        startObj = last->lineBreakObj();
        pos = last->lineBreakPos();
    }
    else
        startObj = first(this, bidi, 0);
        
    adjustEmbedding = true;
    start = BidiIterator(this, startObj, pos);
    
    adjustEmbedding = false;
    
    return curr;
}

RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, BidiIterator& cleanLineStart,
                                                 int& yPos)
{
    RootInlineBox* last = 0;
    if (!startLine)
        last = 0;
    else {
        for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
            if (curr->isDirty())
                last = 0;
            else if (!last)
                last = curr;
        }
    }
    
    if (!last)
        return 0;
    
    cleanLineStart = BidiIterator(this, last->prevRootBox()->lineBreakObj(), last->prevRootBox()->lineBreakPos());
    yPos = last->prevRootBox()->blockHeight();
    
    for (RootInlineBox* line = last; line; line = line->nextRootBox())
        line->extractLine(); // Disconnect all line boxes from their render objects while preserving
                             // their connections to one another.
    
    return last;
}

bool RenderBlock::matchedEndLine(const BidiIterator& start, const BidiIterator& endLineStart, 
                                 RootInlineBox*& endLine, int& endYPos)
{
    if (start == endLineStart)
        return true; // The common case. All the data we already have is correct.
    else {
        // The first clean line doesn't match, but we can check a handful of following lines to try
        // to match back up.
        static int numLines = 8; // The # of lines we're willing to match against.
        RootInlineBox* line = endLine;
        for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {

⌨️ 快捷键说明

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