source: trunk/src/gui/text/qfontengine_s60.cpp@ 753

Last change on this file since 753 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 11.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qfontengine_s60_p.h"
43#include "qtextengine_p.h"
44#include "qglobal.h"
45#include <private/qapplication_p.h>
46#include "qimage.h"
47#include "qt_s60_p.h"
48
49#include <e32base.h>
50#include <e32std.h>
51#include <eikenv.h>
52#include <gdi.h>
53
54QT_BEGIN_NAMESPACE
55
56QFontEngineS60Extensions::QFontEngineS60Extensions(CFont* fontOwner, COpenFont *font)
57 : m_font(font)
58 , m_cmap(0)
59 , m_symbolCMap(false)
60 , m_fontOwner(fontOwner)
61{
62 TAny *shapingExtension = NULL;
63 m_font->ExtendedInterface(KUidOpenFontShapingExtension, shapingExtension);
64 m_shapingExtension = static_cast<MOpenFontShapingExtension*>(shapingExtension);
65 TAny *trueTypeExtension = NULL;
66 m_font->ExtendedInterface(KUidOpenFontTrueTypeExtension, trueTypeExtension);
67 m_trueTypeExtension = static_cast<MOpenFontTrueTypeExtension*>(trueTypeExtension);
68 Q_ASSERT(m_shapingExtension && m_trueTypeExtension);
69}
70
71QByteArray QFontEngineS60Extensions::getSfntTable(uint tag) const
72{
73 Q_ASSERT(m_trueTypeExtension->HasTrueTypeTable(tag));
74 TInt error = KErrNone;
75 TInt tableByteLength = 0;
76 TAny *table = q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength));
77 QByteArray result(static_cast<const char*>(table), tableByteLength);
78 m_trueTypeExtension->ReleaseTrueTypeTable(table);
79 return result;
80}
81
82const unsigned char *QFontEngineS60Extensions::cmap() const
83{
84 if (!m_cmap) {
85 m_cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
86 int size = 0;
87 m_cmap = QFontEngineS60::getCMap(reinterpret_cast<const uchar *>(m_cmapTable.constData()), m_cmapTable.size(), &m_symbolCMap, &size);
88 }
89 return m_cmap;
90}
91
92QPainterPath QFontEngineS60Extensions::glyphOutline(glyph_t glyph) const
93{
94 QPainterPath result;
95 QPolygonF polygon;
96 TInt glyphIndex = glyph;
97 TInt pointNumber = 0;
98 TInt x, y;
99 while (m_shapingExtension->GlyphPointInFontUnits(glyphIndex, pointNumber++, x, y)) {
100 const QPointF point(qreal(x) / 0xffff, qreal(y) / 0xffff);
101 if (polygon.contains(point)) {
102 result.addPolygon(polygon);
103 result.closeSubpath();
104 polygon.clear();
105 } else {
106 polygon.append(point);
107 }
108 }
109 return result;
110}
111
112CFont *QFontEngineS60Extensions::fontOwner() const
113{
114 return m_fontOwner;
115}
116
117
118// duplicated from qfontengine_xyz.cpp
119static inline unsigned int getChar(const QChar *str, int &i, const int len)
120{
121 unsigned int uc = str[i].unicode();
122 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
123 uint low = str[i+1].unicode();
124 if (low >= 0xdc00 && low < 0xe000) {
125 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
126 ++i;
127 }
128 }
129 return uc;
130}
131
132CFont *QFontEngineS60::fontWithSize(qreal size) const
133{
134 CFont *result = 0;
135 TFontSpec fontSpec(qt_QString2TPtrC(QFontEngine::fontDef.family), TInt(size));
136 fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
137 fontSpec.iFontStyle.SetPosture(QFontEngine::fontDef.style == QFont::StyleNormal?EPostureUpright:EPostureItalic);
138 fontSpec.iFontStyle.SetStrokeWeight(QFontEngine::fontDef.weight > QFont::Normal?EStrokeWeightBold:EStrokeWeightNormal);
139 const TInt errorCode = S60->screenDevice()->GetNearestFontToDesignHeightInPixels(result, fontSpec);
140 Q_ASSERT(result && (errorCode == 0));
141 return result;
142}
143
144void QFontEngineS60::setFontScale(qreal scale)
145{
146 if (qFuzzyCompare(scale, qreal(1))) {
147 if (!m_originalFont)
148 m_originalFont = fontWithSize(m_originalFontSizeInPixels);
149 m_activeFont = m_originalFont;
150 } else {
151 const qreal scaledFontSizeInPixels = m_originalFontSizeInPixels * scale;
152 if (!m_scaledFont ||
153 (TInt(scaledFontSizeInPixels) != TInt(m_scaledFontSizeInPixels))) {
154 releaseFont(m_scaledFont);
155 m_scaledFontSizeInPixels = scaledFontSizeInPixels;
156 m_scaledFont = fontWithSize(m_scaledFontSizeInPixels);
157 }
158 m_activeFont = m_scaledFont;
159 }
160}
161
162void QFontEngineS60::releaseFont(CFont *&font)
163{
164 if (font) {
165 S60->screenDevice()->ReleaseFont(font);
166 font = 0;
167 }
168}
169
170QFontEngineS60::QFontEngineS60(const QFontDef &request, const QFontEngineS60Extensions *extensions)
171 : m_extensions(extensions)
172 , m_originalFont(0)
173 , m_originalFontSizeInPixels((request.pixelSize >= 0)?
174 request.pixelSize:pointsToPixels(request.pointSize))
175 , m_scaledFont(0)
176 , m_scaledFontSizeInPixels(0)
177 , m_activeFont(0)
178{
179 QFontEngine::fontDef = request;
180 setFontScale(1.0);
181 cache_cost = sizeof(QFontEngineS60);
182}
183
184QFontEngineS60::~QFontEngineS60()
185{
186 releaseFont(m_originalFont);
187 releaseFont(m_scaledFont);
188}
189
190bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
191{
192 if (*nglyphs < len) {
193 *nglyphs = len;
194 return false;
195 }
196
197 HB_Glyph *g = glyphs->glyphs;
198 const unsigned char* cmap = m_extensions->cmap();
199 for (int i = 0; i < len; ++i) {
200 const unsigned int uc = getChar(characters, i, len);
201 *g++ = QFontEngine::getTrueTypeGlyphIndex(cmap, uc);
202 }
203
204 glyphs->numGlyphs = g - glyphs->glyphs;
205 *nglyphs = glyphs->numGlyphs;
206
207 if (flags & QTextEngine::GlyphIndicesOnly)
208 return true;
209
210 recalcAdvances(glyphs, flags);
211 return true;
212}
213
214void QFontEngineS60::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
215{
216 Q_UNUSED(flags);
217 for (int i = 0; i < glyphs->numGlyphs; i++) {
218 const glyph_metrics_t bbox = boundingBox_const(glyphs->glyphs[i]);
219 glyphs->advances_x[i] = glyphs->offsets[i].x = bbox.xoff;
220 glyphs->advances_y[i] = glyphs->offsets[i].y = bbox.yoff;
221 }
222}
223
224QImage QFontEngineS60::alphaMapForGlyph(glyph_t glyph)
225{
226 TOpenFontCharMetrics metrics;
227 const TUint8 *glyphBitmapBytes;
228 TSize glyphBitmapSize;
229 getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize);
230 QImage result(glyphBitmapBytes, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight, glyphBitmapSize.iWidth, QImage::Format_Indexed8);
231 result.setColorTable(grayPalette());
232
233 // The above setColorTable() call detached the image data anyway, so why not shape tha data a bit, while we can.
234 // CFont::GetCharacterData() returns 8-bit data that obviously was 4-bit data before, and converted to 8-bit incorrectly.
235 // The data values are 0x00, 0x10 ... 0xe0, 0xf0. So, a real opaque 0xff is never reached, which we get punished
236 // for every time we want to blit this glyph in the raster paint engine.
237 // "Fix" is to convert all 0xf0 to 0xff. Is fine, quality wise, and I assume faster than correcting all values.
238 // Blitting is however, evidentially faster now.
239 const int bpl = result.bytesPerLine();
240 for (int row = 0; row < result.height(); ++row) {
241 uchar *scanLine = result.scanLine(row);
242 for (int column = 0; column < bpl; ++column) {
243 if (*scanLine == 0xf0)
244 *scanLine = 0xff;
245 scanLine++;
246 }
247 }
248
249 return result;
250}
251
252glyph_metrics_t QFontEngineS60::boundingBox(const QGlyphLayout &glyphs)
253{
254 if (glyphs.numGlyphs == 0)
255 return glyph_metrics_t();
256
257 QFixed w = 0;
258 for (int i = 0; i < glyphs.numGlyphs; ++i)
259 w += glyphs.effectiveAdvance(i);
260
261 return glyph_metrics_t(0, -ascent(), w, ascent()+descent()+1, w, 0);
262}
263
264glyph_metrics_t QFontEngineS60::boundingBox_const(glyph_t glyph) const
265{
266 TOpenFontCharMetrics metrics;
267 const TUint8 *glyphBitmapBytes;
268 TSize glyphBitmapSize;
269 getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize);
270 TRect glyphBounds;
271 metrics.GetHorizBounds(glyphBounds);
272 const glyph_metrics_t result(
273 glyphBounds.iTl.iX,
274 glyphBounds.iTl.iY,
275 glyphBounds.Width(),
276 glyphBounds.Height(),
277 metrics.HorizAdvance(),
278 0
279 );
280 return result;
281}
282
283glyph_metrics_t QFontEngineS60::boundingBox(glyph_t glyph)
284{
285 return boundingBox_const(glyph);
286}
287
288QFixed QFontEngineS60::ascent() const
289{
290 return m_originalFont->FontMaxAscent();
291}
292
293QFixed QFontEngineS60::descent() const
294{
295 return m_originalFont->FontMaxDescent();
296}
297
298QFixed QFontEngineS60::leading() const
299{
300 return 0;
301}
302
303qreal QFontEngineS60::maxCharWidth() const
304{
305 return m_originalFont->MaxCharWidthInPixels();
306}
307
308const char *QFontEngineS60::name() const
309{
310 return "QFontEngineS60";
311}
312
313bool QFontEngineS60::canRender(const QChar *string, int len)
314{
315 const unsigned char *cmap = m_extensions->cmap();
316 for (int i = 0; i < len; ++i) {
317 const unsigned int uc = getChar(string, i, len);
318 if (QFontEngine::getTrueTypeGlyphIndex(cmap, uc) == 0)
319 return false;
320 }
321 return true;
322}
323
324QByteArray QFontEngineS60::getSfntTable(uint tag) const
325{
326 return m_extensions->getSfntTable(tag);
327}
328
329QFontEngine::Type QFontEngineS60::type() const
330{
331 return QFontEngine::S60FontEngine;
332}
333
334void QFontEngineS60::getCharacterData(glyph_t glyph, TOpenFontCharMetrics& metrics, const TUint8*& bitmap, TSize& bitmapSize) const
335{
336 // Setting the most significant bit tells GetCharacterData
337 // that 'code' is a Glyph ID, rather than a UTF-16 value
338 const TUint specialCode = (TUint)glyph | 0x80000000;
339
340 const CFont::TCharacterDataAvailability availability =
341 m_activeFont->GetCharacterData(specialCode, metrics, bitmap, bitmapSize);
342 const glyph_t fallbackGlyph = '?';
343 if (availability != CFont::EAllCharacterData) {
344 const CFont::TCharacterDataAvailability fallbackAvailability =
345 m_activeFont->GetCharacterData(fallbackGlyph, metrics, bitmap, bitmapSize);
346 Q_ASSERT(fallbackAvailability == CFont::EAllCharacterData);
347 }
348}
349
350QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.