Beispiel #1
0
void LayoutSVGInlineText::addMetricsFromRun(
    const TextRun& run, bool& lastCharacterWasWhiteSpace)
{
    Vector<CharacterRange> charRanges = scaledFont().individualCharacterRanges(run);
    synthesizeGraphemeWidths(run, charRanges);

    const float cachedFontHeight = scaledFont().getFontMetrics().floatHeight() / m_scalingFactor;
    const bool preserveWhiteSpace = styleRef().whiteSpace() == PRE;
    const unsigned runLength = static_cast<unsigned>(run.length());

    // TODO(pdr): Character-based iteration is ambiguous and error-prone. It
    // should be unified under a single concept. See: https://crbug.com/593570
    unsigned characterIndex = 0;
    while (characterIndex < runLength) {
        bool currentCharacterIsWhiteSpace = run[characterIndex] == ' ';
        if (!preserveWhiteSpace && lastCharacterWasWhiteSpace && currentCharacterIsWhiteSpace) {
            m_metrics.append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
            characterIndex++;
            continue;
        }

        unsigned length = isValidSurrogatePair(run, characterIndex) ? 2 : 1;
        float width = charRanges[characterIndex].width() / m_scalingFactor;

        m_metrics.append(SVGTextMetrics(length, width, cachedFontHeight));

        lastCharacterWasWhiteSpace = currentCharacterIsWhiteSpace;
        characterIndex += length;
    }
}
void SVGTextMetricsBuilder::advanceSimpleText()
{
#if PLATFORM(QT) && !HAVE(QRAWFONT)
    ASSERT_NOT_REACHED();
#else
    GlyphBuffer glyphBuffer;
    unsigned metricsLength = m_simpleWidthIterator->advance(m_textPosition + 1, &glyphBuffer);
    if (!metricsLength) {
        m_currentMetrics = SVGTextMetrics();
        return;
    }

    if (currentCharacterStartsSurrogatePair())
        ASSERT(metricsLength == 2);

    float currentWidth = m_simpleWidthIterator->runWidthSoFar() - m_totalWidth;
    m_totalWidth = m_simpleWidthIterator->runWidthSoFar();

#if ENABLE(SVG_FONTS)
    m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, m_simpleWidthIterator->lastGlyphName());
#else
    m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, emptyString());
#endif
#endif
}
SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterSimple(unsigned textPosition)
{
    GlyphBuffer glyphBuffer;
    unsigned metricsLength = m_simpleShaper->advance(textPosition + 1, &glyphBuffer);
    if (!metricsLength)
        return SVGTextMetrics();

    float currentWidth = m_simpleShaper->runWidthSoFar() - m_totalWidth;
    m_totalWidth = m_simpleShaper->runWidthSoFar();

    return SVGTextMetrics(m_text, textPosition, metricsLength, currentWidth);
}
Beispiel #4
0
void SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer(RenderSVGInlineText* text)
{
    m_text = text;
    m_textPosition = 0;
    m_currentMetrics = SVGTextMetrics();
    m_complexStartToCurrentMetrics = SVGTextMetrics();
    m_totalWidth = 0;

    const Font& scaledFont = text->scaledFont();
    m_run = SVGTextMetrics::constructTextRun(text, text->characters(), 0, text->textLength());
    m_isComplexText = scaledFont.codePath(m_run) == Font::Complex;

    if (m_isComplexText)
        m_simpleWidthIterator.clear();
    else
        m_simpleWidthIterator = adoptPtr(new WidthIterator(&scaledFont, m_run));
}
Beispiel #5
0
void SVGTextMetricsBuilder::advanceSimpleText()
{
    GlyphBuffer glyphBuffer;
    unsigned metricsLength = m_simpleWidthIterator->advance(m_textPosition + 1, &glyphBuffer);
    if (!metricsLength) {
        m_currentMetrics = SVGTextMetrics();
        return;
    }

    float currentWidth = m_simpleWidthIterator->runWidthSoFar() - m_totalWidth;
    m_totalWidth = m_simpleWidthIterator->runWidthSoFar();

#if ENABLE(SVG_FONTS)
    m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, m_simpleWidthIterator->lastGlyphName());
#else
    m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, emptyString());
