diff -r 2717213c588a -r 171fae344dd4 fbs/fontandbitmapserver/sfbs/fbsglyphmetricsarray.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fbs/fontandbitmapserver/sfbs/fbsglyphmetricsarray.cpp Fri Jul 16 11:45:55 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 +#include +#include +#include +#include +#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* 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 argGlyphCodes(glyphCodes); + TPckg 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(); + }