First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
18 #include <graphics/gdi/gdistructs.h>
19 #include <graphics/gdi/gdiconsts.h>
20 #include <graphics/fbsglyphdataiterator.h>
21 #include "FbsMessage.h"
24 const TInt KFbsGlyphDataIterCodeInvalid = -1;
26 extern void Panic(TFbsPanic aPanic);
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.
33 EXPORT_C RFbsGlyphDataIterator::RFbsGlyphDataIterator() :
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.
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).
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().
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().
53 @pre The iterator is not already open.
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.
62 KErrNone, if the iterator is successfully initialised to retrieve
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
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
72 KErrArgument, if aCount is negative or zero, or if aGlyphCodes is null.
74 EXPORT_C TInt RFbsGlyphDataIterator::Open(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount)
80 if ((aCount <= 0) || !aGlyphCodes)
84 if (!aFont.Address()->IsOpenFont())
86 return KErrNotSupported;
88 TInt glyphBitmapType = aFont.Address()->GlyphBitmapType();
89 if (!( (glyphBitmapType == EMonochromeGlyphBitmap) || (glyphBitmapType == EAntiAliasedGlyphBitmap) ))
91 //Only supported bitmap types can be used i.e. EMonochromeGlyphBitmap or EAntiAliasedGlyphBitmap
92 return KErrNotSupported;
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) )
104 // Construct implementor object that holds the state for the iterator.
105 iImpl = new CGlyphDataIteratorImpl(aFont.iHandle, aGlyphCodes, aCount);
110 TInt err = iImpl->Initialise();
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.
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.
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.
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.
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.
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.
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.
151 EXPORT_C TInt RFbsGlyphDataIterator::Next()
153 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
154 return iImpl->Next();
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.
162 Once an iterator is closed, the array of glyphs (aGlyphCodes) passed to
163 RFbsGlyphDataIterator::Open() can safely be deleted.
165 @post The iterator is closed.
167 EXPORT_C void RFbsGlyphDataIterator::Close()
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).
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
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.
187 @pre The iterator has been initialised by successfully calling Open().
189 @return A handle to the image where the glyph for this iteration is stored.
191 @panic FBSCLI 31, if the iterator is not open.
193 EXPORT_C const RSgImage& RFbsGlyphDataIterator::Image() const
195 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
196 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
197 return iImpl->iGlyphBatch.First()->iImage;
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.
206 @pre The iterator has been initialised by successfully calling Open().
208 @return A rectangle representing the position and size in pixels,
209 of the glyph for this iteration on the RSgImage provided by Image().
211 @panic FBSCLI 31, if the iterator is not open.
213 EXPORT_C const TRect& RFbsGlyphDataIterator::Rect() const
215 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
216 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
217 return iImpl->iGlyphDataIterRect;
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.
225 @pre The iterator has been initialised by successfully calling Open().
227 @return The metrics for the glyph at the current iteration.
229 @panic FBSCLI 31, if the iterator is not open.
231 EXPORT_C const TOpenFontCharMetrics& RFbsGlyphDataIterator::Metrics() const
233 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
234 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
235 return iImpl->iGlyphBatch.First()->iInfo.iMetrics;
239 Returns the glyph code associated with the data for the current iteration.
241 @pre The iterator has been initialised by successfully calling Open().
243 @return The glyph code of the glyph at the current iteration.
245 @panic FBSCLI 31, if the iterator is not open.
247 EXPORT_C TUint RFbsGlyphDataIterator::GlyphCode() const
249 __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
250 __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
251 return iImpl->iGlyphDataIterCodes[iImpl->iGlyphDataIterCodeIndex];
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.
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)
271 Destructor. Releases all resources, disconnects from server and frees any
272 items in the list of batched items.
274 CGlyphDataIteratorImpl::~CGlyphDataIteratorImpl()
278 if (iGlyphDataIterCodeIndex != KFbsGlyphDataIterCodeInvalid)
280 //Send the No-Op command to ensure that the "In Transit" RSgImage(s) are closed.
281 iFbs->SendCommand(EFbsMessNoOp);
283 RFbsSession::Disconnect();
286 while (!iGlyphBatch.IsEmpty())
288 TGlyphBatchItem* item = iGlyphBatch.First();
289 item->iImage.Close();
290 iGlyphBatch.Remove(*item);
297 Sets up the CGlyphDataIteratorImpl, populating the first batch of glyphs.
298 Should only be called once, immediately after construction.
300 TInt CGlyphDataIteratorImpl::Initialise()
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));
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();
311 iFbs = RFbsSession::GetSession();
312 err = UpdateGlyphBatch(0);
316 iGlyphDataIterCodeIndex = 0;
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
326 @see RFbsGlyphDataIterator::Next()
328 TInt CGlyphDataIteratorImpl::Next()
330 __ASSERT_DEBUG(!iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
331 if ( (iGlyphDataIterCodeIndex + 1) >= iGlyphDataIterCodeCount)
335 TInt err = UpdateGlyphBatch(iGlyphDataIterCodeIndex + 1);
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);
344 __ASSERT_DEBUG(!iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
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.
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
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.
364 TInt CGlyphDataIteratorImpl::UpdateGlyphBatch(TInt aIndex)
366 __ASSERT_DEBUG(Rng(0, aIndex, iGlyphDataIterCodeCount - 1), Panic(EFbsPanicGlyphDataIteratorIndexOutOfRange));
370 TBool needMoreGlyphs = EFalse;
371 if (iGlyphBatch.IsEmpty())
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;
378 else if (iGlyphBatch.IsLast(iGlyphBatch.First()))
380 // Only one item in the list.
381 needMoreGlyphs = ETrue;
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.
390 TBool glyphAddedToBatch = EFalse;
391 TUint glyphCodes[KMaxGlyphBatchSize];
393 TInt numGlyphsToRequest = Min(iGlyphDataIterCodeCount - aIndex, KMaxGlyphBatchSize);
394 (void)Mem::Copy(glyphCodes, &(iGlyphDataIterCodes[aIndex]), sizeof(TUint) * numGlyphsToRequest);
395 TPckg<TUint[KMaxGlyphBatchSize]> argGlyphCodes(glyphCodes);
397 TGlyphImageInfo rcvdGlyphInfo[KMaxGlyphBatchSize];
398 TPckg<TGlyphImageInfo[KMaxGlyphBatchSize]> argGlyphInfo(rcvdGlyphInfo);
400 if (numGlyphsToRequest < KMaxGlyphBatchSize)
402 argGlyphCodes.SetLength(numGlyphsToRequest * sizeof(TUint));
403 argGlyphInfo.SetLength(numGlyphsToRequest * sizeof(TGlyphImageInfo));
406 err = iFbs->SendCommand(EFbsMessGetGlyphs, TIpcArgs(iFbsFontHandle, &argGlyphCodes, &argGlyphInfo));
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));
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)
420 TGlyphBatchItem* glyphEntry = new TGlyphBatchItem;
427 glyphEntry->iInfo = rcvdGlyphInfo[i];
430 if (rcvdGlyphInfo[i].iImageId != KSgNullDrawableId)
432 err = glyphEntry->iImage.Open(rcvdGlyphInfo[i].iImageId);
436 iGlyphBatch.AddLast(*glyphEntry);
437 glyphAddedToBatch = ETrue;
446 if (err != KErrNone && glyphAddedToBatch)
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.
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.
461 void CGlyphDataIteratorImpl::UpdateGlyphRect()
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()));