KHTML
SVGFont.cpp
Go to the documentation of this file.
00001 00021 #include "config.h" 00022 00023 #if ENABLE(SVG_FONTS) 00024 #include "Font.h" 00025 00026 #include "CSSFontSelector.h" 00027 #include "GraphicsContext.h" 00028 #include "RenderObject.h" 00029 #include "SimpleFontData.h" 00030 #include "SVGAltGlyphElement.h" 00031 #include "SVGFontData.h" 00032 #include "SVGGlyphElement.h" 00033 #include "SVGGlyphMap.h" 00034 #include "SVGFontElement.h" 00035 #include "SVGFontFaceElement.h" 00036 #include "SVGMissingGlyphElement.h" 00037 #include "SVGPaintServer.h" 00038 #include "SVGPaintServerSolid.h" 00039 #include "XMLNames.h" 00040 00041 using namespace WTF::Unicode; 00042 00043 namespace WebCore { 00044 00045 static inline float convertEmUnitToPixel(float fontSize, float unitsPerEm, float value) 00046 { 00047 if (unitsPerEm == 0.0f) 00048 return 0.0f; 00049 00050 return value * fontSize / unitsPerEm; 00051 } 00052 00053 static inline bool isVerticalWritingMode(const SVGRenderStyle* style) 00054 { 00055 return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB; 00056 } 00057 00058 // Helper functions to determine the arabic character forms (initial, medial, terminal, isolated) 00059 enum ArabicCharShapingMode { 00060 SNone = 0, 00061 SRight = 1, 00062 SDual = 2 00063 }; 00064 00065 static const ArabicCharShapingMode s_arabicCharShapingMode[222] = { 00066 SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, SDual , SDual , SDual , SDual , SDual , SRight, /* 0x0622 - 0x062F */ 00067 SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SNone , SNone , SNone , SNone , SNone , /* 0x0630 - 0x063F */ 00068 SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDual , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0640 - 0x064F */ 00069 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0650 - 0x065F */ 00070 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0660 - 0x066F */ 00071 SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0670 - 0x067F */ 00072 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */ 00073 SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0690 - 0x069F */ 00074 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06A0 - 0x06AF */ 00075 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06B0 - 0x06BF */ 00076 SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, /* 0x06C0 - 0x06CF */ 00077 SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06D0 - 0x06DF */ 00078 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06E0 - 0x06EF */ 00079 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SDual , SDual , SDual , SNone , SNone , SNone /* 0x06F0 - 0x06FF */ 00080 }; 00081 00082 static inline SVGGlyphIdentifier::ArabicForm processArabicFormDetection(const UChar& curChar, bool& lastCharShapesRight, SVGGlyphIdentifier::ArabicForm* prevForm) 00083 { 00084 SVGGlyphIdentifier::ArabicForm curForm; 00085 00086 ArabicCharShapingMode shapingMode = SNone; 00087 if (curChar >= 0x0622 && curChar <= 0x06FF) 00088 shapingMode = s_arabicCharShapingMode[curChar - 0x0622]; 00089 00090 // Use a simple state machine to identify the actual arabic form 00091 // It depends on the order of the arabic form enum: 00092 // enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial }; 00093 00094 if (lastCharShapesRight && shapingMode == SDual) { 00095 if (prevForm) { 00096 int correctedForm = (int) *prevForm + 1; 00097 ASSERT(correctedForm >= SVGGlyphIdentifier::None && correctedForm <= SVGGlyphIdentifier::Medial); 00098 *prevForm = static_cast<SVGGlyphIdentifier::ArabicForm>(correctedForm); 00099 } 00100 00101 curForm = SVGGlyphIdentifier::Initial; 00102 } else 00103 curForm = shapingMode == SNone ? SVGGlyphIdentifier::None : SVGGlyphIdentifier::Isolated; 00104 00105 lastCharShapesRight = shapingMode != SNone; 00106 return curForm; 00107 } 00108 00109 static Vector<SVGGlyphIdentifier::ArabicForm> charactersWithArabicForm(const String& input, bool rtl) 00110 { 00111 Vector<SVGGlyphIdentifier::ArabicForm> forms; 00112 unsigned int length = input.length(); 00113 00114 bool containsArabic = false; 00115 for (unsigned int i = 0; i < length; ++i) { 00116 if (isArabicChar(input[i])) { 00117 containsArabic = true; 00118 break; 00119 } 00120 } 00121 00122 if (!containsArabic) 00123 return forms; 00124 00125 bool lastCharShapesRight = false; 00126 00127 // Start identifying arabic forms 00128 if (rtl) 00129 for (int i = length - 1; i >= 0; --i) 00130 forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first())); 00131 else 00132 for (unsigned int i = 0; i < length; ++i) 00133 forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last())); 00134 00135 return forms; 00136 } 00137 00138 static inline bool isCompatibleArabicForm(const SVGGlyphIdentifier& identifier, const Vector<SVGGlyphIdentifier::ArabicForm>& chars, unsigned int startPosition, unsigned int endPosition) 00139 { 00140 if (chars.isEmpty()) 00141 return true; 00142 00143 Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator it = chars.begin() + startPosition; 00144 Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator end = chars.begin() + endPosition; 00145 00146 ASSERT(end <= chars.end()); 00147 for (; it != end; ++it) { 00148 if ((*it) != identifier.arabicForm && (*it) != SVGGlyphIdentifier::None) 00149 return false; 00150 } 00151 00152 return true; 00153 } 00154 00155 static inline bool isCompatibleGlyph(const SVGGlyphIdentifier& identifier, bool isVerticalText, const String& language, 00156 const Vector<SVGGlyphIdentifier::ArabicForm>& chars, unsigned int startPosition, unsigned int endPosition) 00157 { 00158 bool valid = true; 00159 00160 // Check whether orientation if glyph fits within the request 00161 switch (identifier.orientation) { 00162 case SVGGlyphIdentifier::Vertical: 00163 valid = isVerticalText; 00164 break; 00165 case SVGGlyphIdentifier::Horizontal: 00166 valid = !isVerticalText; 00167 break; 00168 case SVGGlyphIdentifier::Both: 00169 break; 00170 } 00171 00172 if (!valid) 00173 return false; 00174 00175 // Check whether languages are compatible 00176 if (!identifier.languages.isEmpty()) { 00177 // This glyph exists only in certain languages, if we're not specifying a 00178 // language on the referencing element we're unable to use this glyph. 00179 if (language.isEmpty()) 00180 return false; 00181 00182 // Split subcode from language, if existent. 00183 String languagePrefix; 00184 00185 int subCodeSeparator = language.find('-'); 00186 if (subCodeSeparator != -1) 00187 languagePrefix = language.left(subCodeSeparator); 00188 00189 Vector<String>::const_iterator it = identifier.languages.begin(); 00190 Vector<String>::const_iterator end = identifier.languages.end(); 00191 00192 bool found = false; 00193 for (; it != end; ++it) { 00194 String cur = (*it); 00195 00196 if (cur == language || cur == languagePrefix) { 00197 found = true; 00198 break; 00199 } 00200 } 00201 00202 if (!found) 00203 return false; 00204 } 00205 00206 // Check whether arabic form is compatible 00207 return isCompatibleArabicForm(identifier, chars, startPosition, endPosition); 00208 } 00209 00210 static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const SimpleFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font) 00211 { 00212 ASSERT(fontData->isCustomFont()); 00213 ASSERT(fontData->isSVGFont()); 00214 00215 const SVGFontData* svgFontData = static_cast<const SVGFontData*>(fontData->svgFontData()); 00216 00217 fontFace = svgFontData->svgFontFaceElement(); 00218 ASSERT(fontFace); 00219 00220 font = fontFace->associatedFontElement(); 00221 return svgFontData; 00222 } 00223 00224 // Helper class to walk a text run. Lookup a SVGGlyphIdentifier for each character 00225 // - also respecting possibly defined ligatures - and invoke a callback for each found glyph. 00226 template<typename SVGTextRunData> 00227 struct SVGTextRunWalker { 00228 typedef bool (*SVGTextRunWalkerCallback)(const SVGGlyphIdentifier&, SVGTextRunData&); 00229 typedef void (*SVGTextRunWalkerMissingGlyphCallback)(const TextRun&, SVGTextRunData&); 00230 00231 SVGTextRunWalker(const SVGFontData* fontData, SVGFontElement* fontElement, SVGTextRunData& data, 00232 SVGTextRunWalkerCallback callback, SVGTextRunWalkerMissingGlyphCallback missingGlyphCallback) 00233 : m_fontData(fontData) 00234 , m_fontElement(fontElement) 00235 , m_walkerData(data) 00236 , m_walkerCallback(callback) 00237 , m_walkerMissingGlyphCallback(missingGlyphCallback) 00238 { 00239 } 00240 00241 void walk(const TextRun& run, bool isVerticalText, const String& language, int from, int to) 00242 { 00243 // Should hold true for SVG text, otherwhise sth. is wrong 00244 ASSERT(to - from == run.length()); 00245 00246 Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(String(run.data(from), run.length()), run.rtl())); 00247 00248 SVGGlyphIdentifier identifier; 00249 bool foundGlyph = false; 00250 int characterLookupRange; 00251 int endOfScanRange = to + m_walkerData.extraCharsAvailable; 00252 00253 bool haveAltGlyph = false; 00254 SVGGlyphIdentifier altGlyphIdentifier; 00255 if (RenderObject* renderObject = run.referencingRenderObject()) { 00256 if (renderObject->element() && renderObject->element()->hasTagName(SVGNames::altGlyphTag)) { 00257 SVGGlyphElement* glyphElement = static_cast<SVGAltGlyphElement*>(renderObject->element())->glyphElement(); 00258 if (glyphElement) { 00259 haveAltGlyph = true; 00260 altGlyphIdentifier = glyphElement->buildGlyphIdentifier(); 00261 altGlyphIdentifier.isValid = true; 00262 altGlyphIdentifier.nameLength = to - from; 00263 } 00264 } 00265 } 00266 00267 for (int i = from; i < to; ++i) { 00268 // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1). 00269 // We have to check whether the current character & the next character define a ligature. This needs to be 00270 // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature. 00271 characterLookupRange = endOfScanRange - i; 00272 00273 String lookupString(run.data(i), characterLookupRange); 00274 Vector<SVGGlyphIdentifier> glyphs; 00275 if (haveAltGlyph) 00276 glyphs.append(altGlyphIdentifier); 00277 else 00278 m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs); 00279 00280 Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin(); 00281 Vector<SVGGlyphIdentifier>::iterator end = glyphs.end(); 00282 00283 for (; it != end; ++it) { 00284 identifier = *it; 00285 if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) { 00286 ASSERT(characterLookupRange > 0); 00287 i += identifier.nameLength - 1; 00288 m_walkerData.charsConsumed += identifier.nameLength; 00289 m_walkerData.glyphName = identifier.glyphName; 00290 00291 foundGlyph = true; 00292 SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData); 00293 break; 00294 } 00295 } 00296 00297 if (!foundGlyph) { 00298 ++m_walkerData.charsConsumed; 00299 if (SVGMissingGlyphElement* element = m_fontElement->firstMissingGlyphElement()) { 00300 // <missing-glyph> element support 00301 identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element); 00302 SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData); 00303 identifier.isValid = true; 00304 } else { 00305 // Fallback to system font fallback 00306 TextRun subRun(run); 00307 subRun.setText(subRun.data(i), 1); 00308 00309 (*m_walkerMissingGlyphCallback)(subRun, m_walkerData); 00310 continue; 00311 } 00312 } 00313 00314 if (!(*m_walkerCallback)(identifier, m_walkerData)) 00315 break; 00316 00317 foundGlyph = false; 00318 } 00319 } 00320 00321 private: 00322 const SVGFontData* m_fontData; 00323 SVGFontElement* m_fontElement; 00324 SVGTextRunData& m_walkerData; 00325 SVGTextRunWalkerCallback m_walkerCallback; 00326 SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback; 00327 }; 00328 00329 // Callback & data structures to compute the width of text using SVG Fonts 00330 struct SVGTextRunWalkerMeasuredLengthData { 00331 int at; 00332 int from; 00333 int to; 00334 int extraCharsAvailable; 00335 int charsConsumed; 00336 String glyphName; 00337 00338 float scale; 00339 float length; 00340 const Font* font; 00341 }; 00342 00343 bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerMeasuredLengthData& data) 00344 { 00345 if (data.at >= data.from && data.at < data.to) 00346 data.length += identifier.horizontalAdvanceX * data.scale; 00347 00348 data.at++; 00349 return data.at < data.to; 00350 } 00351 00352 void floatWidthMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerMeasuredLengthData& data) 00353 { 00354 // Handle system font fallback 00355 FontDescription fontDescription(data.font->fontDescription()); 00356 fontDescription.setFamily(FontFamily()); 00357 Font font(fontDescription, 0, 0); // spacing handled by SVG text code. 00358 font.update(data.font->fontSelector()); 00359 00360 data.length += font.floatWidth(run); 00361 } 00362 00363 00364 SVGFontElement* Font::svgFont() const 00365 { 00366 if (!isSVGFont()) 00367 return 0; 00368 00369 SVGFontElement* fontElement = 0; 00370 SVGFontFaceElement* fontFaceElement = 0; 00371 if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) 00372 return fontElement; 00373 00374 return 0; 00375 } 00376 00377 static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun& run, int extraCharsAvailable, int from, int to, int& charsConsumed, String& glyphName) 00378 { 00379 int newFrom = to > from ? from : to; 00380 int newTo = to > from ? to : from; 00381 00382 from = newFrom; 00383 to = newTo; 00384 00385 SVGFontElement* fontElement = 0; 00386 SVGFontFaceElement* fontFaceElement = 0; 00387 00388 if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(font->primaryFont(), fontFaceElement, fontElement)) { 00389 if (!fontElement) 00390 return 0.0f; 00391 00392 SVGTextRunWalkerMeasuredLengthData data; 00393 00394 data.font = font; 00395 data.at = from; 00396 data.from = from; 00397 data.to = to; 00398 data.extraCharsAvailable = extraCharsAvailable; 00399 data.charsConsumed = 0; 00400 data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f); 00401 data.length = 0.0f; 00402 00403 String language; 00404 bool isVerticalText = false; // Holds true for HTML text 00405 00406 // TODO: language matching & svg glyphs should be possible for HTML text, too. 00407 if (RenderObject* renderObject = run.referencingRenderObject()) { 00408 isVerticalText = isVerticalWritingMode(renderObject->style()->svgStyle()); 00409 00410 if (SVGElement* element = static_cast<SVGElement*>(renderObject->element())) 00411 language = element->getAttribute(XMLNames::langAttr); 00412 } 00413 00414 SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback); 00415 runWalker.walk(run, isVerticalText, language, 0, run.length()); 00416 charsConsumed = data.charsConsumed; 00417 glyphName = data.glyphName; 00418 return data.length; 00419 } 00420 00421 return 0.0f; 00422 } 00423 00424 float Font::floatWidthUsingSVGFont(const TextRun& run) const 00425 { 00426 int charsConsumed; 00427 String glyphName; 00428 return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed, glyphName); 00429 } 00430 00431 float Font::floatWidthUsingSVGFont(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const 00432 { 00433 return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed, glyphName); 00434 } 00435 00436 // Callback & data structures to draw text using SVG Fonts 00437 struct SVGTextRunWalkerDrawTextData { 00438 int extraCharsAvailable; 00439 int charsConsumed; 00440 String glyphName; 00441 Vector<SVGGlyphIdentifier> glyphIdentifiers; 00442 Vector<UChar> fallbackCharacters; 00443 }; 00444 00445 bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerDrawTextData& data) 00446 { 00447 data.glyphIdentifiers.append(identifier); 00448 return true; 00449 } 00450 00451 void drawTextMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerDrawTextData& data) 00452 { 00453 ASSERT(run.length() == 1); 00454 data.glyphIdentifiers.append(SVGGlyphIdentifier()); 00455 data.fallbackCharacters.append(run[0]); 00456 } 00457 00458 void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run, 00459 const FloatPoint& point, int from, int to) const 00460 { 00461 SVGFontElement* fontElement = 0; 00462 SVGFontFaceElement* fontFaceElement = 0; 00463 00464 if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) { 00465 if (!fontElement) 00466 return; 00467 00468 SVGTextRunWalkerDrawTextData data; 00469 FloatPoint currentPoint = point; 00470 float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f); 00471 00472 SVGPaintServer* activePaintServer = run.activePaintServer(); 00473 00474 // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts. 00475 if (!run.referencingRenderObject()) { 00476 ASSERT(!activePaintServer); 00477 00478 // TODO: We're only supporting simple filled HTML text so far. 00479 SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer(); 00480 solidPaintServer->setColor(context->fillColor()); 00481 00482 activePaintServer = solidPaintServer; 00483 } 00484 00485 ASSERT(activePaintServer); 00486 00487 int charsConsumed; 00488 String glyphName; 00489 bool isVerticalText = false; 00490 float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName); 00491 FloatPoint glyphOrigin; 00492 00493 String language; 00494 00495 // TODO: language matching & svg glyphs should be possible for HTML text, too. 00496 if (run.referencingRenderObject()) { 00497 isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle()); 00498 00499 if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element())) 00500 language = element->getAttribute(XMLNames::langAttr); 00501 } 00502 00503 if (!isVerticalText) { 00504 glyphOrigin.setX(fontData->horizontalOriginX() * scale); 00505 glyphOrigin.setY(fontData->horizontalOriginY() * scale); 00506 } 00507 00508 data.extraCharsAvailable = 0; 00509 00510 SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback); 00511 runWalker.walk(run, isVerticalText, language, from, to); 00512 00513 SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType; 00514 00515 unsigned numGlyphs = data.glyphIdentifiers.size(); 00516 unsigned fallbackCharacterIndex = 0; 00517 for (unsigned i = 0; i < numGlyphs; ++i) { 00518 const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i]; 00519 if (identifier.isValid) { 00520 // FIXME: Support arbitrary SVG content as glyph (currently limited to <glyph d="..."> situations). 00521 if (!identifier.pathData.isEmpty()) { 00522 context->save(); 00523 00524 if (isVerticalText) { 00525 glyphOrigin.setX(identifier.verticalOriginX * scale); 00526 glyphOrigin.setY(identifier.verticalOriginY * scale); 00527 } 00528 00529 context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); 00530 context->scale(FloatSize(scale, -scale)); 00531 00532 context->beginPath(); 00533 context->addPath(identifier.pathData); 00534 00535 if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) { 00536 // Spec: Any properties specified on a text elements which represents a length, such as the 00537 // 'stroke-width' property, might produce surprising results since the length value will be 00538 // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?) 00539 if (targetType == ApplyToStrokeTargetType && scale != 0.0f) 00540 context->setStrokeThickness(context->strokeThickness() / scale); 00541 00542 activePaintServer->renderPath(context, run.referencingRenderObject(), targetType); 00543 activePaintServer->teardown(context, run.referencingRenderObject(), targetType); 00544 } 00545 00546 context->restore(); 00547 } 00548 00549 if (isVerticalText) 00550 currentPoint.move(0.0f, identifier.verticalAdvanceY * scale); 00551 else 00552 currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f); 00553 } else { 00554 // Handle system font fallback 00555 FontDescription fontDescription(context->font().fontDescription()); 00556 fontDescription.setFamily(FontFamily()); 00557 Font font(fontDescription, 0, 0); // spacing handled by SVG text code. 00558 font.update(context->font().fontSelector()); 00559 00560 TextRun fallbackCharacterRun(run); 00561 fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1); 00562 font.drawText(context, fallbackCharacterRun, currentPoint); 00563 00564 if (isVerticalText) 00565 currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun)); 00566 else 00567 currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f); 00568 00569 fallbackCharacterIndex++; 00570 } 00571 } 00572 } 00573 } 00574 00575 FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun& run, const IntPoint& point, int height, int from, int to) const 00576 { 00577 int charsConsumed; 00578 String glyphName; 00579 00580 return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName), 00581 point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height); 00582 } 00583 00584 int Font::offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const 00585 { 00586 // TODO: Fix text selection when HTML text is drawn using a SVG Font 00587 // We need to integrate the SVG text selection code in the offsetForPosition() framework. 00588 // This will also fix a major issue, that SVG Text code can't select arabic strings properly. 00589 return 0; 00590 } 00591 00592 } 00593 00594 #endif
KDE 4.6 API Reference