bool RenderSVGTextPath::isChildAllowed(RenderObject* child, RenderStyle*) const
{
    if (child->isText())
        return SVGRenderSupport::isRenderableTextNode(child);

#if ENABLE(SVG_FONTS)
    // 'altGlyph' is supported by the content model for 'textPath', but...
    ASSERT(child->node());
    if (isSVGAltGlyphElement(*child->node()))
        return false;
#endif

    return child->isSVGInline() && !child->isSVGTextPath();
}
Beispiel #2
0
bool SVGTSpanElement::rendererIsNeeded(const RenderStyle& style)
{
    if (parentNode()
        && (isSVGAElement(*parentNode())
#if ENABLE(SVG_FONTS)
            || isSVGAltGlyphElement(*parentNode())
#endif
            || isSVGTextElement(*parentNode())
            || isSVGTextPathElement(*parentNode())
            || isSVGTSpanElement(*parentNode())))
        return Element::rendererIsNeeded(style);

    return false;
}
bool RenderSVGTSpan::isChildAllowed(RenderObject* child, RenderStyle*) const
{
    // Always allow text (except empty textnodes and <br>).
    if (child->isText())
        return SVGRenderSupport::isRenderableTextNode(child);

#if ENABLE(SVG_FONTS)
    // Only allow other types of  children if this is not an 'altGlyph'.
    ASSERT(node());
    if (isSVGAltGlyphElement(*node()))
        return false;
#endif

    return child->isSVGInline() && !child->isSVGTextPath();
}
GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, const TextRun& run, WidthIterator& iterator, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength)
{
    const SimpleFontData* primaryFont = font.primaryFont();
    ASSERT(primaryFont);

    pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(character, mirror);
    GlyphData glyphData = pair.first;

    // Check if we have the missing glyph data, in which case we can just return.
    GlyphData missingGlyphData = primaryFont->missingGlyphData();
    if (glyphData.glyph == missingGlyphData.glyph && glyphData.fontData == missingGlyphData.fontData) {
        ASSERT(glyphData.fontData);
        return glyphData;
    }

    // Save data fromt he font fallback list because we may modify it later. Do this before the
    // potential change to glyphData.fontData below.
    FontFallbackList* fontList = font.fontList();
    ASSERT(fontList);
    FontFallbackList::GlyphPagesStateSaver glyphPagesSaver(*fontList);

    // Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage.
    const SimpleFontData* originalFontData = glyphData.fontData;
    if (originalFontData && !originalFontData->isSVGFont()) {
        if (TextRun::RenderingContext* renderingContext = run.renderingContext()) {
            RenderObject* renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
            RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
            ASSERT(parentRenderObject);
            if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
                if (isSVGAltGlyphElement(*parentRenderObjectElement))
                    glyphData.fontData = primaryFont;
            }
        }
    }

    const SimpleFontData* fontData = glyphData.fontData;
    if (fontData) {
        if (!fontData->isSVGFont())
            return glyphData;

        SVGFontElement* fontElement = 0;
        SVGFontFaceElement* fontFaceElement = 0;

        const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
        if (!fontElement || !fontFaceElement)
            return glyphData;

        // If we got here, we're dealing with a glyph defined in a SVG Font.
        // The returned glyph by glyphDataAndPageForCharacter() is a glyph stored in the SVG Font glyph table.
        // This doesn't necessarily mean the glyph is suitable for rendering/measuring in this context, its
        // arabic-form/orientation/... may not match, we have to apply SVG Glyph selection to discover that.
        if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, currentCharacter, advanceLength))
            return glyphData;
    }

    GlyphPage* page = pair.second;
    ASSERT(page);

    // No suitable glyph found that is compatible with the requirments (same language, arabic-form, orientation etc.)
    // Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily
    // remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly.
    page->setGlyphDataForCharacter(character, 0, 0);

    // Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before.
    GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror);
    ASSERT(fallbackGlyphData.fontData != fontData);

    // Restore original state of the SVG Font glyph table and the current font fallback list,
    // to assure the next lookup of the same glyph won't immediately return the fallback glyph.
    page->setGlyphDataForCharacter(character, glyphData.glyph, originalFontData);
    ASSERT(fallbackGlyphData.fontData);
    return fallbackGlyphData;
}
Beispiel #5
0
bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, unsigned currentCharacter, unsigned& advanceLength) const
{
    const TextRun& run = iterator.run();
    Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
    ASSERT(run.charactersLength() >= currentCharacter);

    // Associate text with arabic forms, if needed.
    String remainingTextInRun;

    if (run.is8Bit()) {
        remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter);
        remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length());
    } else {
        remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
        remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length());
    }

    if (mirror)
        remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun);
    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) {
        RenderElement* parentRenderer = renderObject->isRenderElement() ? toRenderElement(renderObject) : renderObject->parent();
        ASSERT(parentRenderer);

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

            if (isSVGAltGlyphElement(parentRendererElement)) {
                SVGAltGlyphElement* altGlyph = toSVGAltGlyphElement(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
        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;
}