static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, bool ltr, int& lastGlyphCount, const SimpleFontData* fontData, WidthIterator& iterator, TypesettingFeatures typesettingFeatures, CharactersTreatedAsSpace& charactersTreatedAsSpace)
{
    ASSERT(typesettingFeatures & (Kerning | Ligatures));

    if (!glyphBuffer)
        return 0;

    int glyphBufferSize = glyphBuffer->size();
    if (glyphBuffer->size() <= lastGlyphCount + 1)
        return 0;

    GlyphBufferAdvance* advances = glyphBuffer->advances(0);
    float widthDifference = 0;
    for (int i = lastGlyphCount; i < glyphBufferSize; ++i)
        widthDifference -= advances[i].width();

    if (!ltr)
        glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount);

#if !ENABLE(SVG_FONTS)
    UNUSED_PARAM(iterator);
#else
    // We need to handle transforms on SVG fonts internally, since they are rendered internally.
    if (fontData->isSVGFont()) {
        // SVG font ligatures are handled during glyph selection, only kerning remaining.
        if (iterator.run().renderingContext() && (typesettingFeatures & Kerning)) {
            // FIXME: We could pass the necessary context down to this level so we can lazily create rendering contexts at this point.
            // However, a larger refactoring of SVG fonts might necessary to sidestep this problem completely.
            iterator.run().renderingContext()->applySVGKerning(fontData, iterator, glyphBuffer, lastGlyphCount);
        }
    } else
#endif
        fontData->applyTransforms(glyphBuffer->glyphs(lastGlyphCount), advances + lastGlyphCount, glyphBufferSize - lastGlyphCount, typesettingFeatures);

    if (!ltr)
        glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount);

    for (size_t i = 0; i < charactersTreatedAsSpace.size(); ++i) {
        int spaceOffset = charactersTreatedAsSpace[i].first;
        const OriginalAdvancesForCharacterTreatedAsSpace& originalAdvances = charactersTreatedAsSpace[i].second;
        if (spaceOffset && !originalAdvances.characterIsSpace)
            glyphBuffer->advances(spaceOffset - 1)->setWidth(originalAdvances.advanceBeforeCharacter);
        glyphBuffer->advances(spaceOffset)->setWidth(originalAdvances.advanceAtCharacter);
    }
    charactersTreatedAsSpace.clear();

    for (int i = lastGlyphCount; i < glyphBufferSize; ++i)
        widthDifference += advances[i].width();

    lastGlyphCount = glyphBufferSize;
    return widthDifference;
}
Example #2
0
static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, bool ltr, int& lastGlyphCount, const SimpleFontData* fontData, WidthIterator& iterator, TypesettingFeatures typesettingFeatures, CharactersTreatedAsSpace& charactersTreatedAsSpace)
{
    ASSERT(typesettingFeatures & (Kerning | Ligatures));

    if (!glyphBuffer)
        return 0;

    int glyphBufferSize = glyphBuffer->size();
    if (glyphBuffer->size() <= lastGlyphCount + 1)
        return 0;

    GlyphBufferAdvance* advances = glyphBuffer->advances(0);
    float widthDifference = 0;
    for (int i = lastGlyphCount; i < glyphBufferSize; ++i)
        widthDifference -= advances[i].width();

    if (!ltr)
        glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount);

#if ENABLE(SVG_FONTS)
    // We need to handle transforms on SVG fonts internally, since they are rendered internally.
    if (fontData->isSVGFont()) {
        // SVG font fallbacks doesn't work properly and will not have a renderingContext. see: textRunNeedsRenderingContext()
        // SVG font ligatures are handled during glyph selection, only kerning remaining.
        if (iterator.run().renderingContext() && (typesettingFeatures & Kerning))
            iterator.run().renderingContext()->applySVGKerning(fontData, iterator, glyphBuffer, lastGlyphCount);
    } else
