예제 #1
0
static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun& run, int extraCharsAvailable, int from, int to, int& charsConsumed, String& glyphName)
{
    int newFrom = to > from ? from : to;
    int newTo = to > from ? to : from;

    from = newFrom;
    to = newTo;

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

    if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(font->primaryFont(), fontFaceElement, fontElement)) {
        if (!fontElement)
            return 0.0f;

        SVGTextRunWalkerMeasuredLengthData data;

        data.font = font;
        data.at = from;
        data.from = from;
        data.to = to;
        data.extraCharsAvailable = extraCharsAvailable;
        data.charsConsumed = 0;
        data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f);
        data.length = 0.0f;

        String language;
        bool isVerticalText = false; // Holds true for HTML text

        // TODO: language matching & svg glyphs should be possible for HTML text, too.
        if (RenderObject* renderObject = run.referencingRenderObject()) {
            isVerticalText = isVerticalWritingMode(renderObject->style()->svgStyle());

            if (SVGElement* element = static_cast<SVGElement*>(renderObject->element()))
                language = element->getAttribute(XMLNames::langAttr);
        }

        SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback);
        runWalker.walk(run, isVerticalText, language, 0, run.length());
        charsConsumed = data.charsConsumed;
        glyphName = data.glyphName;
        return data.length;
    }

    return 0.0f;
}
예제 #2
0
void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run, 
                                const FloatPoint& point, int from, int to) const
{
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
        if (!fontElement)
            return;

        SVGTextRunWalkerDrawTextData data;
        FloatPoint currentPoint = point;
        float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);

        SVGPaintServer* activePaintServer = run.activePaintServer();

        // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
        if (!run.referencingRenderObject()) {
            ASSERT(!activePaintServer);

            // TODO: We're only supporting simple filled HTML text so far.
            SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
            solidPaintServer->setColor(context->fillColor());

            activePaintServer = solidPaintServer;
        }

        ASSERT(activePaintServer);

        int charsConsumed;
        String glyphName;
        bool isVerticalText = false;
        float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
        FloatPoint glyphOrigin;

        String language;

        // TODO: language matching & svg glyphs should be possible for HTML text, too.
        if (run.referencingRenderObject()) {
            isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());    

            if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element()))
                language = element->getAttribute(XMLNames::langAttr);
        }

        if (!isVerticalText) {
            glyphOrigin.setX(fontData->horizontalOriginX() * scale);
            glyphOrigin.setY(fontData->horizontalOriginY() * scale);
        }

        data.extraCharsAvailable = 0;
        data.charsConsumed = 0;

        SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
        runWalker.walk(run, isVerticalText, language, from, to);

        SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;

        unsigned numGlyphs = data.glyphIdentifiers.size();
        unsigned fallbackCharacterIndex = 0;
        for (unsigned i = 0; i < numGlyphs; ++i) {
            const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
            if (identifier.isValid) {
                // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
                if (!identifier.pathData.isEmpty()) {
                    context->save();

                    if (isVerticalText) {
                        glyphOrigin.setX(identifier.verticalOriginX * scale);
                        glyphOrigin.setY(identifier.verticalOriginY * scale);
                    }

                    context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
                    context->scale(FloatSize(scale, -scale));

                    context->beginPath();
                    context->addPath(identifier.pathData);

                    if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
                        // Spec: Any properties specified on a text elements which represents a length, such as the
                        // 'stroke-width' property, might produce surprising results since the length value will be
                        // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
                        if (targetType == ApplyToStrokeTargetType && scale != 0.0f)
                            context->setStrokeThickness(context->strokeThickness() / scale);

                        activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
                        activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
                    }

                    context->restore();
                }

                if (isVerticalText)
                    currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
                else
                    currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
            } else {
                // Handle system font fallback
                FontDescription fontDescription(context->font().fontDescription());
                fontDescription.setFamily(FontFamily());
                Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
                font.update(context->font().fontSelector());

                TextRun fallbackCharacterRun(run);
                fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
                font.drawText(context, fallbackCharacterRun, currentPoint);

                if (isVerticalText)
                    currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
                else
                    currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);

                fallbackCharacterIndex++;
            }
        }
    }
}
예제 #3
0
    void walk(const TextRun& run, bool isVerticalText, const String& language, int from, int to)
    {
        // Should hold true for SVG text, otherwhise sth. is wrong
        ASSERT(to - from == run.length());

        Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(String(run.data(from), run.length()), run.rtl()));

        SVGGlyphIdentifier identifier;
        bool foundGlyph = false;
        int characterLookupRange;
        int endOfScanRange = to + m_walkerData.extraCharsAvailable;

        bool haveAltGlyph = false;
        SVGGlyphIdentifier altGlyphIdentifier;
        if (RenderObject* renderObject = run.referencingRenderObject()) {
            if (renderObject->element() && renderObject->element()->hasTagName(SVGNames::altGlyphTag)) {
                SVGGlyphElement* glyphElement = static_cast<SVGAltGlyphElement*>(renderObject->element())->glyphElement();
                if (glyphElement) {
                    haveAltGlyph = true;
                    altGlyphIdentifier = glyphElement->buildGlyphIdentifier();
                    altGlyphIdentifier.isValid = true;
                    altGlyphIdentifier.nameLength = to - from;
                }
            }
        }

        for (int i = from; i < to; ++i) {
            // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1).
            // We have to check wheter the current character & the next character define a ligature. This needs to be
            // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature.
            characterLookupRange = endOfScanRange - i;

            String lookupString(run.data(i), characterLookupRange);
            Vector<SVGGlyphIdentifier> glyphs;
            if (haveAltGlyph)
                glyphs.append(altGlyphIdentifier);
            else
                m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs);

            Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin();
            Vector<SVGGlyphIdentifier>::iterator end = glyphs.end();
            
            for (; it != end; ++it) {
                identifier = *it;
                if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) {
                    ASSERT(characterLookupRange > 0);
                    i += identifier.nameLength - 1;
                    m_walkerData.charsConsumed += identifier.nameLength;
                    m_walkerData.glyphName = identifier.glyphName;

                    foundGlyph = true;
                    SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
                    break;
                }
            }

            if (!foundGlyph) {
                ++m_walkerData.charsConsumed;
                if (SVGMissingGlyphElement* element = m_fontElement->firstMissingGlyphElement()) {
                    // <missing-glyph> element support
                    identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element);
                    SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
                    identifier.isValid = true;
                } else {
                    // Fallback to system font fallback
                    TextRun subRun(run);
                    subRun.setText(subRun.data(i), 1);

                    (*m_walkerMissingGlyphCallback)(subRun, m_walkerData);
                    continue;
                }
            }

            if (!(*m_walkerCallback)(identifier, m_walkerData))
                break;

            foundGlyph = false;
        }
    }