Esempio n. 1
0
void createTextRuns(Layout::RunVector& runs, unsigned& lineCount, RenderBlockFlow& flow, RenderText& textRenderer)
{
    const Style style(flow.style());

    const CharacterType* text = textRenderer.text()->characters<CharacterType>();
    const unsigned textLength = textRenderer.textLength();

    LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
    LayoutUnit lineHeight = lineHeightFromFlow(flow);

    LazyLineBreakIterator lineBreakIterator(textRenderer.text(), flow.style().locale());

    unsigned lineEnd = 0;
    while (lineEnd < textLength) {
        if (style.collapseWhitespace)
            lineEnd = skipWhitespaces(text, lineEnd, textLength, style.preserveNewline);

        unsigned lineStart = lineEnd;

        // LineWidth reads the current y position from the flow so keep it updated.
        flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
        LineWidth lineWidth(flow, false, DoNotIndentText);

        auto lineRuns = createLineRuns(lineStart, lineWidth, lineBreakIterator, style, text, textLength, textRenderer);

        lineEnd = lineRuns.last().end;
        if (lineStart == lineEnd)
            continue;

        lineRuns.last().isEndOfLine = true;

        float lineLeft = computeLineLeft(style.textAlign, lineWidth);
        adjustRunOffsets(lineRuns, lineLeft);

        for (unsigned i = 0; i < lineRuns.size(); ++i)
            runs.append(lineRuns[i]);

        ++lineCount;
    }
}
Esempio n. 2
0
std::unique_ptr<Layout> create(RenderBlockFlow& flow)
{
    RenderText& textRenderer = toRenderText(*flow.firstChild());
    ASSERT(!textRenderer.firstTextBox());

    const RenderStyle& style = flow.style();
    const unsigned textLength = textRenderer.textLength();

    ETextAlign textAlign = style.textAlign();
    float wordTrailingSpaceWidth = style.font().width(TextRun(&space, 1));

    LazyLineBreakIterator lineBreakIterator(textRenderer.text(), style.locale());
    int nextBreakable = -1;

    Layout::RunVector runs;
    unsigned lineCount = 0;

    unsigned lineEndOffset = 0;
    while (lineEndOffset < textLength) {
        lineEndOffset = skipWhitespaces(textRenderer, lineEndOffset, textLength);
        unsigned lineStartOffset = lineEndOffset;
        unsigned wordEndOffset = lineEndOffset;
        LineWidth lineWidth(flow, false, DoNotIndentText);

        Vector<Run, 4> lineRuns;
        lineRuns.uncheckedAppend(Run(lineStartOffset, 0));

        while (wordEndOffset < textLength) {
            ASSERT(!isWhitespace(textRenderer.characterAt(wordEndOffset)));

            bool previousWasSpaceBetweenWords = wordEndOffset > lineStartOffset && isWhitespace(textRenderer.characterAt(wordEndOffset - 1));
            unsigned wordStartOffset = previousWasSpaceBetweenWords ? wordEndOffset - 1 : wordEndOffset;

            ++wordEndOffset;
            while (wordEndOffset < textLength) {
                if (wordEndOffset > lineStartOffset && isBreakable(lineBreakIterator, wordEndOffset, nextBreakable, false))
                    break;
                ++wordEndOffset;
            }

            unsigned wordLength = wordEndOffset - wordStartOffset;
            bool includeEndSpace = wordEndOffset < textLength && textRenderer.characterAt(wordEndOffset) == ' ';
            float wordWidth;
            if (includeEndSpace)
                wordWidth = textWidth(textRenderer, wordStartOffset, wordLength + 1, lineWidth.committedWidth(), style) - wordTrailingSpaceWidth;
            else
                wordWidth = textWidth(textRenderer, wordStartOffset, wordLength, lineWidth.committedWidth(), style);

            lineWidth.addUncommittedWidth(wordWidth);

            // Move to the next line if the current one is full and we have something on it.
            if (!lineWidth.fitsOnLine() && lineWidth.committedWidth())
                break;

            if (wordStartOffset > lineEndOffset) {
                // There were more than one consecutive whitespace.
                ASSERT(previousWasSpaceBetweenWords);
                // Include space to the end of the previous run.
                lineRuns.last().textLength++;
                lineRuns.last().right += wordTrailingSpaceWidth;
                // Start a new run on the same line.
                lineRuns.append(Run(wordStartOffset + 1, lineRuns.last().right));
            }

            lineWidth.commit();

            lineRuns.last().right = lineWidth.committedWidth();
            lineRuns.last().textLength = wordEndOffset - lineRuns.last().textOffset;

            lineEndOffset = wordEndOffset;
            wordEndOffset = skipWhitespaces(textRenderer, wordEndOffset, textLength);

            if (!lineWidth.fitsOnLine()) {
                // The first run on the line overflows.
                ASSERT(lineRuns.size() == 1);
                break;
            }
        }
        if (lineStartOffset == lineEndOffset)
            continue;

        adjustRunOffsets(lineRuns, textAlign, lineWidth.committedWidth(), lineWidth.availableWidth());

        for (unsigned i = 0; i < lineRuns.size(); ++i)
            runs.append(lineRuns[i]);

        runs.last().isEndOfLine = true;
        ++lineCount;
    }

    textRenderer.clearNeedsLayout();

    return Layout::create(runs, lineCount);
}