File indexing completed on 2024-04-28 11:39:13
0001 /** 0002 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Library General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Library General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 * 0019 */ 0020 0021 #if ENABLE(SVG_FONTS) 0022 #include "Font.h" 0023 0024 #include "CSSFontSelector.h" 0025 #include "GraphicsContext.h" 0026 #include "RenderObject.h" 0027 #include "SimpleFontData.h" 0028 #include "SVGAltGlyphElement.h" 0029 #include "SVGFontData.h" 0030 #include "SVGGlyphElement.h" 0031 #include "SVGGlyphMap.h" 0032 #include "SVGFontElement.h" 0033 #include "SVGFontFaceElement.h" 0034 #include "SVGMissingGlyphElement.h" 0035 #include "SVGPaintServer.h" 0036 #include "SVGPaintServerSolid.h" 0037 #include "XMLNames.h" 0038 0039 using namespace WTF::Unicode; 0040 0041 namespace WebCore 0042 { 0043 0044 static inline float convertEmUnitToPixel(float fontSize, float unitsPerEm, float value) 0045 { 0046 if (unitsPerEm == 0.0f) { 0047 return 0.0f; 0048 } 0049 0050 return value * fontSize / unitsPerEm; 0051 } 0052 0053 static inline bool isVerticalWritingMode(const SVGRenderStyle *style) 0054 { 0055 return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB; 0056 } 0057 0058 // Helper functions to determine the arabic character forms (initial, medial, terminal, isolated) 0059 enum ArabicCharShapingMode { 0060 SNone = 0, 0061 SRight = 1, 0062 SDual = 2 0063 }; 0064 0065 static const ArabicCharShapingMode s_arabicCharShapingMode[222] = { 0066 SRight, SRight, SRight, SRight, SDual, SRight, SDual, SRight, SDual, SDual, SDual, SDual, SDual, SRight, /* 0x0622 - 0x062F */ 0067 SRight, SRight, SRight, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SNone, SNone, SNone, SNone, SNone, /* 0x0630 - 0x063F */ 0068 SNone, SDual, SDual, SDual, SDual, SDual, SDual, SRight, SDual, SDual, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x0640 - 0x064F */ 0069 SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x0650 - 0x065F */ 0070 SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x0660 - 0x066F */ 0071 SNone, SRight, SRight, SRight, SNone, SRight, SRight, SRight, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x0670 - 0x067F */ 0072 SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */ 0073 SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x0690 - 0x069F */ 0074 SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x06A0 - 0x06AF */ 0075 SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x06B0 - 0x06BF */ 0076 SRight, SDual, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual, SRight, SDual, SRight, /* 0x06C0 - 0x06CF */ 0077 SDual, SDual, SRight, SRight, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x06D0 - 0x06DF */ 0078 SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x06E0 - 0x06EF */ 0079 SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SDual, SDual, SDual, SNone, SNone, SNone /* 0x06F0 - 0x06FF */ 0080 }; 0081 0082 static inline SVGGlyphIdentifier::ArabicForm processArabicFormDetection(const UChar &curChar, bool &lastCharShapesRight, SVGGlyphIdentifier::ArabicForm *prevForm) 0083 { 0084 SVGGlyphIdentifier::ArabicForm curForm; 0085 0086 ArabicCharShapingMode shapingMode = SNone; 0087 if (curChar >= 0x0622 && curChar <= 0x06FF) { 0088 shapingMode = s_arabicCharShapingMode[curChar - 0x0622]; 0089 } 0090 0091 // Use a simple state machine to identify the actual arabic form 0092 // It depends on the order of the arabic form enum: 0093 // enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial }; 0094 0095 if (lastCharShapesRight && shapingMode == SDual) { 0096 if (prevForm) { 0097 int correctedForm = (int) * prevForm + 1; 0098 ASSERT(correctedForm >= SVGGlyphIdentifier::None && correctedForm <= SVGGlyphIdentifier::Medial); 0099 *prevForm = static_cast<SVGGlyphIdentifier::ArabicForm>(correctedForm); 0100 } 0101 0102 curForm = SVGGlyphIdentifier::Initial; 0103 } else { 0104 curForm = shapingMode == SNone ? SVGGlyphIdentifier::None : SVGGlyphIdentifier::Isolated; 0105 } 0106 0107 lastCharShapesRight = shapingMode != SNone; 0108 return curForm; 0109 } 0110 0111 static Vector<SVGGlyphIdentifier::ArabicForm> charactersWithArabicForm(const String &input, bool rtl) 0112 { 0113 Vector<SVGGlyphIdentifier::ArabicForm> forms; 0114 unsigned int length = input.length(); 0115 0116 bool containsArabic = false; 0117 for (unsigned int i = 0; i < length; ++i) { 0118 if (isArabicChar(input[i])) { 0119 containsArabic = true; 0120 break; 0121 } 0122 } 0123 0124 if (!containsArabic) { 0125 return forms; 0126 } 0127 0128 bool lastCharShapesRight = false; 0129 0130 // Start identifying arabic forms 0131 if (rtl) 0132 for (int i = length - 1; i >= 0; --i) { 0133 forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first())); 0134 } 0135 else 0136 for (unsigned int i = 0; i < length; ++i) { 0137 forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last())); 0138 } 0139 0140 return forms; 0141 } 0142 0143 static inline bool isCompatibleArabicForm(const SVGGlyphIdentifier &identifier, const Vector<SVGGlyphIdentifier::ArabicForm> &chars, unsigned int startPosition, unsigned int endPosition) 0144 { 0145 if (chars.isEmpty()) { 0146 return true; 0147 } 0148 0149 Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator it = chars.begin() + startPosition; 0150 Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator end = chars.begin() + endPosition; 0151 0152 ASSERT(end <= chars.end()); 0153 for (; it != end; ++it) { 0154 if ((*it) != identifier.arabicForm && (*it) != SVGGlyphIdentifier::None) { 0155 return false; 0156 } 0157 } 0158 0159 return true; 0160 } 0161 0162 static inline bool isCompatibleGlyph(const SVGGlyphIdentifier &identifier, bool isVerticalText, const String &language, 0163 const Vector<SVGGlyphIdentifier::ArabicForm> &chars, unsigned int startPosition, unsigned int endPosition) 0164 { 0165 bool valid = true; 0166 0167 // Check whether orientation if glyph fits within the request 0168 switch (identifier.orientation) { 0169 case SVGGlyphIdentifier::Vertical: 0170 valid = isVerticalText; 0171 break; 0172 case SVGGlyphIdentifier::Horizontal: 0173 valid = !isVerticalText; 0174 break; 0175 case SVGGlyphIdentifier::Both: 0176 break; 0177 } 0178 0179 if (!valid) { 0180 return false; 0181 } 0182 0183 // Check whether languages are compatible 0184 if (!identifier.languages.isEmpty()) { 0185 // This glyph exists only in certain languages, if we're not specifying a 0186 // language on the referencing element we're unable to use this glyph. 0187 if (language.isEmpty()) { 0188 return false; 0189 } 0190 0191 // Split subcode from language, if existent. 0192 String languagePrefix; 0193 0194 int subCodeSeparator = language.find('-'); 0195 if (subCodeSeparator != -1) { 0196 languagePrefix = language.left(subCodeSeparator); 0197 } 0198 0199 Vector<String>::const_iterator it = identifier.languages.begin(); 0200 Vector<String>::const_iterator end = identifier.languages.end(); 0201 0202 bool found = false; 0203 for (; it != end; ++it) { 0204 String cur = (*it); 0205 0206 if (cur == language || cur == languagePrefix) { 0207 found = true; 0208 break; 0209 } 0210 } 0211 0212 if (!found) { 0213 return false; 0214 } 0215 } 0216 0217 // Check whether arabic form is compatible 0218 return isCompatibleArabicForm(identifier, chars, startPosition, endPosition); 0219 } 0220 0221 static inline const SVGFontData *svgFontAndFontFaceElementForFontData(const SimpleFontData *fontData, SVGFontFaceElement *&fontFace, SVGFontElement *&font) 0222 { 0223 ASSERT(fontData->isCustomFont()); 0224 ASSERT(fontData->isSVGFont()); 0225 0226 const SVGFontData *svgFontData = static_cast<const SVGFontData *>(fontData->svgFontData()); 0227 0228 fontFace = svgFontData->svgFontFaceElement(); 0229 ASSERT(fontFace); 0230 0231 font = fontFace->associatedFontElement(); 0232 return svgFontData; 0233 } 0234 0235 // Helper class to walk a text run. Lookup a SVGGlyphIdentifier for each character 0236 // - also respecting possibly defined ligatures - and invoke a callback for each found glyph. 0237 template<typename SVGTextRunData> 0238 struct SVGTextRunWalker { 0239 typedef bool (*SVGTextRunWalkerCallback)(const SVGGlyphIdentifier &, SVGTextRunData &); 0240 typedef void (*SVGTextRunWalkerMissingGlyphCallback)(const TextRun &, SVGTextRunData &); 0241 0242 SVGTextRunWalker(const SVGFontData *fontData, SVGFontElement *fontElement, SVGTextRunData &data, 0243 SVGTextRunWalkerCallback callback, SVGTextRunWalkerMissingGlyphCallback missingGlyphCallback) 0244 : m_fontData(fontData) 0245 , m_fontElement(fontElement) 0246 , m_walkerData(data) 0247 , m_walkerCallback(callback) 0248 , m_walkerMissingGlyphCallback(missingGlyphCallback) 0249 { 0250 } 0251 0252 void walk(const TextRun &run, bool isVerticalText, const String &language, int from, int to) 0253 { 0254 // Should hold true for SVG text, otherwhise sth. is wrong 0255 ASSERT(to - from == run.length()); 0256 0257 Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(String(run.data(from), run.length()), run.rtl())); 0258 0259 SVGGlyphIdentifier identifier; 0260 bool foundGlyph = false; 0261 int characterLookupRange; 0262 int endOfScanRange = to + m_walkerData.extraCharsAvailable; 0263 0264 bool haveAltGlyph = false; 0265 SVGGlyphIdentifier altGlyphIdentifier; 0266 if (RenderObject *renderObject = run.referencingRenderObject()) { 0267 if (renderObject->element() && renderObject->element()->hasTagName(SVGNames::altGlyphTag)) { 0268 SVGGlyphElement *glyphElement = static_cast<SVGAltGlyphElement *>(renderObject->element())->glyphElement(); 0269 if (glyphElement) { 0270 haveAltGlyph = true; 0271 altGlyphIdentifier = glyphElement->buildGlyphIdentifier(); 0272 altGlyphIdentifier.isValid = true; 0273 altGlyphIdentifier.nameLength = to - from; 0274 } 0275 } 0276 } 0277 0278 for (int i = from; i < to; ++i) { 0279 // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1). 0280 // We have to check whether the current character & the next character define a ligature. This needs to be 0281 // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature. 0282 characterLookupRange = endOfScanRange - i; 0283 0284 String lookupString(run.data(i), characterLookupRange); 0285 Vector<SVGGlyphIdentifier> glyphs; 0286 if (haveAltGlyph) { 0287 glyphs.append(altGlyphIdentifier); 0288 } else { 0289 m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs); 0290 } 0291 0292 Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin(); 0293 Vector<SVGGlyphIdentifier>::iterator end = glyphs.end(); 0294 0295 for (; it != end; ++it) { 0296 identifier = *it; 0297 if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) { 0298 ASSERT(characterLookupRange > 0); 0299 i += identifier.nameLength - 1; 0300 m_walkerData.charsConsumed += identifier.nameLength; 0301 m_walkerData.glyphName = identifier.glyphName; 0302 0303 foundGlyph = true; 0304 SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData); 0305 break; 0306 } 0307 } 0308 0309 if (!foundGlyph) { 0310 ++m_walkerData.charsConsumed; 0311 if (SVGMissingGlyphElement *element = m_fontElement->firstMissingGlyphElement()) { 0312 // <missing-glyph> element support 0313 identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element); 0314 SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData); 0315 identifier.isValid = true; 0316 } else { 0317 // Fallback to system font fallback 0318 TextRun subRun(run); 0319 subRun.setText(subRun.data(i), 1); 0320 0321 (*m_walkerMissingGlyphCallback)(subRun, m_walkerData); 0322 continue; 0323 } 0324 } 0325 0326 if (!(*m_walkerCallback)(identifier, m_walkerData)) { 0327 break; 0328 } 0329 0330 foundGlyph = false; 0331 } 0332 } 0333 0334 private: 0335 const SVGFontData *m_fontData; 0336 SVGFontElement *m_fontElement; 0337 SVGTextRunData &m_walkerData; 0338 SVGTextRunWalkerCallback m_walkerCallback; 0339 SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback; 0340 }; 0341 0342 // Callback & data structures to compute the width of text using SVG Fonts 0343 struct SVGTextRunWalkerMeasuredLengthData { 0344 int at; 0345 int from; 0346 int to; 0347 int extraCharsAvailable; 0348 int charsConsumed; 0349 String glyphName; 0350 0351 float scale; 0352 float length; 0353 const Font *font; 0354 }; 0355 0356 bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier &identifier, SVGTextRunWalkerMeasuredLengthData &data) 0357 { 0358 if (data.at >= data.from && data.at < data.to) { 0359 data.length += identifier.horizontalAdvanceX * data.scale; 0360 } 0361 0362 data.at++; 0363 return data.at < data.to; 0364 } 0365 0366 void floatWidthMissingGlyphCallback(const TextRun &run, SVGTextRunWalkerMeasuredLengthData &data) 0367 { 0368 // Handle system font fallback 0369 FontDescription fontDescription(data.font->fontDescription()); 0370 fontDescription.setFamily(FontFamily()); 0371 Font font(fontDescription, 0, 0); // spacing handled by SVG text code. 0372 font.update(data.font->fontSelector()); 0373 0374 data.length += font.floatWidth(run); 0375 } 0376 0377 SVGFontElement *Font::svgFont() const 0378 { 0379 if (!isSVGFont()) { 0380 return 0; 0381 } 0382 0383 SVGFontElement *fontElement = 0; 0384 SVGFontFaceElement *fontFaceElement = 0; 0385 if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) { 0386 return fontElement; 0387 } 0388 0389 return 0; 0390 } 0391 0392 static float floatWidthOfSubStringUsingSVGFont(const Font *font, const TextRun &run, int extraCharsAvailable, int from, int to, int &charsConsumed, String &glyphName) 0393 { 0394 int newFrom = to > from ? from : to; 0395 int newTo = to > from ? to : from; 0396 0397 from = newFrom; 0398 to = newTo; 0399 0400 SVGFontElement *fontElement = 0; 0401 SVGFontFaceElement *fontFaceElement = 0; 0402 0403 if (const SVGFontData *fontData = svgFontAndFontFaceElementForFontData(font->primaryFont(), fontFaceElement, fontElement)) { 0404 if (!fontElement) { 0405 return 0.0f; 0406 } 0407 0408 SVGTextRunWalkerMeasuredLengthData data; 0409 0410 data.font = font; 0411 data.at = from; 0412 data.from = from; 0413 data.to = to; 0414 data.extraCharsAvailable = extraCharsAvailable; 0415 data.charsConsumed = 0; 0416 data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f); 0417 data.length = 0.0f; 0418 0419 String language; 0420 bool isVerticalText = false; // Holds true for HTML text 0421 0422 // TODO: language matching & svg glyphs should be possible for HTML text, too. 0423 if (RenderObject *renderObject = run.referencingRenderObject()) { 0424 isVerticalText = isVerticalWritingMode(renderObject->style()->svgStyle()); 0425 0426 if (SVGElement *element = static_cast<SVGElement *>(renderObject->element())) { 0427 language = element->getAttribute(XMLNames::langAttr); 0428 } 0429 } 0430 0431 SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback); 0432 runWalker.walk(run, isVerticalText, language, 0, run.length()); 0433 charsConsumed = data.charsConsumed; 0434 glyphName = data.glyphName; 0435 return data.length; 0436 } 0437 0438 return 0.0f; 0439 } 0440 0441 float Font::floatWidthUsingSVGFont(const TextRun &run) const 0442 { 0443 int charsConsumed; 0444 String glyphName; 0445 return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed, glyphName); 0446 } 0447 0448 float Font::floatWidthUsingSVGFont(const TextRun &run, int extraCharsAvailable, int &charsConsumed, String &glyphName) const 0449 { 0450 return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed, glyphName); 0451 } 0452 0453 // Callback & data structures to draw text using SVG Fonts 0454 struct SVGTextRunWalkerDrawTextData { 0455 int extraCharsAvailable; 0456 int charsConsumed; 0457 String glyphName; 0458 Vector<SVGGlyphIdentifier> glyphIdentifiers; 0459 Vector<UChar> fallbackCharacters; 0460 }; 0461 0462 bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier &identifier, SVGTextRunWalkerDrawTextData &data) 0463 { 0464 data.glyphIdentifiers.append(identifier); 0465 return true; 0466 } 0467 0468 void drawTextMissingGlyphCallback(const TextRun &run, SVGTextRunWalkerDrawTextData &data) 0469 { 0470 ASSERT(run.length() == 1); 0471 data.glyphIdentifiers.append(SVGGlyphIdentifier()); 0472 data.fallbackCharacters.append(run[0]); 0473 } 0474 0475 void Font::drawTextUsingSVGFont(GraphicsContext *context, const TextRun &run, 0476 const FloatPoint &point, int from, int to) const 0477 { 0478 SVGFontElement *fontElement = 0; 0479 SVGFontFaceElement *fontFaceElement = 0; 0480 0481 if (const SVGFontData *fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) { 0482 if (!fontElement) { 0483 return; 0484 } 0485 0486 SVGTextRunWalkerDrawTextData data; 0487 FloatPoint currentPoint = point; 0488 float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f); 0489 0490 SVGPaintServer *activePaintServer = run.activePaintServer(); 0491 0492 // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts. 0493 if (!run.referencingRenderObject()) { 0494 ASSERT(!activePaintServer); 0495 0496 // TODO: We're only supporting simple filled HTML text so far. 0497 SVGPaintServerSolid *solidPaintServer = SVGPaintServer::sharedSolidPaintServer(); 0498 solidPaintServer->setColor(context->fillColor()); 0499 0500 activePaintServer = solidPaintServer; 0501 } 0502 0503 ASSERT(activePaintServer); 0504 0505 int charsConsumed; 0506 String glyphName; 0507 bool isVerticalText = false; 0508 float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName); 0509 FloatPoint glyphOrigin; 0510 0511 String language; 0512 0513 // TODO: language matching & svg glyphs should be possible for HTML text, too. 0514 if (run.referencingRenderObject()) { 0515 isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle()); 0516 0517 if (SVGElement *element = static_cast<SVGElement *>(run.referencingRenderObject()->element())) { 0518 language = element->getAttribute(XMLNames::langAttr); 0519 } 0520 } 0521 0522 if (!isVerticalText) { 0523 glyphOrigin.setX(fontData->horizontalOriginX() * scale); 0524 glyphOrigin.setY(fontData->horizontalOriginY() * scale); 0525 } 0526 0527 data.extraCharsAvailable = 0; 0528 0529 SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback); 0530 runWalker.walk(run, isVerticalText, language, from, to); 0531 0532 SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType; 0533 0534 unsigned numGlyphs = data.glyphIdentifiers.size(); 0535 unsigned fallbackCharacterIndex = 0; 0536 for (unsigned i = 0; i < numGlyphs; ++i) { 0537 const SVGGlyphIdentifier &identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i]; 0538 if (identifier.isValid) { 0539 // FIXME: Support arbitrary SVG content as glyph (currently limited to <glyph d="..."> situations). 0540 if (!identifier.pathData.isEmpty()) { 0541 context->save(); 0542 0543 if (isVerticalText) { 0544 glyphOrigin.setX(identifier.verticalOriginX * scale); 0545 glyphOrigin.setY(identifier.verticalOriginY * scale); 0546 } 0547 0548 context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); 0549 context->scale(FloatSize(scale, -scale)); 0550 0551 context->beginPath(); 0552 context->addPath(identifier.pathData); 0553 0554 if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) { 0555 // Spec: Any properties specified on a text elements which represents a length, such as the 0556 // 'stroke-width' property, might produce surprising results since the length value will be 0557 // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?) 0558 if (targetType == ApplyToStrokeTargetType && scale != 0.0f) { 0559 context->setStrokeThickness(context->strokeThickness() / scale); 0560 } 0561 0562 activePaintServer->renderPath(context, run.referencingRenderObject(), targetType); 0563 activePaintServer->teardown(context, run.referencingRenderObject(), targetType); 0564 } 0565 0566 context->restore(); 0567 } 0568 0569 if (isVerticalText) { 0570 currentPoint.move(0.0f, identifier.verticalAdvanceY * scale); 0571 } else { 0572 currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f); 0573 } 0574 } else { 0575 // Handle system font fallback 0576 FontDescription fontDescription(context->font().fontDescription()); 0577 fontDescription.setFamily(FontFamily()); 0578 Font font(fontDescription, 0, 0); // spacing handled by SVG text code. 0579 font.update(context->font().fontSelector()); 0580 0581 TextRun fallbackCharacterRun(run); 0582 fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1); 0583 font.drawText(context, fallbackCharacterRun, currentPoint); 0584 0585 if (isVerticalText) { 0586 currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun)); 0587 } else { 0588 currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f); 0589 } 0590 0591 fallbackCharacterIndex++; 0592 } 0593 } 0594 } 0595 } 0596 0597 FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun &run, const IntPoint &point, int height, int from, int to) const 0598 { 0599 int charsConsumed; 0600 String glyphName; 0601 0602 return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName), 0603 point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height); 0604 } 0605 0606 int Font::offsetForPositionForTextUsingSVGFont(const TextRun &, int position, bool includePartialGlyphs) const 0607 { 0608 // TODO: Fix text selection when HTML text is drawn using a SVG Font 0609 // We need to integrate the SVG text selection code in the offsetForPosition() framework. 0610 // This will also fix a major issue, that SVG Text code can't select arabic strings properly. 0611 return 0; 0612 } 0613 0614 } 0615 0616 #endif