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

KHTML

  • sources
  • kde-4.12
  • kdelibs
  • khtml
  • svg
SVGFont.cpp
Go to the documentation of this file.
1 
21 #include "config.h"
22 
23 #if ENABLE(SVG_FONTS)
24 #include "Font.h"
25 
26 #include "CSSFontSelector.h"
27 #include "GraphicsContext.h"
28 #include "RenderObject.h"
29 #include "SimpleFontData.h"
30 #include "SVGAltGlyphElement.h"
31 #include "SVGFontData.h"
32 #include "SVGGlyphElement.h"
33 #include "SVGGlyphMap.h"
34 #include "SVGFontElement.h"
35 #include "SVGFontFaceElement.h"
36 #include "SVGMissingGlyphElement.h"
37 #include "SVGPaintServer.h"
38 #include "SVGPaintServerSolid.h"
39 #include "XMLNames.h"
40 
41 using namespace WTF::Unicode;
42 
43 namespace WebCore {
44 
45 static inline float convertEmUnitToPixel(float fontSize, float unitsPerEm, float value)
46 {
47  if (unitsPerEm == 0.0f)
48  return 0.0f;
49 
50  return value * fontSize / unitsPerEm;
51 }
52 
53 static inline bool isVerticalWritingMode(const SVGRenderStyle* style)
54 {
55  return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB;
56 }
57 
58 // Helper functions to determine the arabic character forms (initial, medial, terminal, isolated)
59 enum ArabicCharShapingMode {
60  SNone = 0,
61  SRight = 1,
62  SDual = 2
63 };
64 
65 static const ArabicCharShapingMode s_arabicCharShapingMode[222] = {
66  SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, SDual , SDual , SDual , SDual , SDual , SRight, /* 0x0622 - 0x062F */
67  SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SNone , SNone , SNone , SNone , SNone , /* 0x0630 - 0x063F */
68  SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDual , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0640 - 0x064F */
69  SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0650 - 0x065F */
70  SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0660 - 0x066F */
71  SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0670 - 0x067F */
72  SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */
73  SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0690 - 0x069F */
74  SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06A0 - 0x06AF */
75  SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06B0 - 0x06BF */
76  SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, /* 0x06C0 - 0x06CF */
77  SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06D0 - 0x06DF */
78  SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06E0 - 0x06EF */
79  SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SDual , SDual , SDual , SNone , SNone , SNone /* 0x06F0 - 0x06FF */
80 };
81 
82 static inline SVGGlyphIdentifier::ArabicForm processArabicFormDetection(const UChar& curChar, bool& lastCharShapesRight, SVGGlyphIdentifier::ArabicForm* prevForm)
83 {
84  SVGGlyphIdentifier::ArabicForm curForm;
85 
86  ArabicCharShapingMode shapingMode = SNone;
87  if (curChar >= 0x0622 && curChar <= 0x06FF)
88  shapingMode = s_arabicCharShapingMode[curChar - 0x0622];
89 
90  // Use a simple state machine to identify the actual arabic form
91  // It depends on the order of the arabic form enum:
92  // enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial };
93 
94  if (lastCharShapesRight && shapingMode == SDual) {
95  if (prevForm) {
96  int correctedForm = (int) *prevForm + 1;
97  ASSERT(correctedForm >= SVGGlyphIdentifier::None && correctedForm <= SVGGlyphIdentifier::Medial);
98  *prevForm = static_cast<SVGGlyphIdentifier::ArabicForm>(correctedForm);
99  }
100 
101  curForm = SVGGlyphIdentifier::Initial;
102  } else
103  curForm = shapingMode == SNone ? SVGGlyphIdentifier::None : SVGGlyphIdentifier::Isolated;
104 
105  lastCharShapesRight = shapingMode != SNone;
106  return curForm;
107 }
108 
109 static Vector<SVGGlyphIdentifier::ArabicForm> charactersWithArabicForm(const String& input, bool rtl)
110 {
111  Vector<SVGGlyphIdentifier::ArabicForm> forms;
112  unsigned int length = input.length();
113 
114  bool containsArabic = false;
115  for (unsigned int i = 0; i < length; ++i) {
116  if (isArabicChar(input[i])) {
117  containsArabic = true;
118  break;
119  }
120  }
121 
122  if (!containsArabic)
123  return forms;
124 
125  bool lastCharShapesRight = false;
126 
127  // Start identifying arabic forms
128  if (rtl)
129  for (int i = length - 1; i >= 0; --i)
130  forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first()));
131  else
132  for (unsigned int i = 0; i < length; ++i)
133  forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last()));
134 
135  return forms;
136 }
137 
138 static inline bool isCompatibleArabicForm(const SVGGlyphIdentifier& identifier, const Vector<SVGGlyphIdentifier::ArabicForm>& chars, unsigned int startPosition, unsigned int endPosition)
139 {
140  if (chars.isEmpty())
141  return true;
142 
143  Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator it = chars.begin() + startPosition;
144  Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator end = chars.begin() + endPosition;
145 
146  ASSERT(end <= chars.end());
147  for (; it != end; ++it) {
148  if ((*it) != identifier.arabicForm && (*it) != SVGGlyphIdentifier::None)
149  return false;
150  }
151 
152  return true;
153 }
154 
155 static inline bool isCompatibleGlyph(const SVGGlyphIdentifier& identifier, bool isVerticalText, const String& language,
156  const Vector<SVGGlyphIdentifier::ArabicForm>& chars, unsigned int startPosition, unsigned int endPosition)
157 {
158  bool valid = true;
159 
160  // Check whether orientation if glyph fits within the request
161  switch (identifier.orientation) {
162  case SVGGlyphIdentifier::Vertical:
163  valid = isVerticalText;
164  break;
165  case SVGGlyphIdentifier::Horizontal:
166  valid = !isVerticalText;
167  break;
168  case SVGGlyphIdentifier::Both:
169  break;
170  }
171 
172  if (!valid)
173  return false;
174 
175  // Check whether languages are compatible
176  if (!identifier.languages.isEmpty()) {
177  // This glyph exists only in certain languages, if we're not specifying a
178  // language on the referencing element we're unable to use this glyph.
179  if (language.isEmpty())
180  return false;
181 
182  // Split subcode from language, if existent.
183  String languagePrefix;
184 
185  int subCodeSeparator = language.find('-');
186  if (subCodeSeparator != -1)
187  languagePrefix = language.left(subCodeSeparator);
188 
189  Vector<String>::const_iterator it = identifier.languages.begin();
190  Vector<String>::const_iterator end = identifier.languages.end();
191 
192  bool found = false;
193  for (; it != end; ++it) {
194  String cur = (*it);
195 
196  if (cur == language || cur == languagePrefix) {
197  found = true;
198  break;
199  }
200  }
201 
202  if (!found)
203  return false;
204  }
205 
206  // Check whether arabic form is compatible
207  return isCompatibleArabicForm(identifier, chars, startPosition, endPosition);
208 }
209 
210 static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const SimpleFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font)
211 {
212  ASSERT(fontData->isCustomFont());
213  ASSERT(fontData->isSVGFont());
214 
215  const SVGFontData* svgFontData = static_cast<const SVGFontData*>(fontData->svgFontData());
216 
217  fontFace = svgFontData->svgFontFaceElement();
218  ASSERT(fontFace);
219 
220  font = fontFace->associatedFontElement();
221  return svgFontData;
222 }
223 
224 // Helper class to walk a text run. Lookup a SVGGlyphIdentifier for each character
225 // - also respecting possibly defined ligatures - and invoke a callback for each found glyph.
226 template<typename SVGTextRunData>
227 struct SVGTextRunWalker {
228  typedef bool (*SVGTextRunWalkerCallback)(const SVGGlyphIdentifier&, SVGTextRunData&);
229  typedef void (*SVGTextRunWalkerMissingGlyphCallback)(const TextRun&, SVGTextRunData&);
230 
231  SVGTextRunWalker(const SVGFontData* fontData, SVGFontElement* fontElement, SVGTextRunData& data,
232  SVGTextRunWalkerCallback callback, SVGTextRunWalkerMissingGlyphCallback missingGlyphCallback)
233  : m_fontData(fontData)
234  , m_fontElement(fontElement)
235  , m_walkerData(data)
236  , m_walkerCallback(callback)
237  , m_walkerMissingGlyphCallback(missingGlyphCallback)
238  {
239  }
240 
241  void walk(const TextRun& run, bool isVerticalText, const String& language, int from, int to)
242  {
243  // Should hold true for SVG text, otherwhise sth. is wrong
244  ASSERT(to - from == run.length());
245 
246  Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(String(run.data(from), run.length()), run.rtl()));
247 
248  SVGGlyphIdentifier identifier;
249  bool foundGlyph = false;
250  int characterLookupRange;
251  int endOfScanRange = to + m_walkerData.extraCharsAvailable;
252 
253  bool haveAltGlyph = false;
254  SVGGlyphIdentifier altGlyphIdentifier;
255  if (RenderObject* renderObject = run.referencingRenderObject()) {
256  if (renderObject->element() && renderObject->element()->hasTagName(SVGNames::altGlyphTag)) {
257  SVGGlyphElement* glyphElement = static_cast<SVGAltGlyphElement*>(renderObject->element())->glyphElement();
258  if (glyphElement) {
259  haveAltGlyph = true;
260  altGlyphIdentifier = glyphElement->buildGlyphIdentifier();
261  altGlyphIdentifier.isValid = true;
262  altGlyphIdentifier.nameLength = to - from;
263  }
264  }
265  }
266 
267  for (int i = from; i < to; ++i) {
268  // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1).
269  // We have to check whether the current character & the next character define a ligature. This needs to be
270  // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature.
271  characterLookupRange = endOfScanRange - i;
272 
273  String lookupString(run.data(i), characterLookupRange);
274  Vector<SVGGlyphIdentifier> glyphs;
275  if (haveAltGlyph)
276  glyphs.append(altGlyphIdentifier);
277  else
278  m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs);
279 
280  Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin();
281  Vector<SVGGlyphIdentifier>::iterator end = glyphs.end();
282 
283  for (; it != end; ++it) {
284  identifier = *it;
285  if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) {
286  ASSERT(characterLookupRange > 0);
287  i += identifier.nameLength - 1;
288  m_walkerData.charsConsumed += identifier.nameLength;
289  m_walkerData.glyphName = identifier.glyphName;
290 
291  foundGlyph = true;
292  SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
293  break;
294  }
295  }
296 
297  if (!foundGlyph) {
298  ++m_walkerData.charsConsumed;
299  if (SVGMissingGlyphElement* element = m_fontElement->firstMissingGlyphElement()) {
300  // <missing-glyph> element support
301  identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element);
302  SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
303  identifier.isValid = true;
304  } else {
305  // Fallback to system font fallback
306  TextRun subRun(run);
307  subRun.setText(subRun.data(i), 1);
308 
309  (*m_walkerMissingGlyphCallback)(subRun, m_walkerData);
310  continue;
311  }
312  }
313 
314  if (!(*m_walkerCallback)(identifier, m_walkerData))
315  break;
316 
317  foundGlyph = false;
318  }
319  }
320 
321 private:
322  const SVGFontData* m_fontData;
323  SVGFontElement* m_fontElement;
324  SVGTextRunData& m_walkerData;
325  SVGTextRunWalkerCallback m_walkerCallback;
326  SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback;
327 };
328 
329 // Callback & data structures to compute the width of text using SVG Fonts
330 struct SVGTextRunWalkerMeasuredLengthData {
331  int at;
332  int from;
333  int to;
334  int extraCharsAvailable;
335  int charsConsumed;
336  String glyphName;
337 
338  float scale;
339  float length;
340  const Font* font;
341 };
342 
343 bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerMeasuredLengthData& data)
344 {
345  if (data.at >= data.from && data.at < data.to)
346  data.length += identifier.horizontalAdvanceX * data.scale;
347 
348  data.at++;
349  return data.at < data.to;
350 }
351 
352 void floatWidthMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerMeasuredLengthData& data)
353 {
354  // Handle system font fallback
355  FontDescription fontDescription(data.font->fontDescription());
356  fontDescription.setFamily(FontFamily());
357  Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
358  font.update(data.font->fontSelector());
359 
360  data.length += font.floatWidth(run);
361 }
362 
363 
364 SVGFontElement* Font::svgFont() const
365 {
366  if (!isSVGFont())
367  return 0;
368 
369  SVGFontElement* fontElement = 0;
370  SVGFontFaceElement* fontFaceElement = 0;
371  if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement))
372  return fontElement;
373 
374  return 0;
375 }
376 
377 static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun& run, int extraCharsAvailable, int from, int to, int& charsConsumed, String& glyphName)
378 {
379  int newFrom = to > from ? from : to;
380  int newTo = to > from ? to : from;
381 
382  from = newFrom;
383  to = newTo;
384 
385  SVGFontElement* fontElement = 0;
386  SVGFontFaceElement* fontFaceElement = 0;
387 
388  if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(font->primaryFont(), fontFaceElement, fontElement)) {
389  if (!fontElement)
390  return 0.0f;
391 
392  SVGTextRunWalkerMeasuredLengthData data;
393 
394  data.font = font;
395  data.at = from;
396  data.from = from;
397  data.to = to;
398  data.extraCharsAvailable = extraCharsAvailable;
399  data.charsConsumed = 0;
400  data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f);
401  data.length = 0.0f;
402 
403  String language;
404  bool isVerticalText = false; // Holds true for HTML text
405 
406  // TODO: language matching & svg glyphs should be possible for HTML text, too.
407  if (RenderObject* renderObject = run.referencingRenderObject()) {
408  isVerticalText = isVerticalWritingMode(renderObject->style()->svgStyle());
409 
410  if (SVGElement* element = static_cast<SVGElement*>(renderObject->element()))
411  language = element->getAttribute(XMLNames::langAttr);
412  }
413 
414  SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback);
415  runWalker.walk(run, isVerticalText, language, 0, run.length());
416  charsConsumed = data.charsConsumed;
417  glyphName = data.glyphName;
418  return data.length;
419  }
420 
421  return 0.0f;
422 }
423 
424 float Font::floatWidthUsingSVGFont(const TextRun& run) const
425 {
426  int charsConsumed;
427  String glyphName;
428  return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed, glyphName);
429 }
430 
431 float Font::floatWidthUsingSVGFont(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
432 {
433  return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed, glyphName);
434 }
435 
436 // Callback & data structures to draw text using SVG Fonts
437 struct SVGTextRunWalkerDrawTextData {
438  int extraCharsAvailable;
439  int charsConsumed;
440  String glyphName;
441  Vector<SVGGlyphIdentifier> glyphIdentifiers;
442  Vector<UChar> fallbackCharacters;
443 };
444 
445 bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerDrawTextData& data)
446 {
447  data.glyphIdentifiers.append(identifier);
448  return true;
449 }
450 
451 void drawTextMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerDrawTextData& data)
452 {
453  ASSERT(run.length() == 1);
454  data.glyphIdentifiers.append(SVGGlyphIdentifier());
455  data.fallbackCharacters.append(run[0]);
456 }
457 
458 void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run,
459  const FloatPoint& point, int from, int to) const
460 {
461  SVGFontElement* fontElement = 0;
462  SVGFontFaceElement* fontFaceElement = 0;
463 
464  if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
465  if (!fontElement)
466  return;
467 
468  SVGTextRunWalkerDrawTextData data;
469  FloatPoint currentPoint = point;
470  float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);
471 
472  SVGPaintServer* activePaintServer = run.activePaintServer();
473 
474  // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
475  if (!run.referencingRenderObject()) {
476  ASSERT(!activePaintServer);
477 
478  // TODO: We're only supporting simple filled HTML text so far.
479  SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
480  solidPaintServer->setColor(context->fillColor());
481 
482  activePaintServer = solidPaintServer;
483  }
484 
485  ASSERT(activePaintServer);
486 
487  int charsConsumed;
488  String glyphName;
489  bool isVerticalText = false;
490  float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
491  FloatPoint glyphOrigin;
492 
493  String language;
494 
495  // TODO: language matching & svg glyphs should be possible for HTML text, too.
496  if (run.referencingRenderObject()) {
497  isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());
498 
499  if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element()))
500  language = element->getAttribute(XMLNames::langAttr);
501  }
502 
503  if (!isVerticalText) {
504  glyphOrigin.setX(fontData->horizontalOriginX() * scale);
505  glyphOrigin.setY(fontData->horizontalOriginY() * scale);
506  }
507 
508  data.extraCharsAvailable = 0;
509 
510  SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
511  runWalker.walk(run, isVerticalText, language, from, to);
512 
513  SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;
514 
515  unsigned numGlyphs = data.glyphIdentifiers.size();
516  unsigned fallbackCharacterIndex = 0;
517  for (unsigned i = 0; i < numGlyphs; ++i) {
518  const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
519  if (identifier.isValid) {
520  // FIXME: Support arbitrary SVG content as glyph (currently limited to <glyph d="..."> situations).
521  if (!identifier.pathData.isEmpty()) {
522  context->save();
523 
524  if (isVerticalText) {
525  glyphOrigin.setX(identifier.verticalOriginX * scale);
526  glyphOrigin.setY(identifier.verticalOriginY * scale);
527  }
528 
529  context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
530  context->scale(FloatSize(scale, -scale));
531 
532  context->beginPath();
533  context->addPath(identifier.pathData);
534 
535  if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
536  // Spec: Any properties specified on a text elements which represents a length, such as the
537  // 'stroke-width' property, might produce surprising results since the length value will be
538  // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
539  if (targetType == ApplyToStrokeTargetType && scale != 0.0f)
540  context->setStrokeThickness(context->strokeThickness() / scale);
541 
542  activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
543  activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
544  }
545 
546  context->restore();
547  }
548 
549  if (isVerticalText)
550  currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
551  else
552  currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
553  } else {
554  // Handle system font fallback
555  FontDescription fontDescription(context->font().fontDescription());
556  fontDescription.setFamily(FontFamily());
557  Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
558  font.update(context->font().fontSelector());
559 
560  TextRun fallbackCharacterRun(run);
561  fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
562  font.drawText(context, fallbackCharacterRun, currentPoint);
563 
564  if (isVerticalText)
565  currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
566  else
567  currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);
568 
569  fallbackCharacterIndex++;
570  }
571  }
572  }
573 }
574 
575 FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun& run, const IntPoint& point, int height, int from, int to) const
576 {
577  int charsConsumed;
578  String glyphName;
579 
580  return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName),
581  point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height);
582 }
583 
584 int Font::offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const
585 {
586  // TODO: Fix text selection when HTML text is drawn using a SVG Font
587  // We need to integrate the SVG text selection code in the offsetForPosition() framework.
588  // This will also fix a major issue, that SVG Text code can't select arabic strings properly.
589  return 0;
590 }
591 
592 }
593 
594 #endif
SVGAltGlyphElement.h
SVGFontElement.h
SVGMissingGlyphElement.h
SVGFontData.h
SVGPaintServer.h
DOM::DOMString::find
int find(const QChar c, int start=0) const
Definition: dom_string.cpp:154
WebCore::SVGNames::langAttr
DOM::QualifiedName langAttr
Definition: SVGNames.cpp:206
SVGFontFaceElement.h
SVGGlyphMap.h
SVGGlyphElement.h
bool
WebCore::SVGNames::altGlyphTag
DOM::QualifiedName altGlyphTag
Definition: SVGNames.cpp:22
WebCore::String
DOM::DOMString String
Definition: PlatformString.h:8
SVGPaintServerSolid.h
RenderObject.h
end
const KShortcut & end()
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:51:22 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KHTML

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal