|
1 // Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <e32def.h> |
|
17 #include <gdi.h> |
|
18 #include <graphics/gdi/gdistructs.h> |
|
19 #include <graphics/gdi/gdiconsts.h> |
|
20 #include <graphics/fbsglyphdataiterator.h> |
|
21 #include "FbsMessage.h" |
|
22 #include "UTILS.H" |
|
23 |
|
24 const TInt KFbsGlyphDataIterCodeInvalid = -1; |
|
25 |
|
26 extern void Panic(TFbsPanic aPanic); |
|
27 |
|
28 /** |
|
29 The default constructor sets the iterator to a closed and empty state. It |
|
30 is the only way of constructing an iterator as instances cannot be copied by |
|
31 assignment or passed by value. |
|
32 */ |
|
33 EXPORT_C RFbsGlyphDataIterator::RFbsGlyphDataIterator() : |
|
34 iImpl(NULL) |
|
35 { |
|
36 } |
|
37 |
|
38 /** |
|
39 For a given font (aFont), this method retrieves the glyph data for a list of |
|
40 glyph codes (aGlyphCodes), containing a number (aCount) of codes. On success, |
|
41 the iterator is initialised with the data for the first glyph in aGlyphCodes. |
|
42 |
|
43 The memory allocated to aGlyphCodes must not be freed or altered while the |
|
44 iterator is in use (i.e. until the iterator has been closed). |
|
45 |
|
46 Open() may not be called on an already open iterator. In order to re-open an |
|
47 iterator, it must first be closed by a call tor Close(). |
|
48 |
|
49 If a glyph code is passed in that is not a recognised glyph code for the |
|
50 associated font, an empty-box glyph will be returned. This behaviour is |
|
51 consistent with CFbsFont::GetCharacterData(). |
|
52 |
|
53 @pre The iterator is not already open. |
|
54 |
|
55 @param aFont The font to provide the glyph code data for. |
|
56 @param aGlyphCodes An array of glyph codes that the iterator will |
|
57 provide data for. This memory allocated for this array must not be |
|
58 freed before the iterator is closed. |
|
59 @param aCount The number of glyph codes in aGlyphCodes. |
|
60 |
|
61 @return |
|
62 KErrNone, if the iterator is successfully initialised to retrieve |
|
63 the glyph data; |
|
64 KErrInUse, if the iterator is already open, in which case the state of |
|
65 the iterator is left unchanged; |
|
66 KErrNoMemory, if the iterator cannot be opened due to insufficient |
|
67 system memory; |
|
68 KErrNotSupported, if aFont refers to a bitmap font or an outline & shadow |
|
69 font, if the required version of the hardware driver is not available |
|
70 (EGL 1.3 or later is required), or if RSgImages are not supported by |
|
71 the system; |
|
72 KErrArgument, if aCount is negative or zero, or if aGlyphCodes is null. |
|
73 */ |
|
74 EXPORT_C TInt RFbsGlyphDataIterator::Open(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount) |
|
75 { |
|
76 if (iImpl) |
|
77 { |
|
78 return KErrInUse; |
|
79 } |
|
80 if ((aCount <= 0) || !aGlyphCodes) |
|
81 { |
|
82 return KErrArgument; |
|
83 } |
|
84 if (!aFont.Address()->IsOpenFont()) |
|
85 { |
|
86 return KErrNotSupported; |
|
87 } |
|
88 TInt glyphBitmapType = aFont.Address()->GlyphBitmapType(); |
|
89 if (!( (glyphBitmapType == EMonochromeGlyphBitmap) || (glyphBitmapType == EAntiAliasedGlyphBitmap) )) |
|
90 { |
|
91 //Only supported bitmap types can be used i.e. EMonochromeGlyphBitmap or EAntiAliasedGlyphBitmap |
|
92 return KErrNotSupported; |
|
93 } |
|
94 // Check that the max width and height of the font are both no more than 2048. |
|
95 // This is the smallest maximum size an RSgImage can be created with. |
|
96 // This limit is arbitrarily set as it should cover nearly all use cases. |
|
97 const TInt KMaxFontSizeInPixels = 2048; |
|
98 TInt maxHeight = aFont.FontMaxHeight(); |
|
99 TInt maxWidth = aFont.MaxCharWidthInPixels(); |
|
100 if ( (KMaxFontSizeInPixels < maxHeight) || (KMaxFontSizeInPixels < maxWidth) ) |
|
101 { |
|
102 return KErrTooBig; |
|
103 } |
|
104 // Construct implementor object that holds the state for the iterator. |
|
105 iImpl = new CGlyphDataIteratorImpl(aFont.iHandle, aGlyphCodes, aCount); |
|
106 if (!iImpl) |
|
107 { |
|
108 return KErrNoMemory; |
|
109 } |
|
110 TInt err = iImpl->Initialise(); |
|
111 if (err != KErrNone) |
|
112 { |
|
113 Close(); |
|
114 } |
|
115 return err; |
|
116 } |
|
117 |
|
118 /** |
|
119 Moves the iterator to the data for the next glyph code in the array passed |
|
120 into RFbsGlyphDataIterator::Open(). Data for the glyph can then be accessed |
|
121 using the Image(), Rect() and Metrics() methods. |
|
122 |
|
123 Once Next() has been called, the references returned by Image(), Rect() and |
|
124 Metrics() methods during the previous iteration should be considered invalid |
|
125 and must be discarded. |
|
126 |
|
127 Calling Next() repeatedly will iterate through the glyph data for all the glyph |
|
128 codes, until it has reached the last glyph code in the array (assuming no errors |
|
129 are encountered), at which point KErrNotFound is returned, and the array of glyph |
|
130 codes passed to RFbsGlyphDataIterator::Open() can safely be deleted. |
|
131 |
|
132 If the call was successful, KErrNone is returned. If an error is encountered an |
|
133 error code will be returned and the state of the iterator is left unchanged. |
|
134 |
|
135 @pre The iterator has been opened by a successful call to Open(). |
|
136 @post The properties of the iterator are of the glyph corresponding |
|
137 to the next code passed in the array to Open(). However, if an error code |
|
138 was returned, the state of the iterator is unchanged. |
|
139 |
|
140 @return |
|
141 KErrNone, if the iterator was successfully advanced; |
|
142 KErrNotFound, if the iterator is already at the last element and cannot |
|
143 be advanced any further; |
|
144 KErrNoMemory, if there is insufficient system memory available; |
|
145 KErrNoGraphicsMemory, if there is insufficient graphics memory available. |
|
146 |
|
147 @panic FBSCLI 31, if the iterator is not open. |
|
148 @panic FBSERV -8, if as a result of this call, communication with the |
|
149 server is invoked, and the associated CFbsFont has been destroyed. |
|
150 */ |
|
151 EXPORT_C TInt RFbsGlyphDataIterator::Next() |
|
152 { |
|
153 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed)); |
|
154 return iImpl->Next(); |
|
155 } |
|
156 |
|
157 /** |
|
158 Closes the iterator and releases its internal resources. After calling, all data |
|
159 retrieved by the iterator is no longer safe to use. Once closed, this iterator |
|
160 can be re-opened. Calling Close() on an already closed iterator has no effect. |
|
161 |
|
162 Once an iterator is closed, the array of glyphs (aGlyphCodes) passed to |
|
163 RFbsGlyphDataIterator::Open() can safely be deleted. |
|
164 |
|
165 @post The iterator is closed. |
|
166 */ |
|
167 EXPORT_C void RFbsGlyphDataIterator::Close() |
|
168 { |
|
169 delete iImpl; |
|
170 iImpl = NULL; |
|
171 } |
|
172 |
|
173 /** |
|
174 Returns a reference to the RSgImage that contains the glyph for the current |
|
175 iteration. The image representation of the glyph is the same as the image |
|
176 returned by the existing CFbsFont::GetCharacterData() method (i.e. an alpha mask). |
|
177 |
|
178 The RSgImage should only be considered a temporary handle for use in this |
|
179 iteration, and should not be used after a call to Next() or Close() has |
|
180 been made. |
|
181 |
|
182 Note: For glyphs such as space which have no visible representation, Image() |
|
183 will return a null image handle (i.e. RSgImage::IsNull() returns ETrue). This |
|
184 cannot be used for drawing. In this case Rect() will be empty however |
|
185 Metrics() will still be valid. |
|
186 |
|
187 @pre The iterator has been initialised by successfully calling Open(). |
|
188 |
|
189 @return A handle to the image where the glyph for this iteration is stored. |
|
190 |
|
191 @panic FBSCLI 31, if the iterator is not open. |
|
192 */ |
|
193 EXPORT_C const RSgImage& RFbsGlyphDataIterator::Image() const |
|
194 { |
|
195 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed)); |
|
196 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
197 return iImpl->iGlyphBatch.First()->iImage; |
|
198 } |
|
199 |
|
200 /** |
|
201 Returns the area within the RSgImage where the glyph for the current |
|
202 iteration is located. The reference returned by Rect() should be considered |
|
203 temporary for use within this iteration and should not be used after a call to |
|
204 Next() or Close() has been made. |
|
205 |
|
206 @pre The iterator has been initialised by successfully calling Open(). |
|
207 |
|
208 @return A rectangle representing the position and size in pixels, |
|
209 of the glyph for this iteration on the RSgImage provided by Image(). |
|
210 |
|
211 @panic FBSCLI 31, if the iterator is not open. |
|
212 */ |
|
213 EXPORT_C const TRect& RFbsGlyphDataIterator::Rect() const |
|
214 { |
|
215 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed)); |
|
216 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
217 return iImpl->iGlyphDataIterRect; |
|
218 } |
|
219 |
|
220 /** |
|
221 Returns the glyph metrics for the current iteration. The reference returned by |
|
222 Metrics() should be considered temporary for use within this iteration and |
|
223 should not be used after a call to Next() or Close() has been made. |
|
224 |
|
225 @pre The iterator has been initialised by successfully calling Open(). |
|
226 |
|
227 @return The metrics for the glyph at the current iteration. |
|
228 |
|
229 @panic FBSCLI 31, if the iterator is not open. |
|
230 */ |
|
231 EXPORT_C const TOpenFontCharMetrics& RFbsGlyphDataIterator::Metrics() const |
|
232 { |
|
233 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed)); |
|
234 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
235 return iImpl->iGlyphBatch.First()->iInfo.iMetrics; |
|
236 } |
|
237 |
|
238 /** |
|
239 Returns the glyph code associated with the data for the current iteration. |
|
240 |
|
241 @pre The iterator has been initialised by successfully calling Open(). |
|
242 |
|
243 @return The glyph code of the glyph at the current iteration. |
|
244 |
|
245 @panic FBSCLI 31, if the iterator is not open. |
|
246 */ |
|
247 EXPORT_C TUint RFbsGlyphDataIterator::GlyphCode() const |
|
248 { |
|
249 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed)); |
|
250 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
251 return iImpl->iGlyphDataIterCodes[iImpl->iGlyphDataIterCodeIndex]; |
|
252 } |
|
253 |
|
254 |
|
255 /** |
|
256 Constructs a CGlyphDataIteratorImpl. |
|
257 @param aFbsFontHandle The handle of the FbsFont that the iterator is working with. |
|
258 @param aGlyphCodes The array of glyph codes sent to RFbsGlyphDataIterator::Open() |
|
259 @param aCount The number of glyph codes in aGlyphCodes. |
|
260 */ |
|
261 CGlyphDataIteratorImpl::CGlyphDataIteratorImpl(TInt aFbsFontHandle, const TUint* aGlyphCodes, TInt aCount) : |
|
262 iGlyphBatch(_FOFF(TGlyphBatchItem, iLink)), |
|
263 iGlyphDataIterCodes(aGlyphCodes), |
|
264 iGlyphDataIterCodeCount(aCount), |
|
265 iGlyphDataIterCodeIndex(KFbsGlyphDataIterCodeInvalid), |
|
266 iFbsFontHandle(aFbsFontHandle) |
|
267 { |
|
268 } |
|
269 |
|
270 /** |
|
271 Destructor. Releases all resources, disconnects from server and frees any |
|
272 items in the list of batched items. |
|
273 */ |
|
274 CGlyphDataIteratorImpl::~CGlyphDataIteratorImpl() |
|
275 { |
|
276 if (iFbs) |
|
277 { |
|
278 if (iGlyphDataIterCodeIndex != KFbsGlyphDataIterCodeInvalid) |
|
279 { |
|
280 //Send the No-Op command to ensure that the "In Transit" RSgImage(s) are closed. |
|
281 iFbs->SendCommand(EFbsMessNoOp); |
|
282 } |
|
283 RFbsSession::Disconnect(); |
|
284 iFbs = NULL; |
|
285 } |
|
286 while (!iGlyphBatch.IsEmpty()) |
|
287 { |
|
288 TGlyphBatchItem* item = iGlyphBatch.First(); |
|
289 item->iImage.Close(); |
|
290 iGlyphBatch.Remove(*item); |
|
291 delete item; |
|
292 } |
|
293 iGlyphBatch.Reset(); |
|
294 } |
|
295 |
|
296 /** |
|
297 Sets up the CGlyphDataIteratorImpl, populating the first batch of glyphs. |
|
298 Should only be called once, immediately after construction. |
|
299 */ |
|
300 TInt CGlyphDataIteratorImpl::Initialise() |
|
301 { |
|
302 __ASSERT_DEBUG(iFbsFontHandle, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
303 __ASSERT_DEBUG(iGlyphDataIterCodes, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
304 __ASSERT_DEBUG(iGlyphDataIterCodeCount, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
305 __ASSERT_DEBUG(iGlyphDataIterCodeIndex == KFbsGlyphDataIterCodeInvalid, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
306 |
|
307 // If the client already has a session open, this is just a reference counting exercise and should incur no performance impact. |
|
308 TInt err = RFbsSession::Connect(); |
|
309 if (err == KErrNone) |
|
310 { |
|
311 iFbs = RFbsSession::GetSession(); |
|
312 err = UpdateGlyphBatch(0); |
|
313 } |
|
314 if (err == KErrNone) |
|
315 { |
|
316 iGlyphDataIterCodeIndex = 0; |
|
317 UpdateGlyphRect(); |
|
318 } |
|
319 return err; |
|
320 } |
|
321 |
|
322 /** |
|
323 Increments the current iteration if possible, re-sending the request |
|
324 for more glyphs if the current batch of glyphs is down to the last |
|
325 item. |
|
326 @see RFbsGlyphDataIterator::Next() |
|
327 */ |
|
328 TInt CGlyphDataIteratorImpl::Next() |
|
329 { |
|
330 __ASSERT_DEBUG(!iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
331 if ( (iGlyphDataIterCodeIndex + 1) >= iGlyphDataIterCodeCount) |
|
332 { |
|
333 return KErrNotFound; |
|
334 } |
|
335 TInt err = UpdateGlyphBatch(iGlyphDataIterCodeIndex + 1); |
|
336 if (err == KErrNone) |
|
337 { |
|
338 ++iGlyphDataIterCodeIndex; |
|
339 // Close the current image and pop the head of the batch. |
|
340 TGlyphBatchItem* item = iGlyphBatch.First(); |
|
341 item->iImage.Close(); |
|
342 iGlyphBatch.Remove(*item); |
|
343 delete item; |
|
344 __ASSERT_DEBUG(!iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
345 UpdateGlyphRect(); |
|
346 } |
|
347 return err; |
|
348 } |
|
349 |
|
350 /** |
|
351 Checks whether a call to the server is required to get a new batch of glyph |
|
352 info, and processes the response from the server as necessary. |
|
353 |
|
354 @param aIndex Specifies the index into the glyph array which needs to be in |
|
355 the active glyph batch. If it is not there, a request is made to the server |
|
356 to get it. |
|
357 @return KErrNone if getting at least one glyph succeeded or a call to the |
|
358 server was not necessary, otherwise one of the system wide error codes. |
|
359 @panic FBSCLI 31 (debug only), if the iterator is not open |
|
360 @panic FBSCLI 33 (debug only), if an unexpected number of glyphs was received |
|
361 as a result of requesting glyphs from the server, or if the current batch |
|
362 of glyphs is empty when there should be at least one item. |
|
363 */ |
|
364 TInt CGlyphDataIteratorImpl::UpdateGlyphBatch(TInt aIndex) |
|
365 { |
|
366 __ASSERT_DEBUG(Rng(0, aIndex, iGlyphDataIterCodeCount - 1), Panic(EFbsPanicGlyphDataIteratorIndexOutOfRange)); |
|
367 |
|
368 TInt err = KErrNone; |
|
369 |
|
370 TBool needMoreGlyphs = EFalse; |
|
371 if (iGlyphBatch.IsEmpty()) |
|
372 { |
|
373 // Current batch is empty, must request more. Should only get here when the iterator |
|
374 // is first opened, since one item should always be in the list from then on. |
|
375 __ASSERT_DEBUG(aIndex == 0, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
376 needMoreGlyphs = ETrue; |
|
377 } |
|
378 else if (iGlyphBatch.IsLast(iGlyphBatch.First())) |
|
379 { |
|
380 // Only one item in the list. |
|
381 needMoreGlyphs = ETrue; |
|
382 } |
|
383 |
|
384 if (needMoreGlyphs) |
|
385 { |
|
386 // If the array of batched images is empty OR only one left, means we need to request a new batch. |
|
387 // We make sure there is at least one glyph in the batch so the iterator is always usable even |
|
388 // when a failure to move to the next iteration occurs. |
|
389 |
|
390 TBool glyphAddedToBatch = EFalse; |
|
391 TUint glyphCodes[KMaxGlyphBatchSize]; |
|
392 |
|
393 TInt numGlyphsToRequest = Min(iGlyphDataIterCodeCount - aIndex, KMaxGlyphBatchSize); |
|
394 (void)Mem::Copy(glyphCodes, &(iGlyphDataIterCodes[aIndex]), sizeof(TUint) * numGlyphsToRequest); |
|
395 TPckg<TUint[KMaxGlyphBatchSize]> argGlyphCodes(glyphCodes); |
|
396 |
|
397 TGlyphImageInfo rcvdGlyphInfo[KMaxGlyphBatchSize]; |
|
398 TPckg<TGlyphImageInfo[KMaxGlyphBatchSize]> argGlyphInfo(rcvdGlyphInfo); |
|
399 |
|
400 if (numGlyphsToRequest < KMaxGlyphBatchSize) |
|
401 { |
|
402 argGlyphCodes.SetLength(numGlyphsToRequest * sizeof(TUint)); |
|
403 argGlyphInfo.SetLength(numGlyphsToRequest * sizeof(TGlyphImageInfo)); |
|
404 } |
|
405 |
|
406 err = iFbs->SendCommand(EFbsMessGetGlyphs, TIpcArgs(iFbsFontHandle, &argGlyphCodes, &argGlyphInfo)); |
|
407 if (err == KErrNone) |
|
408 { |
|
409 __ASSERT_DEBUG(argGlyphInfo.Length() % sizeof(TGlyphImageInfo) == 0, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
410 TInt numRcvdGlyphs = argGlyphInfo.Length() / sizeof(TGlyphImageInfo); |
|
411 __ASSERT_DEBUG(numRcvdGlyphs > 0, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
412 __ASSERT_DEBUG(numRcvdGlyphs <= KMaxGlyphBatchSize, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
413 |
|
414 // Store the received glyph data, and open the image handles so that the IDs |
|
415 // will not be released by FbServ between now and the client using them. |
|
416 // If a failure occurs while processing one of the recevied glyphs, |
|
417 // abort the rest but keep the ones that succeeded. |
|
418 for (TInt i = 0; (i < numRcvdGlyphs) && (err == KErrNone); ++i) |
|
419 { |
|
420 TGlyphBatchItem* glyphEntry = new TGlyphBatchItem; |
|
421 if (!glyphEntry) |
|
422 { |
|
423 err = KErrNoMemory; |
|
424 } |
|
425 else |
|
426 { |
|
427 glyphEntry->iInfo = rcvdGlyphInfo[i]; |
|
428 |
|
429 RSgImage glyphImage; |
|
430 if (rcvdGlyphInfo[i].iImageId != KSgNullDrawableId) |
|
431 { |
|
432 err = glyphEntry->iImage.Open(rcvdGlyphInfo[i].iImageId); |
|
433 } |
|
434 if (err == KErrNone) |
|
435 { |
|
436 iGlyphBatch.AddLast(*glyphEntry); |
|
437 glyphAddedToBatch = ETrue; |
|
438 } |
|
439 else |
|
440 { |
|
441 delete glyphEntry; |
|
442 } |
|
443 } |
|
444 } |
|
445 } |
|
446 if (err != KErrNone && glyphAddedToBatch) |
|
447 { |
|
448 // There was an error adding an item to the batch. Rather than return the |
|
449 // error to the client, ignore it and use what glyphs we successfully batched. |
|
450 err = KErrNone; |
|
451 } |
|
452 } |
|
453 return err; |
|
454 } |
|
455 |
|
456 /** |
|
457 Updates the glyph rectangle member based on the current glyph metrics. |
|
458 @post The iGlyphDataIterRect member is updated to reflect the position |
|
459 and size of the currently active glyph. |
|
460 */ |
|
461 void CGlyphDataIteratorImpl::UpdateGlyphRect() |
|
462 { |
|
463 iGlyphDataIterRect.iTl = TPoint(iGlyphBatch.First()->iInfo.iPosX, iGlyphBatch.First()->iInfo.iPosY); |
|
464 iGlyphDataIterRect.SetSize(TSize(iGlyphBatch.First()->iInfo.iMetrics.Width(), iGlyphBatch.First()->iInfo.iMetrics.Height())); |
|
465 } |