Changeset 846 for trunk/src/gui/text/qfontengine_s60.cpp
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/gui/text/qfontengine_s60.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 42 42 #include "qfontengine_s60_p.h" 43 43 #include "qtextengine_p.h" 44 #include "qendian.h" 44 45 #include "qglobal.h" 45 46 #include <private/qapplication_p.h> 46 47 #include "qimage.h" 47 48 #include <private/qt_s60_p.h> 49 #include <private/qpixmap_s60_p.h> 48 50 49 51 #include <e32base.h> … … 51 53 #include <eikenv.h> 52 54 #include <gdi.h> 55 #if defined(Q_SYMBIAN_HAS_GLYPHOUTLINE_API) 56 #include <graphics/gdi/gdiplatapi.h> 57 #endif // Q_SYMBIAN_HAS_GLYPHOUTLINE_API 58 59 // Replication of TGetFontTableParam & friends. 60 // There is unfortunately no compile time flag like SYMBIAN_FONT_TABLE_API 61 // that would help us to only replicate these things for Symbian versions 62 // that do not yet have the font table Api. Symbian's public SDK does 63 // generally not define any usable macros. 64 class QSymbianTGetFontTableParam 65 { 66 public: 67 TUint32 iTag; 68 TAny *iContent; 69 TInt iLength; 70 }; 71 const TUid QSymbianKFontGetFontTable = {0x102872C1}; 72 const TUid QSymbianKFontReleaseFontTable = {0x2002AC24}; 53 73 54 74 QT_BEGIN_NAMESPACE 55 75 56 QSymbianTypeFaceExtras::QSymbianTypeFaceExtras(CFont* fontOwner, COpenFont *font) 57 : m_font(font) 58 , m_cmap(0) 76 QSymbianTypeFaceExtras::QSymbianTypeFaceExtras(CFont* cFont, COpenFont *openFont) 77 : m_cFont(cFont) 59 78 , m_symbolCMap(false) 60 , m_fontOwner(fontOwner) 61 { 62 TAny *trueTypeExtension = NULL; 63 m_font->ExtendedInterface(KUidOpenFontTrueTypeExtension, trueTypeExtension); 64 m_trueTypeExtension = static_cast<MOpenFontTrueTypeExtension*>(trueTypeExtension); 65 Q_ASSERT(m_trueTypeExtension); 79 , m_openFont(openFont) 80 { 81 if (!symbianFontTableApiAvailable()) { 82 TAny *trueTypeExtension = NULL; 83 m_openFont->ExtendedInterface(KUidOpenFontTrueTypeExtension, trueTypeExtension); 84 m_trueTypeExtension = static_cast<MOpenFontTrueTypeExtension*>(trueTypeExtension); 85 Q_ASSERT(m_trueTypeExtension); 86 } 87 } 88 89 QSymbianTypeFaceExtras::~QSymbianTypeFaceExtras() 90 { 91 if (symbianFontTableApiAvailable()) 92 S60->screenDevice()->ReleaseFont(m_cFont); 66 93 } 67 94 68 95 QByteArray QSymbianTypeFaceExtras::getSfntTable(uint tag) const 69 96 { 70 Q_ASSERT(m_trueTypeExtension->HasTrueTypeTable(tag)); 71 TInt error = KErrNone; 72 TInt tableByteLength = 0; 73 TAny *table = q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength)); 74 QByteArray result(static_cast<const char*>(table), tableByteLength); 75 m_trueTypeExtension->ReleaseTrueTypeTable(table); 97 if (symbianFontTableApiAvailable()) { 98 QSymbianTGetFontTableParam fontTableParams = { tag, 0, 0 }; 99 if (m_cFont->ExtendedFunction(QSymbianKFontGetFontTable, &fontTableParams) == KErrNone) { 100 const char* const fontTableContent = 101 static_cast<const char *>(fontTableParams.iContent); 102 const QByteArray fontTable(fontTableContent, fontTableParams.iLength); 103 m_cFont->ExtendedFunction(QSymbianKFontReleaseFontTable, &fontTableParams); 104 return fontTable; 105 } 106 return QByteArray(); 107 } else { 108 Q_ASSERT(m_trueTypeExtension->HasTrueTypeTable(tag)); 109 TInt error = KErrNone; 110 TInt tableByteLength = 0; 111 TAny *table = q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength)); 112 const QByteArray result(static_cast<const char*>(table), tableByteLength); 113 m_trueTypeExtension->ReleaseTrueTypeTable(table); 114 return result; 115 } 116 } 117 118 bool QSymbianTypeFaceExtras::getSfntTableData(uint tag, uchar *buffer, uint *length) const 119 { 120 bool result = true; 121 if (symbianFontTableApiAvailable()) { 122 QSymbianTGetFontTableParam fontTableParams = { tag, 0, 0 }; 123 if (m_cFont->ExtendedFunction(QSymbianKFontGetFontTable, &fontTableParams) == KErrNone) { 124 if (*length > 0 && *length < fontTableParams.iLength) { 125 result = false; // Caller did not allocate enough memory 126 } else { 127 *length = fontTableParams.iLength; 128 if (buffer) 129 memcpy(buffer, fontTableParams.iContent, fontTableParams.iLength); 130 } 131 m_cFont->ExtendedFunction(QSymbianKFontReleaseFontTable, &fontTableParams); 132 } else { 133 result = false; 134 } 135 } else { 136 if (!m_trueTypeExtension->HasTrueTypeTable(tag)) 137 return false; 138 139 TInt error = KErrNone; 140 TInt tableByteLength; 141 TAny *table = 142 q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength)); 143 144 if (error != KErrNone) { 145 return false; 146 } else if (*length > 0 && *length < tableByteLength) { 147 result = false; // Caller did not allocate enough memory 148 } else { 149 *length = tableByteLength; 150 if (buffer) 151 memcpy(buffer, table, tableByteLength); 152 } 153 154 m_trueTypeExtension->ReleaseTrueTypeTable(table); 155 } 76 156 return result; 77 157 } 78 158 79 bool QSymbianTypeFaceExtras::getSfntTableData(uint tag, uchar *buffer, uint *length) const 80 { 81 if (!m_trueTypeExtension->HasTrueTypeTable(tag)) 82 return false; 83 84 bool result = true; 85 TInt error = KErrNone; 86 TInt tableByteLength; 87 TAny *table = 88 q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength)); 89 90 if (error != KErrNone) { 91 return false; 92 } else if (*length > 0 && *length < tableByteLength) { 93 result = false; // Caller did not allocate enough memory 159 const uchar *QSymbianTypeFaceExtras::cmap() const 160 { 161 if (m_cmapTable.isNull()) { 162 const QByteArray cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); 163 int size = 0; 164 const uchar *cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *> 165 (cmapTable.constData()), cmapTable.size(), &m_symbolCMap, &size); 166 m_cmapTable = QByteArray(reinterpret_cast<const char *>(cmap), size); 167 } 168 return reinterpret_cast<const uchar *>(m_cmapTable.constData()); 169 } 170 171 bool QSymbianTypeFaceExtras::isSymbolCMap() const 172 { 173 return m_symbolCMap; 174 } 175 176 CFont *QSymbianTypeFaceExtras::fontOwner() const 177 { 178 return m_cFont; 179 } 180 181 QFixed QSymbianTypeFaceExtras::unitsPerEm() const 182 { 183 if (m_unitsPerEm.value() != 0) 184 return m_unitsPerEm; 185 const QByteArray head = getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')); 186 const int unitsPerEmOffset = 18; 187 if (head.size() > unitsPerEmOffset + sizeof(quint16)) { 188 const uchar* tableData = reinterpret_cast<const uchar*>(head.constData()); 189 const uchar* unitsPerEm = tableData + unitsPerEmOffset; 190 m_unitsPerEm = qFromBigEndian<quint16>(unitsPerEm); 94 191 } else { 95 *length = tableByteLength; 96 if (buffer) 97 qMemCopy(buffer, table, tableByteLength); 98 } 99 100 m_trueTypeExtension->ReleaseTrueTypeTable(table); 101 return result; 102 } 103 104 const unsigned char *QSymbianTypeFaceExtras::cmap() const 105 { 106 if (!m_cmap) { 107 m_cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); 108 int size = 0; 109 m_cmap = QFontEngineS60::getCMap(reinterpret_cast<const uchar *>(m_cmapTable.constData()), m_cmapTable.size(), &m_symbolCMap, &size); 110 } 111 return m_cmap; 112 } 113 114 CFont *QSymbianTypeFaceExtras::fontOwner() const 115 { 116 return m_fontOwner; 117 } 118 192 // Bitmap font? Corrupt font? 193 // We return -1 and let the QFontEngineS60 return the pixel size. 194 m_unitsPerEm = -1; 195 } 196 return m_unitsPerEm; 197 } 198 199 bool QSymbianTypeFaceExtras::symbianFontTableApiAvailable() 200 { 201 enum FontTableApiAvailability { 202 Unknown, 203 Available, 204 Unavailable 205 }; 206 static FontTableApiAvailability availability = 207 QSysInfo::symbianVersion() < QSysInfo::SV_SF_3 ? 208 Unavailable : Unknown; 209 if (availability == Unknown) { 210 // Actually, we should ask CFeatureDiscovery::IsFeatureSupportedL() 211 // with FfFontTable here. But since at the time of writing, the 212 // FfFontTable flag check either gave false positives or false 213 // negatives. Here comes an implicit check via CFont::ExtendedFunction. 214 QSymbianTGetFontTableParam fontTableParams = { 215 MAKE_TAG('O', 'S', '/', '2'), 0, 0 }; 216 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); 217 CFont *font; 218 const TInt getFontErr = S60->screenDevice()->GetNearestFontInTwips(font, TFontSpec()); 219 Q_ASSERT(getFontErr == KErrNone); 220 if (font->ExtendedFunction(QSymbianKFontGetFontTable, &fontTableParams) == KErrNone) { 221 font->ExtendedFunction(QSymbianKFontReleaseFontTable, &fontTableParams); 222 availability = Available; 223 } else { 224 availability = Unavailable; 225 } 226 S60->screenDevice()->ReleaseFont(font); 227 lock.relock(); 228 } 229 return availability == Available; 230 } 119 231 120 232 // duplicated from qfontengine_xyz.cpp … … 132 244 } 133 245 246 extern QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName); // qfontdatabase_s60.cpp 247 134 248 CFont *QFontEngineS60::fontWithSize(qreal size) const 135 249 { 136 250 CFont *result = 0; 137 TFontSpec fontSpec(qt_QString2TPtrC(QFontEngine::fontDef.family), TInt(size)); 251 const QString family = qt_symbian_fontNameWithAppFontMarker(QFontEngine::fontDef.family); 252 TFontSpec fontSpec(qt_QString2TPtrC(family), TInt(size)); 138 253 fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap); 139 254 fontSpec.iFontStyle.SetPosture(QFontEngine::fontDef.style == QFont::StyleNormal?EPostureUpright:EPostureItalic); … … 190 305 } 191 306 307 QFixed QFontEngineS60::emSquareSize() const 308 { 309 const QFixed unitsPerEm = m_extras->unitsPerEm(); 310 return unitsPerEm.toInt() == -1 ? 311 QFixed::fromReal(m_originalFontSizeInPixels) : unitsPerEm; 312 } 313 192 314 bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const 193 315 { … … 203 325 const unsigned int uc = getChar(characters, i, len); 204 326 *g++ = QFontEngine::getTrueTypeGlyphIndex(cmap, 205 isRtl? QChar::mirroredChar(uc) : uc);327 (isRtl && !m_extras->isSymbolCMap()) ? QChar::mirroredChar(uc) : uc); 206 328 } 207 329 … … 219 341 { 220 342 Q_UNUSED(flags); 343 TOpenFontCharMetrics metrics; 344 const TUint8 *glyphBitmapBytes; 345 TSize glyphBitmapSize; 221 346 for (int i = 0; i < glyphs->numGlyphs; i++) { 222 const glyph_metrics_t bbox = boundingBox_const(glyphs->glyphs[i]); 223 glyphs->advances_x[i] = bbox.xoff; 224 glyphs->advances_y[i] = bbox.yoff; 225 } 347 getCharacterData(glyphs->glyphs[i], metrics, glyphBitmapBytes, glyphBitmapSize); 348 glyphs->advances_x[i] = metrics.HorizAdvance(); 349 glyphs->advances_y[i] = 0; 350 } 351 } 352 353 #ifdef Q_SYMBIAN_HAS_GLYPHOUTLINE_API 354 static bool parseGlyphPathData(const char *dataStr, const char *dataEnd, QPainterPath &path, 355 qreal fontPixelSize, const QPointF &offset, bool hinted); 356 #endif //Q_SYMBIAN_HAS_GLYPHOUTLINE_API 357 358 void QFontEngineS60::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, 359 int nglyphs, QPainterPath *path, 360 QTextItem::RenderFlags flags) 361 { 362 #ifdef Q_SYMBIAN_HAS_GLYPHOUTLINE_API 363 Q_UNUSED(flags) 364 RGlyphOutlineIterator iterator; 365 const TInt error = iterator.Open(*m_activeFont, glyphs, nglyphs); 366 if (KErrNone != error) 367 return; 368 const qreal fontSizeInPixels = qreal(m_activeFont->HeightInPixels()); 369 int count = 0; 370 do { 371 const TUint8* outlineUint8 = iterator.Outline(); 372 const char* const outlineChar = reinterpret_cast<const char*>(outlineUint8); 373 const char* const outlineEnd = outlineChar + iterator.OutlineLength(); 374 parseGlyphPathData(outlineChar, outlineEnd, *path, fontSizeInPixels, 375 positions[count++].toPointF(), false); 376 } while(KErrNone == iterator.Next() && count <= nglyphs); 377 iterator.Close(); 378 #else // Q_SYMBIAN_HAS_GLYPHOUTLINE_API 379 QFontEngine::addGlyphsToPath(glyphs, positions, nglyphs, path, flags); 380 #endif //Q_SYMBIAN_HAS_GLYPHOUTLINE_API 226 381 } 227 382 228 383 QImage QFontEngineS60::alphaMapForGlyph(glyph_t glyph) 229 384 { 385 // Note: On some Symbian versions (apparently <= Symbian^1), this 386 // function will return gray values 0x00, 0x10 ... 0xe0, 0xf0 due 387 // to a bug. The glyphs are nowhere perfectly opaque. 388 // This has been fixed for Symbian^3. 389 230 390 TOpenFontCharMetrics metrics; 231 391 const TUint8 *glyphBitmapBytes; … … 234 394 QImage result(glyphBitmapBytes, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight, glyphBitmapSize.iWidth, QImage::Format_Indexed8); 235 395 result.setColorTable(grayPalette()); 236 237 // The above setColorTable() call detached the image data anyway, so why not shape tha data a bit, while we can.238 // CFont::GetCharacterData() returns 8-bit data that obviously was 4-bit data before, and converted to 8-bit incorrectly.239 // The data values are 0x00, 0x10 ... 0xe0, 0xf0. So, a real opaque 0xff is never reached, which we get punished240 // for every time we want to blit this glyph in the raster paint engine.241 // "Fix" is to convert all 0xf0 to 0xff. Is fine, quality wise, and I assume faster than correcting all values.242 // Blitting is however, evidentially faster now.243 const int bpl = result.bytesPerLine();244 for (int row = 0; row < result.height(); ++row) {245 uchar *scanLine = result.scanLine(row);246 for (int column = 0; column < bpl; ++column) {247 if (*scanLine == 0xf0)248 *scanLine = 0xff;249 scanLine++;250 }251 }252 253 396 return result; 254 397 } … … 263 406 w += glyphs.effectiveAdvance(i); 264 407 265 return glyph_metrics_t(0, -ascent(), w , ascent()+descent()+1, w, 0);408 return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), ascent()+descent()+1, w, 0); 266 409 } 267 410 … … 272 415 TSize glyphBitmapSize; 273 416 getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize); 274 TRect glyphBounds;275 metrics.GetHorizBounds(glyphBounds);276 417 const glyph_metrics_t result( 277 glyphBounds.iTl.iX,278 glyphBounds.iTl.iY,279 glyphBounds.Width(),280 glyphBounds.Height(),418 metrics.HorizBearingX(), 419 -metrics.HorizBearingY(), 420 metrics.Width(), 421 metrics.Height(), 281 422 metrics.HorizAdvance(), 282 423 0 … … 292 433 QFixed QFontEngineS60::ascent() const 293 434 { 294 return m_originalFont->FontMaxAscent(); 435 // Workaround for QTBUG-8013 436 // Stroke based fonts may return an incorrect FontMaxAscent of 0. 437 const QFixed ascent = m_originalFont->FontMaxAscent(); 438 return (ascent > 0) ? ascent : QFixed::fromReal(m_originalFontSizeInPixels) - descent(); 295 439 } 296 440 … … 357 501 } 358 502 503 #ifdef Q_SYMBIAN_HAS_GLYPHOUTLINE_API 504 static inline void skipSpacesAndComma(const char* &str, const char* const strEnd) 505 { 506 while (str <= strEnd && (*str == ' ' || *str == ',')) 507 ++str; 508 } 509 510 static bool parseGlyphPathData(const char *svgPath, const char *svgPathEnd, QPainterPath &path, 511 qreal fontPixelSize, const QPointF &offset, bool hinted) 512 { 513 Q_UNUSED(hinted) 514 QPointF p1, p2, firstSubPathPoint; 515 qreal *elementValues[] = 516 {&p1.rx(), &p1.ry(), &p2.rx(), &p2.ry()}; 517 const int unitsPerEm = 2048; // See: http://en.wikipedia.org/wiki/Em_%28typography%29 518 const qreal resizeFactor = fontPixelSize / unitsPerEm; 519 520 while (svgPath < svgPathEnd) { 521 skipSpacesAndComma(svgPath, svgPathEnd); 522 const char pathElem = *svgPath++; 523 skipSpacesAndComma(svgPath, svgPathEnd); 524 525 if (pathElem != 'Z') { 526 char *endStr = 0; 527 int elementValuesCount = 0; 528 for (int i = 0; i < 4; ++i) { // 4 = size of elementValues[] 529 qreal coordinateValue = strtod(svgPath, &endStr); 530 if (svgPath == endStr) 531 break; 532 if (i % 2) // Flip vertically 533 coordinateValue = -coordinateValue; 534 *elementValues[i] = coordinateValue * resizeFactor; 535 elementValuesCount++; 536 svgPath = endStr; 537 skipSpacesAndComma(svgPath, svgPathEnd); 538 } 539 p1 += offset; 540 if (elementValuesCount == 2) 541 p2 = firstSubPathPoint; 542 else 543 p2 += offset; 544 } 545 546 switch (pathElem) { 547 case 'M': 548 firstSubPathPoint = p1; 549 path.moveTo(p1); 550 break; 551 case 'Z': 552 path.closeSubpath(); 553 break; 554 case 'L': 555 path.lineTo(p1); 556 break; 557 case 'Q': 558 path.quadTo(p1, p2); 559 break; 560 default: 561 return false; 562 } 563 } 564 return true; 565 } 566 #endif // Q_SYMBIAN_HAS_GLYPHOUTLINE_API 567 359 568 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.