• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

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

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal