fbs/fontandbitmapserver/sfbs/fbsglyphmetricsarray.cpp
changeset 187 9f66f99ee56f
equal deleted inserted replaced
103:2717213c588a 187:9f66f99ee56f
       
     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 
       
    17 #include <e32def.h>
       
    18 #include <gdi.h>
       
    19 #include <graphics/gdi/gdistructs.h>
       
    20 #include <graphics/gdi/gdiconsts.h>
       
    21 #include <graphics/fbsglyphmetricsarray.h>
       
    22 #include "UTILS.H"
       
    23 #include "FbsMessage.h"
       
    24 
       
    25 // 'most significant bit' flag to ensure value is interpreted as a glyph code rather than an ascii code
       
    26 const TUint KGlyphCodeFlag = 0x80000000;      
       
    27 
       
    28 extern void Panic(TFbsPanic aPanic);
       
    29 
       
    30 /** Helper function for converting an offset (that was calculated using
       
    31 PointerToOffset()) back to a pointer relative to the passed heap base.
       
    32 @param aOffset The offset to be converted to a pointer.
       
    33 @param aHeapBase A pointer to the heap base of the current process.
       
    34 @return A pointer relative to the passed heap base.
       
    35 */
       
    36 static TAny* OffsetToPointer(const TInt aOffset, TUint8* aHeapBase)
       
    37     {
       
    38     if ( (aOffset != 0) && (aHeapBase != NULL) )
       
    39         {
       
    40         return (TAny*)(aOffset + aHeapBase);
       
    41         }
       
    42     return NULL;
       
    43     }
       
    44 
       
    45 /**
       
    46 Constructs an empty RFbsGlyphMetricsArray instance. This will not allocate any memory.
       
    47  */
       
    48 EXPORT_C RFbsGlyphMetricsArray::RFbsGlyphMetricsArray() :
       
    49     iGlyphCodes(NULL)
       
    50     {
       
    51     }
       
    52 
       
    53 /**
       
    54 Allocates the memory for the array if it has not already been allocated, and 
       
    55 populates the RFbsGlyphMetricsArray with the metrics information for aCount glyph 
       
    56 codes passed in as the array aGlyphCodes, for the font aFont. If the operation 
       
    57 is successful, KErrNone is returned and the array is populated with glyph 
       
    58 metrics data. Each entry in the array will be in the same order as the 
       
    59 corresponding codes in aGlyphCodes.
       
    60 
       
    61 The memory allocated to aGlyphCodes can be freed after the call to Get().
       
    62 
       
    63 Get() can be called on an RFbsGlyphMetricsArray multiple times without calling 
       
    64 Close(), since the memory for the array is not de-allocated until a call to 
       
    65 Close(). Calls to Get() will cause the previous content of the array to be 
       
    66 overwritten.
       
    67 
       
    68 In the event of an error code other than KErrNone, the state of the array
       
    69 will remain unchanged.
       
    70  
       
    71 @param aFont A font which to retrieve the glyph metrics for.
       
    72 @param aGlyphCodes An array of glyph codes to retrieve the metrics for.
       
    73 @param aCount The number of glyph codes in aGlyphCodes.
       
    74 
       
    75 @return
       
    76 	KErrNone, if the array is successfully populated with glyph metrics;
       
    77 	KErrNoMemory, if insufficient system memory is available;
       
    78 	KErrArgument, if aCount is negative or zero, or if aGlyphCodes is null;
       
    79 	KErrNotSupported, if aFont is a bitmap font.
       
    80 */
       
    81 EXPORT_C TInt RFbsGlyphMetricsArray::Get(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount)
       
    82 	{
       
    83     if ((aCount <= 0) || !aGlyphCodes)
       
    84         {
       
    85         return KErrArgument;
       
    86         }
       
    87     if (iMetrics.Reserve(aCount) != KErrNone)
       
    88         {
       
    89         return KErrNoMemory;
       
    90         }
       
    91     if (!aFont.Address()->IsOpenFont())
       
    92         {
       
    93         return KErrNotSupported;
       
    94         }
       
    95     
       
    96     iGlyphCodes = aGlyphCodes;
       
    97     iCount = aCount;
       
    98     TInt err = KErrNone;
       
    99     
       
   100     
       
   101     // If iMetrics array already has a count greater than aCount, remove entries
       
   102     // until count is same as aCount so that we can reuse the existing entries.
       
   103     TInt numEntriesToRemove = iMetrics.Count() - aCount;
       
   104     while (0 < numEntriesToRemove)
       
   105         {
       
   106         --numEntriesToRemove;
       
   107         iMetrics.Remove(aCount + numEntriesToRemove);
       
   108         }
       
   109     const TInt indexToGrowArrayAt = iMetrics.Count();
       
   110     
       
   111     CBitmapFont* font = aFont.Address();
       
   112     TUint ipcGlyphArrayIndex[KMaxMetricsBatchSize];
       
   113     TInt ipcGlyphArrayIndexCount = 0;   
       
   114     const TUint8* dummyBitmap;
       
   115     TOpenFontCharMetrics charDataMetrics;
       
   116             
       
   117     for (TInt i = 0; i < aCount && (err == KErrNone); ++i)
       
   118         {
       
   119         // First check the cache in shared memory - if present it will avoid using IPC.
       
   120         if (font->GetCharacterData(aFont.iFbs->ServerSessionHandle(), aGlyphCodes[i] | KGlyphCodeFlag, charDataMetrics, dummyBitmap))
       
   121             {
       
   122             if (i < indexToGrowArrayAt)
       
   123                 {
       
   124                 iMetrics[i] = charDataMetrics;
       
   125                 }
       
   126             else
       
   127                 {
       
   128                 // Extending the size of the array, but memory is already reserved.
       
   129                 (void) iMetrics.Append(charDataMetrics);    
       
   130                 }
       
   131             }            
       
   132         else
       
   133             {
       
   134             // Not found in shared memory - instead add the index to index array, which will
       
   135             // be processed when the array is full or at the end of the loop.
       
   136             ipcGlyphArrayIndex[ipcGlyphArrayIndexCount++] = i;
       
   137             if (ipcGlyphArrayIndexCount == KMaxMetricsBatchSize)
       
   138                 {
       
   139                 err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
       
   140                 ipcGlyphArrayIndexCount = 0;
       
   141                 }
       
   142             else if (i >= indexToGrowArrayAt)
       
   143                 {
       
   144                 // Add a metrics placeholder to keep the size of the array and the currently
       
   145                 // processed glyph in sync. It will later get overwritten when it is received
       
   146                 // from the server.
       
   147                 (void) iMetrics.Append(charDataMetrics);
       
   148                 }
       
   149             }
       
   150         }
       
   151     if ((err == KErrNone) && (ipcGlyphArrayIndexCount != 0))
       
   152         {
       
   153         err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
       
   154         }
       
   155     
       
   156     __ASSERT_DEBUG((err != KErrNone) || (aCount == iMetrics.Count()), Panic(EFbsPanicGlyphMetricsArrayInvalidState));  
       
   157     
       
   158     return err;    
       
   159 	}
       
   160 /**
       
   161 Helper function for Get(). 
       
   162 Given a list of indices into a glyph code array, the corresponding glyph
       
   163 codes are made into a single list sent to the server, and the received glyph
       
   164 metrics are set in the array of metrics at the corresponding indices.
       
   165 
       
   166 @param aFont The font to receive the glyph metrics of.
       
   167 @param aArrayIndices An array of indices into the glyphcode array which
       
   168     will be sent for requesting of metrics to the server.
       
   169 @param aArrayIndicesCount The number of glyphs in aGlyphArrayIndices.
       
   170 @param aMetrics The array which will store the resulting metrics objects upon
       
   171     completion.
       
   172 @return KErrNone if successful, otherwise one of the system-wide error codes. 
       
   173 
       
   174 @panic FBSCLI 39 in debug builds only, if the parameters to this method are
       
   175     invalid, or if the output array is of the wrong size when appending to it.
       
   176  */
       
   177 TInt RFbsGlyphMetricsArray::SendRecvGlyphMetrics(CFbsFont& aFont, TUint* aArrayIndices, TInt aArrayIndicesCount, RArray<TOpenFontCharMetrics>* aMetrics) const
       
   178     {
       
   179     __ASSERT_DEBUG(aArrayIndicesCount > 0, Panic(EFbsPanicGlyphDataIteratorInvalidState)); 
       
   180     __ASSERT_DEBUG(aArrayIndicesCount <= KMaxMetricsBatchSize, Panic(EFbsPanicGlyphDataIteratorInvalidState)); 
       
   181     __ASSERT_DEBUG(aArrayIndices, Panic(EFbsPanicGlyphDataIteratorInvalidState));
       
   182     TInt err = KErrNone;
       
   183     
       
   184     TUint glyphCodes[KMaxMetricsBatchSize];
       
   185     for (TInt i = 0; i < aArrayIndicesCount; ++i)
       
   186         {
       
   187         glyphCodes[i] = iGlyphCodes[aArrayIndices[i]];
       
   188         }
       
   189     
       
   190     TInt rcvdGlyphMetricsOffsets[KMaxMetricsBatchSize];
       
   191     TPckg<TUint[KMaxMetricsBatchSize]> argGlyphCodes(glyphCodes);
       
   192     TPckg<TInt[KMaxMetricsBatchSize]> argGlyphMetricsOffsets(rcvdGlyphMetricsOffsets);
       
   193     if (aArrayIndicesCount < KMaxMetricsBatchSize)
       
   194         {
       
   195         argGlyphCodes.SetLength(aArrayIndicesCount * sizeof(TUint));
       
   196         argGlyphMetricsOffsets.SetLength(aArrayIndicesCount * sizeof(TInt));
       
   197         }   
       
   198     err = aFont.iFbs->SendCommand(EFbsMessGetGlyphMetrics, TIpcArgs(aFont.iHandle, &argGlyphCodes, &argGlyphMetricsOffsets));
       
   199     
       
   200     if (err == KErrNone)
       
   201         {
       
   202         TInt numRcvdMetrics = argGlyphMetricsOffsets.Length() / sizeof(TInt);
       
   203         __ASSERT_DEBUG(argGlyphMetricsOffsets.Length() % sizeof(TInt) == 0, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
       
   204         __ASSERT_DEBUG(numRcvdMetrics == aArrayIndicesCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
       
   205         
       
   206         if (numRcvdMetrics == aArrayIndicesCount)
       
   207             {
       
   208             TInt arrayCount = aMetrics->Count();
       
   209             TUint8* heapBase = aFont.iFbs->HeapBase();
       
   210             for (TInt rcvdMetricsItem = 0; rcvdMetricsItem < numRcvdMetrics; ++rcvdMetricsItem)
       
   211                 {
       
   212                 TInt arrayIndex = aArrayIndices[rcvdMetricsItem];
       
   213                 // The array should never need to grow more than one item. If the difference is larger, 
       
   214                 // it means the glyph and the metrics are not in sync.
       
   215                 __ASSERT_DEBUG(arrayIndex <= arrayCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
       
   216                 
       
   217                 TInt metricsOffset = rcvdGlyphMetricsOffsets[rcvdMetricsItem];              
       
   218                 const TOpenFontCharMetrics* metrics = (const TOpenFontCharMetrics*)(OffsetToPointer(metricsOffset, heapBase));
       
   219                 
       
   220                 if (arrayIndex < arrayCount)
       
   221                     {
       
   222                     // Copy metrics into existing element
       
   223                     (*aMetrics)[arrayIndex] = *metrics;
       
   224                     }
       
   225                 else if (arrayIndex == arrayCount)
       
   226                     {
       
   227                     // Memory should already be reserved by GetGlyphMetricsArray()
       
   228                     (void) aMetrics->Append(*metrics);    
       
   229                     ++arrayCount;
       
   230                     }
       
   231                 }
       
   232             }
       
   233         else
       
   234             {
       
   235             // did not receive the same number of glyphs as was asked.
       
   236             err = KErrGeneral;
       
   237             }
       
   238         }
       
   239     return err;
       
   240     }
       
   241 
       
   242 /**
       
   243 Closes the array, and releases the memory for the array. Calling Close() on an 
       
   244 already closed RFbsGlyphMetricsArray has no effect. 
       
   245 
       
   246 In the typical case where the array is a member of a class, Close() should only 
       
   247 be called in the destructor of that class.
       
   248  */
       
   249 EXPORT_C void RFbsGlyphMetricsArray::Close()
       
   250 	{
       
   251 	iMetrics.Close();
       
   252 	}
       
   253 
       
   254 /**
       
   255 Retrieves the glyph metrics for the glyph which was at position aIndex in the 
       
   256 array passed to Get().
       
   257 
       
   258 @param aIndex The index of the entry in the array to access.
       
   259 @return The metrics for the glyph at the requested index.
       
   260 @panic FBSCLI 32, if aIndex is out of bounds.
       
   261  */
       
   262 EXPORT_C const TOpenFontCharMetrics& RFbsGlyphMetricsArray::operator[](TInt aIndex) const
       
   263 	{
       
   264 	__ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMetrics.Count(), Panic(EFbsPanicGlyphMetricsArrayOutOfBounds));
       
   265 	return (iMetrics)[aIndex];
       
   266 	}
       
   267 
       
   268 /**
       
   269 @return The number of glyph metrics held in the array.
       
   270  */
       
   271 EXPORT_C TInt RFbsGlyphMetricsArray::Count() const
       
   272 	{
       
   273 	return iMetrics.Count();
       
   274 	}