fbs/fontandbitmapserver/sfbs/fbsglyphmetricsarray.cpp
changeset 187 9f66f99ee56f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fbs/fontandbitmapserver/sfbs/fbsglyphmetricsarray.cpp	Fri Sep 24 16:14:28 2010 +0300
@@ -0,0 +1,274 @@
+// Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+#include <e32def.h>
+#include <gdi.h>
+#include <graphics/gdi/gdistructs.h>
+#include <graphics/gdi/gdiconsts.h>
+#include <graphics/fbsglyphmetricsarray.h>
+#include "UTILS.H"
+#include "FbsMessage.h"
+
+// 'most significant bit' flag to ensure value is interpreted as a glyph code rather than an ascii code
+const TUint KGlyphCodeFlag = 0x80000000;      
+
+extern void Panic(TFbsPanic aPanic);
+
+/** Helper function for converting an offset (that was calculated using
+PointerToOffset()) back to a pointer relative to the passed heap base.
+@param aOffset The offset to be converted to a pointer.
+@param aHeapBase A pointer to the heap base of the current process.
+@return A pointer relative to the passed heap base.
+*/
+static TAny* OffsetToPointer(const TInt aOffset, TUint8* aHeapBase)
+    {
+    if ( (aOffset != 0) && (aHeapBase != NULL) )
+        {
+        return (TAny*)(aOffset + aHeapBase);
+        }
+    return NULL;
+    }
+
+/**
+Constructs an empty RFbsGlyphMetricsArray instance. This will not allocate any memory.
+ */
+EXPORT_C RFbsGlyphMetricsArray::RFbsGlyphMetricsArray() :
+    iGlyphCodes(NULL)
+    {
+    }
+
+/**
+Allocates the memory for the array if it has not already been allocated, and 
+populates the RFbsGlyphMetricsArray with the metrics information for aCount glyph 
+codes passed in as the array aGlyphCodes, for the font aFont. If the operation 
+is successful, KErrNone is returned and the array is populated with glyph 
+metrics data. Each entry in the array will be in the same order as the 
+corresponding codes in aGlyphCodes.
+
+The memory allocated to aGlyphCodes can be freed after the call to Get().
+
+Get() can be called on an RFbsGlyphMetricsArray multiple times without calling 
+Close(), since the memory for the array is not de-allocated until a call to 
+Close(). Calls to Get() will cause the previous content of the array to be 
+overwritten.
+
+In the event of an error code other than KErrNone, the state of the array
+will remain unchanged.
+ 
+@param aFont A font which to retrieve the glyph metrics for.
+@param aGlyphCodes An array of glyph codes to retrieve the metrics for.
+@param aCount The number of glyph codes in aGlyphCodes.
+
+@return
+	KErrNone, if the array is successfully populated with glyph metrics;
+	KErrNoMemory, if insufficient system memory is available;
+	KErrArgument, if aCount is negative or zero, or if aGlyphCodes is null;
+	KErrNotSupported, if aFont is a bitmap font.
+*/
+EXPORT_C TInt RFbsGlyphMetricsArray::Get(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount)
+	{
+    if ((aCount <= 0) || !aGlyphCodes)
+        {
+        return KErrArgument;
+        }
+    if (iMetrics.Reserve(aCount) != KErrNone)
+        {
+        return KErrNoMemory;
+        }
+    if (!aFont.Address()->IsOpenFont())
+        {
+        return KErrNotSupported;
+        }
+    
+    iGlyphCodes = aGlyphCodes;
+    iCount = aCount;
+    TInt err = KErrNone;
+    
+    
+    // If iMetrics array already has a count greater than aCount, remove entries
+    // until count is same as aCount so that we can reuse the existing entries.
+    TInt numEntriesToRemove = iMetrics.Count() - aCount;
+    while (0 < numEntriesToRemove)
+        {
+        --numEntriesToRemove;
+        iMetrics.Remove(aCount + numEntriesToRemove);
+        }
+    const TInt indexToGrowArrayAt = iMetrics.Count();
+    
+    CBitmapFont* font = aFont.Address();
+    TUint ipcGlyphArrayIndex[KMaxMetricsBatchSize];
+    TInt ipcGlyphArrayIndexCount = 0;   
+    const TUint8* dummyBitmap;
+    TOpenFontCharMetrics charDataMetrics;
+            
+    for (TInt i = 0; i < aCount && (err == KErrNone); ++i)
+        {
+        // First check the cache in shared memory - if present it will avoid using IPC.
+        if (font->GetCharacterData(aFont.iFbs->ServerSessionHandle(), aGlyphCodes[i] | KGlyphCodeFlag, charDataMetrics, dummyBitmap))
+            {
+            if (i < indexToGrowArrayAt)
+                {
+                iMetrics[i] = charDataMetrics;
+                }
+            else
+                {
+                // Extending the size of the array, but memory is already reserved.
+                (void) iMetrics.Append(charDataMetrics);    
+                }
+            }            
+        else
+            {
+            // Not found in shared memory - instead add the index to index array, which will
+            // be processed when the array is full or at the end of the loop.
+            ipcGlyphArrayIndex[ipcGlyphArrayIndexCount++] = i;
+            if (ipcGlyphArrayIndexCount == KMaxMetricsBatchSize)
+                {
+                err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
+                ipcGlyphArrayIndexCount = 0;
+                }
+            else if (i >= indexToGrowArrayAt)
+                {
+                // Add a metrics placeholder to keep the size of the array and the currently
+                // processed glyph in sync. It will later get overwritten when it is received
+                // from the server.
+                (void) iMetrics.Append(charDataMetrics);
+                }
+            }
+        }
+    if ((err == KErrNone) && (ipcGlyphArrayIndexCount != 0))
+        {
+        err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
+        }
+    
+    __ASSERT_DEBUG((err != KErrNone) || (aCount == iMetrics.Count()), Panic(EFbsPanicGlyphMetricsArrayInvalidState));  
+    
+    return err;    
+	}
+/**
+Helper function for Get(). 
+Given a list of indices into a glyph code array, the corresponding glyph
+codes are made into a single list sent to the server, and the received glyph
+metrics are set in the array of metrics at the corresponding indices.
+
+@param aFont The font to receive the glyph metrics of.
+@param aArrayIndices An array of indices into the glyphcode array which
+    will be sent for requesting of metrics to the server.
+@param aArrayIndicesCount The number of glyphs in aGlyphArrayIndices.
+@param aMetrics The array which will store the resulting metrics objects upon
+    completion.
+@return KErrNone if successful, otherwise one of the system-wide error codes. 
+
+@panic FBSCLI 39 in debug builds only, if the parameters to this method are
+    invalid, or if the output array is of the wrong size when appending to it.
+ */
+TInt RFbsGlyphMetricsArray::SendRecvGlyphMetrics(CFbsFont& aFont, TUint* aArrayIndices, TInt aArrayIndicesCount, RArray<TOpenFontCharMetrics>* aMetrics) const
+    {
+    __ASSERT_DEBUG(aArrayIndicesCount > 0, Panic(EFbsPanicGlyphDataIteratorInvalidState)); 
+    __ASSERT_DEBUG(aArrayIndicesCount <= KMaxMetricsBatchSize, Panic(EFbsPanicGlyphDataIteratorInvalidState)); 
+    __ASSERT_DEBUG(aArrayIndices, Panic(EFbsPanicGlyphDataIteratorInvalidState));
+    TInt err = KErrNone;
+    
+    TUint glyphCodes[KMaxMetricsBatchSize];
+    for (TInt i = 0; i < aArrayIndicesCount; ++i)
+        {
+        glyphCodes[i] = iGlyphCodes[aArrayIndices[i]];
+        }
+    
+    TInt rcvdGlyphMetricsOffsets[KMaxMetricsBatchSize];
+    TPckg<TUint[KMaxMetricsBatchSize]> argGlyphCodes(glyphCodes);
+    TPckg<TInt[KMaxMetricsBatchSize]> argGlyphMetricsOffsets(rcvdGlyphMetricsOffsets);
+    if (aArrayIndicesCount < KMaxMetricsBatchSize)
+        {
+        argGlyphCodes.SetLength(aArrayIndicesCount * sizeof(TUint));
+        argGlyphMetricsOffsets.SetLength(aArrayIndicesCount * sizeof(TInt));
+        }   
+    err = aFont.iFbs->SendCommand(EFbsMessGetGlyphMetrics, TIpcArgs(aFont.iHandle, &argGlyphCodes, &argGlyphMetricsOffsets));
+    
+    if (err == KErrNone)
+        {
+        TInt numRcvdMetrics = argGlyphMetricsOffsets.Length() / sizeof(TInt);
+        __ASSERT_DEBUG(argGlyphMetricsOffsets.Length() % sizeof(TInt) == 0, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
+        __ASSERT_DEBUG(numRcvdMetrics == aArrayIndicesCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
+        
+        if (numRcvdMetrics == aArrayIndicesCount)
+            {
+            TInt arrayCount = aMetrics->Count();
+            TUint8* heapBase = aFont.iFbs->HeapBase();
+            for (TInt rcvdMetricsItem = 0; rcvdMetricsItem < numRcvdMetrics; ++rcvdMetricsItem)
+                {
+                TInt arrayIndex = aArrayIndices[rcvdMetricsItem];
+                // The array should never need to grow more than one item. If the difference is larger, 
+                // it means the glyph and the metrics are not in sync.
+                __ASSERT_DEBUG(arrayIndex <= arrayCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
+                
+                TInt metricsOffset = rcvdGlyphMetricsOffsets[rcvdMetricsItem];              
+                const TOpenFontCharMetrics* metrics = (const TOpenFontCharMetrics*)(OffsetToPointer(metricsOffset, heapBase));
+                
+                if (arrayIndex < arrayCount)
+                    {
+                    // Copy metrics into existing element
+                    (*aMetrics)[arrayIndex] = *metrics;
+                    }
+                else if (arrayIndex == arrayCount)
+                    {
+                    // Memory should already be reserved by GetGlyphMetricsArray()
+                    (void) aMetrics->Append(*metrics);    
+                    ++arrayCount;
+                    }
+                }
+            }
+        else
+            {
+            // did not receive the same number of glyphs as was asked.
+            err = KErrGeneral;
+            }
+        }
+    return err;
+    }
+
+/**
+Closes the array, and releases the memory for the array. Calling Close() on an 
+already closed RFbsGlyphMetricsArray has no effect. 
+
+In the typical case where the array is a member of a class, Close() should only 
+be called in the destructor of that class.
+ */
+EXPORT_C void RFbsGlyphMetricsArray::Close()
+	{
+	iMetrics.Close();
+	}
+
+/**
+Retrieves the glyph metrics for the glyph which was at position aIndex in the 
+array passed to Get().
+
+@param aIndex The index of the entry in the array to access.
+@return The metrics for the glyph at the requested index.
+@panic FBSCLI 32, if aIndex is out of bounds.
+ */
+EXPORT_C const TOpenFontCharMetrics& RFbsGlyphMetricsArray::operator[](TInt aIndex) const
+	{
+	__ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMetrics.Count(), Panic(EFbsPanicGlyphMetricsArrayOutOfBounds));
+	return (iMetrics)[aIndex];
+	}
+
+/**
+@return The number of glyph metrics held in the array.
+ */
+EXPORT_C TInt RFbsGlyphMetricsArray::Count() const
+	{
+	return iMetrics.Count();
+	}