First public contribution.
1 // Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
19 #include <graphics/gdi/gdistructs.h>
20 #include <graphics/gdi/gdiconsts.h>
21 #include <graphics/fbsglyphmetricsarray.h>
23 #include "FbsMessage.h"
25 // 'most significant bit' flag to ensure value is interpreted as a glyph code rather than an ascii code
26 const TUint KGlyphCodeFlag = 0x80000000;
28 extern void Panic(TFbsPanic aPanic);
30 /** Helper function for converting an offset (that was calculated using
31 PointerToOffset()) back to a pointer relative to the passed heap base.
32 @param aOffset The offset to be converted to a pointer.
33 @param aHeapBase A pointer to the heap base of the current process.
34 @return A pointer relative to the passed heap base.
36 static TAny* OffsetToPointer(const TInt aOffset, TUint8* aHeapBase)
38 if ( (aOffset != 0) && (aHeapBase != NULL) )
40 return (TAny*)(aOffset + aHeapBase);
46 Constructs an empty RFbsGlyphMetricsArray instance. This will not allocate any memory.
48 EXPORT_C RFbsGlyphMetricsArray::RFbsGlyphMetricsArray() :
54 Allocates the memory for the array if it has not already been allocated, and
55 populates the RFbsGlyphMetricsArray with the metrics information for aCount glyph
56 codes passed in as the array aGlyphCodes, for the font aFont. If the operation
57 is successful, KErrNone is returned and the array is populated with glyph
58 metrics data. Each entry in the array will be in the same order as the
59 corresponding codes in aGlyphCodes.
61 The memory allocated to aGlyphCodes can be freed after the call to Get().
63 Get() can be called on an RFbsGlyphMetricsArray multiple times without calling
64 Close(), since the memory for the array is not de-allocated until a call to
65 Close(). Calls to Get() will cause the previous content of the array to be
68 In the event of an error code other than KErrNone, the state of the array
69 will remain unchanged.
71 @param aFont A font which to retrieve the glyph metrics for.
72 @param aGlyphCodes An array of glyph codes to retrieve the metrics for.
73 @param aCount The number of glyph codes in aGlyphCodes.
76 KErrNone, if the array is successfully populated with glyph metrics;
77 KErrNoMemory, if insufficient system memory is available;
78 KErrArgument, if aCount is negative or zero, or if aGlyphCodes is null;
79 KErrNotSupported, if aFont is a bitmap font.
81 EXPORT_C TInt RFbsGlyphMetricsArray::Get(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount)
83 if ((aCount <= 0) || !aGlyphCodes)
87 if (iMetrics.Reserve(aCount) != KErrNone)
91 if (!aFont.Address()->IsOpenFont())
93 return KErrNotSupported;
96 iGlyphCodes = aGlyphCodes;
101 // If iMetrics array already has a count greater than aCount, remove entries
102 // until count is same as aCount so that we can reuse the existing entries.
103 TInt numEntriesToRemove = iMetrics.Count() - aCount;
104 while (0 < numEntriesToRemove)
106 --numEntriesToRemove;
107 iMetrics.Remove(aCount + numEntriesToRemove);
109 const TInt indexToGrowArrayAt = iMetrics.Count();
111 CBitmapFont* font = aFont.Address();
112 TUint ipcGlyphArrayIndex[KMaxMetricsBatchSize];
113 TInt ipcGlyphArrayIndexCount = 0;
114 const TUint8* dummyBitmap;
115 TOpenFontCharMetrics charDataMetrics;
117 for (TInt i = 0; i < aCount && (err == KErrNone); ++i)
119 // First check the cache in shared memory - if present it will avoid using IPC.
120 if (font->GetCharacterData(aFont.iFbs->ServerSessionHandle(), aGlyphCodes[i] | KGlyphCodeFlag, charDataMetrics, dummyBitmap))
122 if (i < indexToGrowArrayAt)
124 iMetrics[i] = charDataMetrics;
128 // Extending the size of the array, but memory is already reserved.
129 (void) iMetrics.Append(charDataMetrics);
134 // Not found in shared memory - instead add the index to index array, which will
135 // be processed when the array is full or at the end of the loop.
136 ipcGlyphArrayIndex[ipcGlyphArrayIndexCount++] = i;
137 if (ipcGlyphArrayIndexCount == KMaxMetricsBatchSize)
139 err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
140 ipcGlyphArrayIndexCount = 0;
142 else if (i >= indexToGrowArrayAt)
144 // Add a metrics placeholder to keep the size of the array and the currently
145 // processed glyph in sync. It will later get overwritten when it is received
147 (void) iMetrics.Append(charDataMetrics);
151 if ((err == KErrNone) && (ipcGlyphArrayIndexCount != 0))
153 err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics);
156 __ASSERT_DEBUG((err != KErrNone) || (aCount == iMetrics.Count()), Panic(EFbsPanicGlyphMetricsArrayInvalidState));
161 Helper function for Get().
162 Given a list of indices into a glyph code array, the corresponding glyph
163 codes are made into a single list sent to the server, and the received glyph
164 metrics are set in the array of metrics at the corresponding indices.
166 @param aFont The font to receive the glyph metrics of.
167 @param aArrayIndices An array of indices into the glyphcode array which
168 will be sent for requesting of metrics to the server.
169 @param aArrayIndicesCount The number of glyphs in aGlyphArrayIndices.
170 @param aMetrics The array which will store the resulting metrics objects upon
172 @return KErrNone if successful, otherwise one of the system-wide error codes.
174 @panic FBSCLI 39 in debug builds only, if the parameters to this method are
175 invalid, or if the output array is of the wrong size when appending to it.
177 TInt RFbsGlyphMetricsArray::SendRecvGlyphMetrics(CFbsFont& aFont, TUint* aArrayIndices, TInt aArrayIndicesCount, RArray<TOpenFontCharMetrics>* aMetrics) const
179 __ASSERT_DEBUG(aArrayIndicesCount > 0, Panic(EFbsPanicGlyphDataIteratorInvalidState));
180 __ASSERT_DEBUG(aArrayIndicesCount <= KMaxMetricsBatchSize, Panic(EFbsPanicGlyphDataIteratorInvalidState));
181 __ASSERT_DEBUG(aArrayIndices, Panic(EFbsPanicGlyphDataIteratorInvalidState));
184 TUint glyphCodes[KMaxMetricsBatchSize];
185 for (TInt i = 0; i < aArrayIndicesCount; ++i)
187 glyphCodes[i] = iGlyphCodes[aArrayIndices[i]];
190 TInt rcvdGlyphMetricsOffsets[KMaxMetricsBatchSize];
191 TPckg<TUint[KMaxMetricsBatchSize]> argGlyphCodes(glyphCodes);
192 TPckg<TInt[KMaxMetricsBatchSize]> argGlyphMetricsOffsets(rcvdGlyphMetricsOffsets);
193 if (aArrayIndicesCount < KMaxMetricsBatchSize)
195 argGlyphCodes.SetLength(aArrayIndicesCount * sizeof(TUint));
196 argGlyphMetricsOffsets.SetLength(aArrayIndicesCount * sizeof(TInt));
198 err = aFont.iFbs->SendCommand(EFbsMessGetGlyphMetrics, TIpcArgs(aFont.iHandle, &argGlyphCodes, &argGlyphMetricsOffsets));
202 TInt numRcvdMetrics = argGlyphMetricsOffsets.Length() / sizeof(TInt);
203 __ASSERT_DEBUG(argGlyphMetricsOffsets.Length() % sizeof(TInt) == 0, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
204 __ASSERT_DEBUG(numRcvdMetrics == aArrayIndicesCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
206 if (numRcvdMetrics == aArrayIndicesCount)
208 TInt arrayCount = aMetrics->Count();
209 TUint8* heapBase = aFont.iFbs->HeapBase();
210 for (TInt rcvdMetricsItem = 0; rcvdMetricsItem < numRcvdMetrics; ++rcvdMetricsItem)
212 TInt arrayIndex = aArrayIndices[rcvdMetricsItem];
213 // The array should never need to grow more than one item. If the difference is larger,
214 // it means the glyph and the metrics are not in sync.
215 __ASSERT_DEBUG(arrayIndex <= arrayCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState));
217 TInt metricsOffset = rcvdGlyphMetricsOffsets[rcvdMetricsItem];
218 const TOpenFontCharMetrics* metrics = (const TOpenFontCharMetrics*)(OffsetToPointer(metricsOffset, heapBase));
220 if (arrayIndex < arrayCount)
222 // Copy metrics into existing element
223 (*aMetrics)[arrayIndex] = *metrics;
225 else if (arrayIndex == arrayCount)
227 // Memory should already be reserved by GetGlyphMetricsArray()
228 (void) aMetrics->Append(*metrics);
235 // did not receive the same number of glyphs as was asked.
243 Closes the array, and releases the memory for the array. Calling Close() on an
244 already closed RFbsGlyphMetricsArray has no effect.
246 In the typical case where the array is a member of a class, Close() should only
247 be called in the destructor of that class.
249 EXPORT_C void RFbsGlyphMetricsArray::Close()
255 Retrieves the glyph metrics for the glyph which was at position aIndex in the
256 array passed to Get().
258 @param aIndex The index of the entry in the array to access.
259 @return The metrics for the glyph at the requested index.
260 @panic FBSCLI 32, if aIndex is out of bounds.
262 EXPORT_C const TOpenFontCharMetrics& RFbsGlyphMetricsArray::operator[](TInt aIndex) const
264 __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMetrics.Count(), Panic(EFbsPanicGlyphMetricsArrayOutOfBounds));
265 return (iMetrics)[aIndex];
269 @return The number of glyph metrics held in the array.
271 EXPORT_C TInt RFbsGlyphMetricsArray::Count() const
273 return iMetrics.Count();