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
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,
00067 SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SNone , SNone , SNone , SNone , SNone ,
00068 SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDual , SNone , SNone , SNone , SNone , SNone , SNone ,
00069 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone ,
00070 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone ,
00071 SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual ,
00072 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight,
00073 SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual ,
00074 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual ,
00075 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual ,
00076 SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight,
00077 SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone ,
00078 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone ,
00079 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SDual , SDual , SDual , SNone , SNone , SNone
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
00091
00092
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
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
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
00176 if (!identifier.languages.isEmpty()) {
00177
00178
00179 if (language.isEmpty())
00180 return false;
00181
00182
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
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
00225
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
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
00269
00270
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
00301 identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element);
00302 SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
00303 identifier.isValid = true;
00304 } else {
00305
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
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
00355 FontDescription fontDescription(data.font->fontDescription());
00356 fontDescription.setFamily(FontFamily());
00357 Font font(fontDescription, 0, 0);
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;
00405
00406
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
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
00475 if (!run.referencingRenderObject()) {
00476 ASSERT(!activePaintServer);
00477
00478
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
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
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
00537
00538
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
00555 FontDescription fontDescription(context->font().fontDescription());
00556 fontDescription.setFamily(FontFamily());
00557 Font font(fontDescription, 0, 0);
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
00587
00588
00589 return 0;
00590 }
00591
00592 }
00593
00594 #endif