os/graphics/fbs/fontandbitmapserver/sfbs/fbsglyphmetricsarray.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/graphics/fbs/fontandbitmapserver/sfbs/fbsglyphmetricsarray.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,274 @@
     1.4 +// Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +
    1.20 +#include <e32def.h>
    1.21 +#include <gdi.h>
    1.22 +#include <graphics/gdi/gdistructs.h>
    1.23 +#include <graphics/gdi/gdiconsts.h>
    1.24 +#include <graphics/fbsglyphmetricsarray.h>
    1.25 +#include "UTILS.H"
    1.26 +#include "FbsMessage.h"
    1.27 +
    1.28 +// 'most significant bit' flag to ensure value is interpreted as a glyph code rather than an ascii code
    1.29 +const TUint KGlyphCodeFlag = 0x80000000;      
    1.30 +
    1.31 +extern void Panic(TFbsPanic aPanic);
    1.32 +
    1.33 +/** Helper function for converting an offset (that was calculated using
    1.34 +PointerToOffset()) back to a pointer relative to the passed heap base.
    1.35 +@param aOffset The offset to be converted to a pointer.
    1.36 +@param aHeapBase A pointer to the heap base of the current process.
    1.37 +@return A pointer relative to the passed heap base.
    1.38 +*/
    1.39 +static TAny* OffsetToPointer(const TInt aOffset, TUint8* aHeapBase)
    1.40 +    {
    1.41 +    if ( (aOffset != 0) && (aHeapBase != NULL) )
    1.42 +        {
    1.43 +        return (TAny*)(aOffset + aHeapBase);
    1.44 +        }
    1.45 +    return NULL;
    1.46 +    }
    1.47 +
    1.48 +/**
    1.49 +Constructs an empty RFbsGlyphMetricsArray instance. This will not allocate any memory.
    1.50 + */
    1.51 +EXPORT_C RFbsGlyphMetricsArray::RFbsGlyphMetricsArray() :
    1.52 +    iGlyphCodes(NULL)
    1.53 +    {
    1.54 +    }
    1.55 +
    1.56 +/**
    1.57 +Allocates the memory for the array if it has not already been allocated, and 
    1.58 +populates the RFbsGlyphMetricsArray with the metrics information for aCount glyph 
    1.59 +codes passed in as the array aGlyphCodes, for the font aFont. If the operation 
    1.60 +is successful, KErrNone is returned and the array is populated with glyph 
    1.61 +metrics data. Each entry in the array will be in the same order as the 
    1.62 +corresponding codes in aGlyphCodes.
    1.63 +
    1.64 +The memory allocated to aGlyphCodes can be freed after the call to Get().
    1.65 +
    1.66 +Get() can be called on an RFbsGlyphMetricsArray multiple times without calling 
    1.67 +Close(), since the memory for the array is not de-allocated until a call to 
    1.68 +Close(). Calls to Get() will cause the previous content of the array to be 
    1.69 +overwritten.
    1.70 +
    1.71 +In the event of an error code other than KErrNone, the state of the array
    1.72 +will remain unchanged.
    1.73 + 
    1.74 +@param aFont A font which to retrieve the glyph metrics for.
    1.75 +@param aGlyphCodes An array of glyph codes to retrieve the metrics for.
    1.76 +@param aCount The number of glyph codes in aGlyphCodes.
    1.77 +
    1.78 +@return
    1.79 +	KErrNone, if the array is successfully populated with glyph metrics;
    1.80 +	KErrNoMemory, if insufficient system memory is available;
    1.81 +	KErrArgument, if aCount is negative or zero, or if aGlyphCodes is null;
    1.82 +	KErrNotSupported, if aFont is a bitmap font.
    1.83 +*/
    1.84 +EXPORT_C TInt RFbsGlyphMetricsArray::Get(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount)
    1.85 +	{
    1.86 +    if ((aCount <= 0) || !aGlyphCodes)
    1.87 +        {
    1.88 +        return KErrArgument;
    1.89 +        }
    1.90 +    if (iMetrics.Reserve(aCount) != KErrNone)
    1.91 +        {
    1.92 +        return KErrNoMemory;
    1.93 +        }
    1.94 +    if (!aFont.Address()->IsOpenFont())
    1.95 +        {
    1.96 +        return KErrNotSupported;
    1.97 +        }
    1.98 +    
    1.99 +    iGlyphCodes = aGlyphCodes;
   1.100 +    iCount = aCount;
   1.101 +    TInt err = KErrNone;
   1.102 +    
   1.103 +    
   1.104 +    // If iMetrics array already has a count greater than aCount, remove entries
   1.105 +    // until count is same as aCount so that we can reuse the existing entries.
   1.106 +    TInt numEntriesToRemove = iMetrics.Count() - aCount;
   1.107 +    while (0 < numEntriesToRemove)
   1.108 +        {
   1.109 +        --numEntriesToRemove;
   1.110 +        iMetrics.Remove(aCount + numEntriesToRemove);
   1.111 +        }
   1.112 +    const TInt indexToGrowArrayAt = iMetrics.Count();
   1.113 +    
   1.114 +    CBitmapFont* font = aFont.Address();
   1.115 +    TUint ipcGlyphArrayIndex[KMaxMetricsBatchSize];
   1.116 +    TInt ipcGlyphArrayIndexCount = 0;   
   1.117 +    const TUint8* dummyBitmap;
   1.118 +    TOpenFontCharMetrics charDataMetrics;
   1.119 +            
   1.120 +    for (TInt i = 0; i < aCount && (err == KErrNone); ++i)
   1.121 +        {
   1.122 +        // First check the cache in shared memory - if present it will avoid using IPC.
   1.123 +        if (font->GetCharacterData(aFont.iFbs->ServerSessionHandle(), aGlyphCodes[i] | KGlyphCodeFlag, charDataMetrics, dummyBitmap))
   1.124 +            {
   1.125 +            if (i < indexToGrowArrayAt)
   1.126 +                {
   1.127 +                iMetrics[i] = charDataMetrics;
   1.128 +                }
   1.129 +            else
   1.130 +                {
   1.131 +                // Extending the size of the array, but memory is already reserved.
   1.132 +                (void) iMetrics.Append(charDataMetrics);    
   1.133 +                }
   1.134 +            }            
   1.135 +        else
   1.136 +            {
   1.137 +            // Not found in shared memory - instead add the index to index array, which will
   1.138 +            // be processed when the array is full or at the end of the loop.
   1.139 +            ipcGlyphArrayIndex[ipcGlyphArrayIndexCount++] = i;
   1.140 +            if (ipcGlyphArrayIndexCount == KMaxMetricsBatchSize)
   1.141 +                {
   1.142 +                err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
   1.143 +                ipcGlyphArrayIndexCount = 0;
   1.144 +                }
   1.145 +            else if (i >= indexToGrowArrayAt)
   1.146 +                {
   1.147 +                // Add a metrics placeholder to keep the size of the array and the currently
   1.148 +                // processed glyph in sync. It will later get overwritten when it is received
   1.149 +                // from the server.
   1.150 +                (void) iMetrics.Append(charDataMetrics);
   1.151 +                }
   1.152 +            }
   1.153 +        }
   1.154 +    if ((err == KErrNone) && (ipcGlyphArrayIndexCount != 0))
   1.155 +        {
   1.156 +        err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
   1.157 +        }
   1.158 +    
   1.159 +    __ASSERT_DEBUG((err != KErrNone) || (aCount == iMetrics.Count()), Panic(EFbsPanicGlyphMetricsArrayInvalidState));  
   1.160 +    
   1.161 +    return err;    
   1.162 +	}
   1.163 +/**
   1.164 +Helper function for Get(). 
   1.165 +Given a list of indices into a glyph code array, the corresponding glyph
   1.166 +codes are made into a single list sent to the server, and the received glyph
   1.167 +metrics are set in the array of metrics at the corresponding indices.
   1.168 +
   1.169 +@param aFont The font to receive the glyph metrics of.
   1.170 +@param aArrayIndices An array of indices into the glyphcode array which
   1.171 +    will be sent for requesting of metrics to the server.
   1.172 +@param aArrayIndicesCount The number of glyphs in aGlyphArrayIndices.
   1.173 +@param aMetrics The array which will store the resulting metrics objects upon
   1.174 +    completion.
   1.175 +@return KErrNone if successful, otherwise one of the system-wide error codes. 
   1.176 +
   1.177 +@panic FBSCLI 39 in debug builds only, if the parameters to this method are
   1.178 +    invalid, or if the output array is of the wrong size when appending to it.
   1.179 + */
   1.180 +TInt RFbsGlyphMetricsArray::SendRecvGlyphMetrics(CFbsFont& aFont, TUint* aArrayIndices, TInt aArrayIndicesCount, RArray<TOpenFontCharMetrics>* aMetrics) const
   1.181 +    {
   1.182 +    __ASSERT_DEBUG(aArrayIndicesCount > 0, Panic(EFbsPanicGlyphDataIteratorInvalidState)); 
   1.183 +    __ASSERT_DEBUG(aArrayIndicesCount <= KMaxMetricsBatchSize, Panic(EFbsPanicGlyphDataIteratorInvalidState)); 
   1.184 +    __ASSERT_DEBUG(aArrayIndices, Panic(EFbsPanicGlyphDataIteratorInvalidState));
   1.185 +    TInt err = KErrNone;
   1.186 +    
   1.187 +    TUint glyphCodes[KMaxMetricsBatchSize];
   1.188 +    for (TInt i = 0; i < aArrayIndicesCount; ++i)
   1.189 +        {
   1.190 +        glyphCodes[i] = iGlyphCodes[aArrayIndices[i]];
   1.191 +        }
   1.192 +    
   1.193 +    TInt rcvdGlyphMetricsOffsets[KMaxMetricsBatchSize];
   1.194 +    TPckg<TUint[KMaxMetricsBatchSize]> argGlyphCodes(glyphCodes);
   1.195 +    TPckg<TInt[KMaxMetricsBatchSize]> argGlyphMetricsOffsets(rcvdGlyphMetricsOffsets);
   1.196 +    if (aArrayIndicesCount < KMaxMetricsBatchSize)
   1.197 +        {
   1.198 +        argGlyphCodes.SetLength(aArrayIndicesCount * sizeof(TUint));
   1.199 +        argGlyphMetricsOffsets.SetLength(aArrayIndicesCount * sizeof(TInt));
   1.200 +        }   
   1.201 +    err = aFont.iFbs->SendCommand(EFbsMessGetGlyphMetrics, TIpcArgs(aFont.iHandle, &argGlyphCodes, &argGlyphMetricsOffsets));
   1.202 +    
   1.203 +    if (err == KErrNone)
   1.204 +        {
   1.205 +        TInt numRcvdMetrics = argGlyphMetricsOffsets.Length() / sizeof(TInt);
   1.206 +        __ASSERT_DEBUG(argGlyphMetricsOffsets.Length() % sizeof(TInt) == 0, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
   1.207 +        __ASSERT_DEBUG(numRcvdMetrics == aArrayIndicesCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
   1.208 +        
   1.209 +        if (numRcvdMetrics == aArrayIndicesCount)
   1.210 +            {
   1.211 +            TInt arrayCount = aMetrics->Count();
   1.212 +            TUint8* heapBase = aFont.iFbs->HeapBase();
   1.213 +            for (TInt rcvdMetricsItem = 0; rcvdMetricsItem < numRcvdMetrics; ++rcvdMetricsItem)
   1.214 +                {
   1.215 +                TInt arrayIndex = aArrayIndices[rcvdMetricsItem];
   1.216 +                // The array should never need to grow more than one item. If the difference is larger, 
   1.217 +                // it means the glyph and the metrics are not in sync.
   1.218 +                __ASSERT_DEBUG(arrayIndex <= arrayCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
   1.219 +                
   1.220 +                TInt metricsOffset = rcvdGlyphMetricsOffsets[rcvdMetricsItem];              
   1.221 +                const TOpenFontCharMetrics* metrics = (const TOpenFontCharMetrics*)(OffsetToPointer(metricsOffset, heapBase));
   1.222 +                
   1.223 +                if (arrayIndex < arrayCount)
   1.224 +                    {
   1.225 +                    // Copy metrics into existing element
   1.226 +                    (*aMetrics)[arrayIndex] = *metrics;
   1.227 +                    }
   1.228 +                else if (arrayIndex == arrayCount)
   1.229 +                    {
   1.230 +                    // Memory should already be reserved by GetGlyphMetricsArray()
   1.231 +                    (void) aMetrics->Append(*metrics);    
   1.232 +                    ++arrayCount;
   1.233 +                    }
   1.234 +                }
   1.235 +            }
   1.236 +        else
   1.237 +            {
   1.238 +            // did not receive the same number of glyphs as was asked.
   1.239 +            err = KErrGeneral;
   1.240 +            }
   1.241 +        }
   1.242 +    return err;
   1.243 +    }
   1.244 +
   1.245 +/**
   1.246 +Closes the array, and releases the memory for the array. Calling Close() on an 
   1.247 +already closed RFbsGlyphMetricsArray has no effect. 
   1.248 +
   1.249 +In the typical case where the array is a member of a class, Close() should only 
   1.250 +be called in the destructor of that class.
   1.251 + */
   1.252 +EXPORT_C void RFbsGlyphMetricsArray::Close()
   1.253 +	{
   1.254 +	iMetrics.Close();
   1.255 +	}
   1.256 +
   1.257 +/**
   1.258 +Retrieves the glyph metrics for the glyph which was at position aIndex in the 
   1.259 +array passed to Get().
   1.260 +
   1.261 +@param aIndex The index of the entry in the array to access.
   1.262 +@return The metrics for the glyph at the requested index.
   1.263 +@panic FBSCLI 32, if aIndex is out of bounds.
   1.264 + */
   1.265 +EXPORT_C const TOpenFontCharMetrics& RFbsGlyphMetricsArray::operator[](TInt aIndex) const
   1.266 +	{
   1.267 +	__ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMetrics.Count(), Panic(EFbsPanicGlyphMetricsArrayOutOfBounds));
   1.268 +	return (iMetrics)[aIndex];
   1.269 +	}
   1.270 +
   1.271 +/**
   1.272 +@return The number of glyph metrics held in the array.
   1.273 + */
   1.274 +EXPORT_C TInt RFbsGlyphMetricsArray::Count() const
   1.275 +	{
   1.276 +	return iMetrics.Count();
   1.277 +	}