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 + }