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++; } } } }