📄 svgfont.cpp
字号:
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; } }private: const SVGFontData* m_fontData; SVGFontElement* m_fontElement; SVGTextRunData& m_walkerData; SVGTextRunWalkerCallback m_walkerCallback; SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback;};// Callback & data structures to compute the width of text using SVG Fontsstruct SVGTextRunWalkerMeasuredLengthData { int at; int from; int to; int extraCharsAvailable; int charsConsumed; String glyphName; float scale; float length; const Font* font;};static bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerMeasuredLengthData& data){ if (data.at >= data.from && data.at < data.to) data.length += identifier.horizontalAdvanceX * data.scale; data.at++; return data.at < data.to;}static void floatWidthMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerMeasuredLengthData& data){ // Handle system font fallback FontDescription fontDescription(data.font->fontDescription()); fontDescription.setFamily(FontFamily()); Font font(fontDescription, 0, 0); // spacing handled by SVG text code. font.update(data.font->fontSelector()); data.length += font.floatWidth(run);}SVGFontElement* Font::svgFont() const{ if (!isSVGFont()) return 0; SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) return fontElement; return 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->node())) 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;}float Font::floatWidthUsingSVGFont(const TextRun& run) const{ int charsConsumed; String glyphName; return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed, glyphName);}float Font::floatWidthUsingSVGFont(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const{ return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed, glyphName);}// Callback & data structures to draw text using SVG Fontsstruct SVGTextRunWalkerDrawTextData { int extraCharsAvailable; int charsConsumed; String glyphName; Vector<SVGGlyphIdentifier> glyphIdentifiers; Vector<UChar> fallbackCharacters;};static bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerDrawTextData& data){ data.glyphIdentifiers.append(identifier); return true;}static void drawTextMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerDrawTextData& data){ ASSERT(run.length() == 1); data.glyphIdentifiers.append(SVGGlyphIdentifier()); data.fallbackCharacters.append(run[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()->node())) 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(m_fontDescription); fontDescription.setFamily(FontFamily()); Font font(fontDescription, 0, 0); // spacing handled by SVG text code. font.update(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++; } } }}FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun& run, const IntPoint& point, int height, int from, int to) const{ int charsConsumed; String glyphName; return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName), point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height);}int Font::offsetForPositionForTextUsingSVGFont(const TextRun&, int, bool) const{ // TODO: Fix text selection when HTML text is drawn using a SVG Font // We need to integrate the SVG text selection code in the offsetForPosition() framework. // This will also fix a major issue, that SVG Text code can't select arabic strings properly. return 0;}}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -