bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes& logicalAttributes, SVGTextMetrics& logicalMetrics)
{
    logicalMetrics = SVGTextMetrics::emptyMetrics();

    Vector<SVGTextMetrics>& textMetricsValues = logicalAttributes.textMetricsValues();
    unsigned textMetricsSize = textMetricsValues.size();
    while (true) {
        if (m_logicalMetricsListOffset == textMetricsSize) {
            if (!currentLogicalCharacterAttributes(logicalAttributes))
                return false;

            textMetricsValues = logicalAttributes.textMetricsValues();
            textMetricsSize = textMetricsValues.size();
            continue;
        }

        ASSERT(textMetricsSize);
        ASSERT(m_logicalMetricsListOffset < textMetricsSize);
        logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset);
        if (logicalMetrics == SVGTextMetrics::emptyMetrics() || (!logicalMetrics.width() && !logicalMetrics.height())) {
            advanceToNextLogicalCharacter(logicalMetrics);
            continue;
        }

        // Stop if we found the next valid logical text metrics object.
        return true;
    }

    ASSERT_NOT_REACHED();
    return true;
}
Esempio n. 2
0
void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, const SVGTextFragment& fragment, int& startPosition, int& endPosition) const
{
    SVGTextLayoutAttributes* layoutAttributes = queryData->textRenderer->layoutAttributes();
    Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes->textMetricsValues();

    unsigned textMetricsOffset = fragment.metricsListOffset;

    // Compute the offset of the fragment within the box, since that's the
    // space <startPosition, endPosition> is in (and that's what we need).
    int fragmentOffsetInBox = fragment.characterOffset - queryData->textBox->start();
    int fragmentEndInBox = fragmentOffsetInBox + fragment.length;

    // Find the text metrics cell that start at or contain the character startPosition.
    while (fragmentOffsetInBox < fragmentEndInBox) {
        SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset];
        int glyphEnd = fragmentOffsetInBox + metrics.length();
        if (startPosition < glyphEnd)
            break;
        fragmentOffsetInBox = glyphEnd;
        textMetricsOffset++;
    }

    startPosition = fragmentOffsetInBox;

    // Find the text metrics cell that contain or ends at the character endPosition.
    while (fragmentOffsetInBox < fragmentEndInBox) {
        SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset];
        fragmentOffsetInBox += metrics.length();
        if (fragmentOffsetInBox >= endPosition)
            break;
        textMetricsOffset++;
    }

    endPosition = fragmentOffsetInBox;
}
Esempio n. 3
0
void SVGTextLayoutAttributesBuilder::assignLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes, SVGTextMetrics& metrics, unsigned valueListPosition) const
{
    attributes.xValues().append(nextLayoutValue(XValueAttribute, valueListPosition));
    attributes.yValues().append(nextLayoutValue(YValueAttribute, valueListPosition));
    attributes.dxValues().append(nextLayoutValue(DxValueAttribute, valueListPosition));
    attributes.dyValues().append(nextLayoutValue(DyValueAttribute, valueListPosition));
    attributes.rotateValues().append(nextLayoutValue(RotateValueAttribute, valueListPosition));
    attributes.textMetricsValues().append(metrics);
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, 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;
            attributes.reserveCapacity(textLength);
    
            unsigned valueListPosition = atCharacter;
            unsigned metricsLength = 1;
            for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) {
                const UChar& currentCharacter = characters[textPosition];

                SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1);
                metricsLength = metrics.length();

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

                assignLayoutAttributesForCharacter(attributes, metrics, valueListPosition);

                if (metricsLength > 1) {
                    for (unsigned i = 0; i < metricsLength - 1; ++i)
                        assignEmptyLayoutAttributesForCharacter(attributes);
                }

                lastCharacter = currentCharacter;
                valueListPosition += metricsLength;
            }

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

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

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

        propagateLayoutAttributes(child, atCharacter, lastCharacter);
    }
}
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;
}
Esempio n. 7
0
void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, int& startPosition, int& endPosition) const
{
    SVGTextLayoutAttributes* layoutAttributes = queryData->textRenderer->layoutAttributes();
    Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes->textMetricsValues();
    unsigned boxStart = queryData->textBox->start();
    unsigned boxLength = queryData->textBox->len();

    unsigned textMetricsOffset = 0;
    unsigned textMetricsSize = textMetricsValues.size();

    unsigned positionOffset = 0;
    unsigned positionSize = layoutAttributes->context()->textLength();

    bool alterStartPosition = true;
    bool alterEndPosition = true;

    int lastPositionOffset = -1;
    for (; textMetricsOffset < textMetricsSize && positionOffset < positionSize; ++textMetricsOffset) {
        SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset];

        // Advance to text box start location.
        if (positionOffset < boxStart) {
            positionOffset += metrics.length();
            continue;
        }

        // Stop if we've finished processing this text box.
        if (positionOffset >= boxStart + boxLength)
            break;

        // If the start position maps to a character in the metrics list, we don't need to modify it.
        if (startPosition == static_cast<int>(positionOffset))
            alterStartPosition = false;

        // If the start position maps to a character in the metrics list, we don't need to modify it.
        if (endPosition == static_cast<int>(positionOffset))
            alterEndPosition = false;

        // Detect ligatures.
        if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) {
            if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) {
                startPosition = lastPositionOffset;
                alterStartPosition = false;
            }

            if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) {
                endPosition = positionOffset;
                alterEndPosition = false;
            }
        }

        if (!alterStartPosition && !alterEndPosition)
            break;

        lastPositionOffset = positionOffset;
        positionOffset += metrics.length();
    }

    if (!alterStartPosition && !alterEndPosition)
        return;

    if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) {
        if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) {
            startPosition = lastPositionOffset;
            alterStartPosition = false;
        }

        if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) {
            endPosition = positionOffset;
            alterEndPosition = false;
        }
    }
}