#endif
}
static void measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data, bool processRenderer)
{
    ASSERT(text);

    SVGTextLayoutAttributes* attributes = text->layoutAttributes();
    Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues();
    if (processRenderer) {
        if (data->allCharactersMap)
            attributes->clear();
        else
            textMetricsValues->clear();
    }

    SVGTextMetricsCalculator calculator(text);
    bool preserveWhiteSpace = text->style()->whiteSpace() == PRE;
    unsigned surrogatePairCharacters = 0;
    unsigned skippedCharacters = 0;
    unsigned textPosition = 0;
    unsigned textLength = calculator.textLength();

    SVGTextMetrics currentMetrics;
    for (; textPosition < textLength; textPosition += currentMetrics.length()) {
        currentMetrics = calculator.computeMetricsForCharacter(textPosition);
        if (!currentMetrics.length())
            break;

        bool characterIsWhiteSpace = calculator.characterIsWhiteSpace(textPosition);
        if (characterIsWhiteSpace && !preserveWhiteSpace && data->lastCharacterWasWhiteSpace) {
            if (processRenderer)
                textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
            if (data->allCharactersMap)
                skippedCharacters += currentMetrics.length();
            continue;
        }

        if (processRenderer) {
            if (data->allCharactersMap) {
                const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + textPosition - skippedCharacters - surrogatePairCharacters + 1);
                if (it != data->allCharactersMap->end())
                    attributes->characterDataMap().set(textPosition + 1, it->value);
            }
            textMetricsValues->append(currentMetrics);
        }

        if (data->allCharactersMap && calculator.characterStartsSurrogatePair(textPosition))
            surrogatePairCharacters++;

        data->lastCharacterWasWhiteSpace = characterIsWhiteSpace;
    }

    if (!data->allCharactersMap)
        return;

    data->valueListPosition += textPosition - skippedCharacters;
}
void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data)
{
    ASSERT(text);

    SVGTextLayoutAttributes* attributes = text->layoutAttributes();
    Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues();
    if (data->processRenderer) {
        if (data->allCharactersMap)
            attributes->clear();
        else
            textMetricsValues->clear();
    }

    initializeMeasurementWithTextRenderer(text);
    bool preserveWhiteSpace = text->style()->whiteSpace() == PRE;
    int surrogatePairCharacters = 0;

    while (advance()) {
        const UChar* currentCharacter = m_run.data16(m_textPosition);
        if (*currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || *data->lastCharacter == ' ')) {
            if (data->processRenderer)
                textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
            if (data->allCharactersMap)
                data->skippedCharacters += m_currentMetrics.length();
            continue;
        }

        if (data->processRenderer) {
            if (data->allCharactersMap) {
                const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + m_textPosition - data->skippedCharacters - surrogatePairCharacters + 1);
                if (it != data->allCharactersMap->end())
                    attributes->characterDataMap().set(m_textPosition + 1, it->value);
            }
            textMetricsValues->append(m_currentMetrics);
        }

        if (data->allCharactersMap && currentCharacterStartsSurrogatePair())
            surrogatePairCharacters++;

        data->lastCharacter = currentCharacter;
    }

    if (!data->allCharactersMap)
        return;

    data->valueListPosition += m_textPosition - data->skippedCharacters;
    data->skippedCharacters = 0;
}
SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length)
{
    ASSERT(text);
    return SVGTextMetrics(text, constructTextRun(text, position, length));
}
SVGTextMetrics SVGTextMetrics::measureCharacterRange(LineLayoutSVGInlineText textLayoutItem, unsigned position, unsigned length, TextDirection textDirection)
{
    ASSERT(textLayoutItem);
    return SVGTextMetrics(textLayoutItem, constructTextRun(textLayoutItem, position, length, textDirection));
}
Beispiel #10
0
void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const
{
    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { 
        if (child->isSVGInlineText()) {
            RenderSVGInlineText* text = toRenderSVGInlineText(child);
            const UChar* characters = text->characters();
            unsigned textLength = text->textLength();
            bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style());

            SVGTextLayoutAttributes attributes(text);
            attributes.reserveCapacity(textLength);
    
            unsigned valueListPosition = atCharacter;
            unsigned metricsLength = 1;
            SVGTextMetrics lastMetrics(SVGTextMetrics::SkippedSpaceMetrics);

            for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) {
                const UChar& currentCharacter = characters[textPosition];

                SVGTextMetrics startToCurrentMetrics;
                SVGTextMetrics currentMetrics;
                unsigned valueListAdvance = 0;

                if (U16_IS_LEAD(currentCharacter) && (textPosition + 1) < textLength && U16_IS_TRAIL(characters[textPosition + 1])) {
                    // Handle surrogate pairs.
                    startToCurrentMetrics = SVGTextMetrics::measureCharacterRange(text, 0, textPosition + 2);
                    currentMetrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 2);
                    metricsLength = currentMetrics.length();
                    valueListAdvance = 1;
                } else {
                    // Handle BMP characters.
                    startToCurrentMetrics = SVGTextMetrics::measureCharacterRange(text, 0, textPosition + 1);
                    currentMetrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1);
                    metricsLength = currentMetrics.length();
                    valueListAdvance = metricsLength;
                }

                if (!metricsLength)
                    break;
                
                // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken
                // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping.
                // So whenever runWidthAdvance != currentMetrics.width(), we are processing a text run whose length is
                // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated.
                float runWidthAdvance = startToCurrentMetrics.width() - lastMetrics.width();
                if (runWidthAdvance != currentMetrics.width())
                    currentMetrics.setWidth(runWidthAdvance);

                lastMetrics = startToCurrentMetrics;

                if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) {
                    attributes.positioningLists().appendEmptyValues();
                    attributes.textMetricsValues().append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
                    continue;
                }

                SVGTextLayoutAttributes::PositioningLists& positioningLists = attributes.positioningLists();
                positioningLists.appendValuesFromPosition(m_positioningLists, valueListPosition);
                attributes.textMetricsValues().append(currentMetrics);

                // Pad x/y/dx/dy/rotate value lists with empty values, if the metrics span more than one character.
                if (metricsLength > 1) {
                    for (unsigned i = 0; i < metricsLength - 1; ++i)
                        positioningLists.appendEmptyValues();
                }

                lastCharacter = currentCharacter;
                valueListPosition += valueListAdvance;
            }

#if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0
            fprintf(stderr, "\nDumping layout attributes for RenderSVGInlineText, renderer=%p, node=%p (atCharacter: %i)\n", text, text->node(), atCharacter);
            fprintf(stderr, "BiDi properties: unicode-bidi=%i, block direction=%i\n", text->style()->unicodeBidi(), text->style()->direction());
            attributes.dump();
#endif

            text->storeLayoutAttributes(attributes);
            allAttributes.append(attributes);
            atCharacter = valueListPosition;
            continue;
        }

        if (!child->isSVGInline())
            continue;

        propagateLayoutAttributes(child, allAttributes, atCharacter, lastCharacter);
    }
}