#endif
        fontData->applyTransforms(glyphBuffer->glyphs(lastGlyphCount), advances + lastGlyphCount, glyphBufferSize - lastGlyphCount, typesettingFeatures);

    if (!ltr)
        glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount);

    for (size_t i = 0; i < charactersTreatedAsSpace.size(); ++i) {
        int spaceOffset = charactersTreatedAsSpace[i].first;
        const OriginalAdvancesForCharacterTreatedAsSpace& originalAdvances = charactersTreatedAsSpace[i].second;
        if (spaceOffset && !originalAdvances.characterIsSpace)
            glyphBuffer->advances(spaceOffset - 1)->setWidth(originalAdvances.advanceBeforeCharacter);
        glyphBuffer->advances(spaceOffset)->setWidth(originalAdvances.advanceAtCharacter);
    }
    charactersTreatedAsSpace.clear();

    for (int i = lastGlyphCount; i < glyphBufferSize; ++i)
        widthDifference += advances[i].width();

    lastGlyphCount = glyphBufferSize;
    return widthDifference;
}
bool SVGTextRunRenderingContext::applySVGKerning(const SimpleFontData* fontData, WidthIterator& iterator, GlyphBuffer* glyphBuffer, int from) const
{
    ASSERT(glyphBuffer);
    ASSERT(glyphBuffer->size() > 1);
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
    if (!fontElement || !fontFaceElement)
        return false;

    if (fontElement->horizontalKerningMapIsEmpty())
        return true;

    float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm());

    String lastGlyphName;
    String lastUnicodeString;
    int characterOffset = iterator.m_currentCharacter;
    String text = iterator.run().string();
    const int glyphCount = glyphBuffer->size() - from;
    GlyphBufferAdvance* advances = glyphBuffer->advances(from);

    for (int i = 0; i < glyphCount; ++i) {
        Glyph glyph = glyphBuffer->glyphAt(from + i);
        if (!glyph)
            continue;
        float kerning = 0;
        SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
        String unicodeString = text.substring(characterOffset, svgGlyph.unicodeStringLength);
        if (i >= 1) {
            // FIXME: Support vertical text.
            kerning = fontElement->horizontalKerningForPairOfStringsAndGlyphs(lastUnicodeString, lastGlyphName, unicodeString, svgGlyph.glyphName);
            advances[i - 1].setWidth(advances[i - 1].width() - kerning * scale);
        }
        lastGlyphName = svgGlyph.glyphName;
        lastUnicodeString = unicodeString;
        characterOffset += svgGlyph.unicodeStringLength;
    }

    return true;
}
Example #4
0
bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength, String& normalizedSpacesStringCache) const
{
    const TextRun& run = iterator.run();
    Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
    ASSERT(run.charactersLength() >= static_cast<unsigned>(currentCharacter));

    SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
    ASSERT(svgFontFaceElement);

    SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
    ASSERT(associatedFontElement);

    RenderObject* renderObject = nullptr;
    if (TextRun::RenderingContext* renderingContext = run.renderingContext())
        renderObject = &static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();

    String language;
    bool isVerticalText = false;
    Vector<String> altGlyphNames;

    if (renderObject) {
        RenderElement& parentRenderer = is<RenderElement>(*renderObject) ? downcast<RenderElement>(*renderObject) : *renderObject->parent();

        isVerticalText = parentRenderer.style().svgStyle().isVerticalWritingMode();
        if (Element* parentRendererElement = parentRenderer.element()) {
            language = parentRendererElement->getAttribute(XMLNames::langAttr);

            if (is<SVGAltGlyphElement>(*parentRendererElement)) {
                SVGAltGlyphElement& altGlyph = downcast<SVGAltGlyphElement>(*parentRendererElement);
                if (!altGlyph.hasValidGlyphElements(altGlyphNames))
                    altGlyphNames.clear();
            }
        }
    }

    Vector<SVGGlyph> glyphs;
    size_t altGlyphNamesSize = altGlyphNames.size();
    if (altGlyphNamesSize) {
        for (size_t index = 0; index < altGlyphNamesSize; ++index)
            associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs);

        // Assign the unicodeStringLength now that its known.
        size_t glyphsSize = glyphs.size();
        for (size_t i = 0; i < glyphsSize; ++i)
            glyphs[i].unicodeStringLength = run.length();

        // Do not check alt glyphs for compatibility. Just return the first one.
        // Later code will fail if we do not do this and the glyph is incompatible.
        if (glyphsSize) {
            SVGGlyph& svgGlyph = glyphs[0];
            iterator.setLastGlyphName(svgGlyph.glyphName);
            glyphData.glyph = svgGlyph.tableEntry;
            advanceLength = svgGlyph.unicodeStringLength;
            return true;
        }
    } else {
        // Associate text with arabic forms, if needed.
        computeNormalizedSpaces(run, mirror, normalizedSpacesStringCache);
        auto remainingTextInRun = normalizedSpacesStringCache.substring(currentCharacter);

        if (!currentCharacter && arabicForms.isEmpty())
            arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);

        associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
    }

    size_t glyphsSize = glyphs.size();
    for (size_t i = 0; i < glyphsSize; ++i) {
        SVGGlyph& svgGlyph = glyphs[i];
        if (svgGlyph.isPartOfLigature)
            continue;
        if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
            continue;
        iterator.setLastGlyphName(svgGlyph.glyphName);
        glyphData.glyph = svgGlyph.tableEntry;
        advanceLength = svgGlyph.unicodeStringLength;
        return true;
    }

    iterator.setLastGlyphName(String());
    return false;
}
Example #5
0
bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const
{
    const TextRun& run = iterator.run();
    Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
    ASSERT(int(run.charactersLength()) >= currentCharacter);

    // Associate text with arabic forms, if needed.
    String remainingTextInRun(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
    remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters(), remainingTextInRun.length());
    if (mirror)
        remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun.characters(), remainingTextInRun.length());
    if (!currentCharacter && arabicForms.isEmpty())
        arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);

    SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
    ASSERT(svgFontFaceElement);

    SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
    ASSERT(associatedFontElement);

    RenderObject* renderObject = 0;
    if (TextRun::RenderingContext* renderingContext = run.renderingContext())
        renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();

    String language;
    bool isVerticalText = false;
    Vector<String> altGlyphNames;

    if (renderObject) {
        RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
        ASSERT(parentRenderObject);

        isVerticalText = parentRenderObject->style()->svgStyle()->isVerticalWritingMode();
        if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
            language = parentRenderObjectElement->getAttribute(XMLNames::langAttr);

            if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) {
                SVGAltGlyphElement* altGlyph = static_cast<SVGAltGlyphElement*>(parentRenderObjectElement);
                if (!altGlyph->hasValidGlyphElements(altGlyphNames))
                    altGlyphNames.clear();
            }
        }
    }

    Vector<SVGGlyph> glyphs;
    size_t altGlyphNamesSize = altGlyphNames.size();
    if (altGlyphNamesSize) {
        for (size_t index = 0; index < altGlyphNamesSize; ++index)
            associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs);

        // Assign the unicodeStringLength now that its known.
        size_t glyphsSize = glyphs.size();
        for (size_t i = 0; i < glyphsSize; ++i)
            glyphs[i].unicodeStringLength = run.length();
    } else
        associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);

    size_t glyphsSize = glyphs.size();
    for (size_t i = 0; i < glyphsSize; ++i) {
        SVGGlyph& svgGlyph = glyphs[i];
        if (svgGlyph.isPartOfLigature)
            continue;
        if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
            continue;
        iterator.setLastGlyphName(svgGlyph.glyphName);
        glyphData.glyph = svgGlyph.tableEntry;
        advanceLength = svgGlyph.unicodeStringLength;
        return true;
    }

    iterator.setLastGlyphName(String());
    return false;
}