os/graphics/fbs/fontandbitmapserver/sfbs/fbsglyphdataiterator.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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     }