fbs/fontandbitmapserver/sfbs/fbsglyphdataiterator.cpp
branchRCL_3
changeset 163 bbf46f59e123
equal deleted inserted replaced
150:57c618273d5c 163:bbf46f59e123
       
     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     }