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