|
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". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 |
|
17 #include <e32def.h> |
|
18 #include <gdi.h> |
|
19 #include <graphics/gdi/gdistructs.h> |
|
20 #include <graphics/gdi/gdiconsts.h> |
|
21 #include <graphics/fbsglyphmetricsarray.h> |
|
22 #include "UTILS.H" |
|
23 #include "FbsMessage.h" |
|
24 |
|
25 // 'most significant bit' flag to ensure value is interpreted as a glyph code rather than an ascii code |
|
26 const TUint KGlyphCodeFlag = 0x80000000; |
|
27 |
|
28 extern void Panic(TFbsPanic aPanic); |
|
29 |
|
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. |
|
35 */ |
|
36 static TAny* OffsetToPointer(const TInt aOffset, TUint8* aHeapBase) |
|
37 { |
|
38 if ( (aOffset != 0) && (aHeapBase != NULL) ) |
|
39 { |
|
40 return (TAny*)(aOffset + aHeapBase); |
|
41 } |
|
42 return NULL; |
|
43 } |
|
44 |
|
45 /** |
|
46 Constructs an empty RFbsGlyphMetricsArray instance. This will not allocate any memory. |
|
47 */ |
|
48 EXPORT_C RFbsGlyphMetricsArray::RFbsGlyphMetricsArray() : |
|
49 iGlyphCodes(NULL) |
|
50 { |
|
51 } |
|
52 |
|
53 /** |
|
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. |
|
60 |
|
61 The memory allocated to aGlyphCodes can be freed after the call to Get(). |
|
62 |
|
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 |
|
66 overwritten. |
|
67 |
|
68 In the event of an error code other than KErrNone, the state of the array |
|
69 will remain unchanged. |
|
70 |
|
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. |
|
74 |
|
75 @return |
|
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. |
|
80 */ |
|
81 EXPORT_C TInt RFbsGlyphMetricsArray::Get(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount) |
|
82 { |
|
83 if ((aCount <= 0) || !aGlyphCodes) |
|
84 { |
|
85 return KErrArgument; |
|
86 } |
|
87 if (iMetrics.Reserve(aCount) != KErrNone) |
|
88 { |
|
89 return KErrNoMemory; |
|
90 } |
|
91 if (!aFont.Address()->IsOpenFont()) |
|
92 { |
|
93 return KErrNotSupported; |
|
94 } |
|
95 |
|
96 iGlyphCodes = aGlyphCodes; |
|
97 iCount = aCount; |
|
98 TInt err = KErrNone; |
|
99 |
|
100 |
|
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) |
|
105 { |
|
106 --numEntriesToRemove; |
|
107 iMetrics.Remove(aCount + numEntriesToRemove); |
|
108 } |
|
109 const TInt indexToGrowArrayAt = iMetrics.Count(); |
|
110 |
|
111 CBitmapFont* font = aFont.Address(); |
|
112 TUint ipcGlyphArrayIndex[KMaxMetricsBatchSize]; |
|
113 TInt ipcGlyphArrayIndexCount = 0; |
|
114 const TUint8* dummyBitmap; |
|
115 TOpenFontCharMetrics charDataMetrics; |
|
116 |
|
117 for (TInt i = 0; i < aCount && (err == KErrNone); ++i) |
|
118 { |
|
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)) |
|
121 { |
|
122 if (i < indexToGrowArrayAt) |
|
123 { |
|
124 iMetrics[i] = charDataMetrics; |
|
125 } |
|
126 else |
|
127 { |
|
128 // Extending the size of the array, but memory is already reserved. |
|
129 (void) iMetrics.Append(charDataMetrics); |
|
130 } |
|
131 } |
|
132 else |
|
133 { |
|
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) |
|
138 { |
|
139 err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics); |
|
140 ipcGlyphArrayIndexCount = 0; |
|
141 } |
|
142 else if (i >= indexToGrowArrayAt) |
|
143 { |
|
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 |
|
146 // from the server. |
|
147 (void) iMetrics.Append(charDataMetrics); |
|
148 } |
|
149 } |
|
150 } |
|
151 if ((err == KErrNone) && (ipcGlyphArrayIndexCount != 0)) |
|
152 { |
|
153 err = SendRecvGlyphMetrics(aFont, ipcGlyphArrayIndex, ipcGlyphArrayIndexCount, &iMetrics); |
|
154 } |
|
155 |
|
156 __ASSERT_DEBUG((err != KErrNone) || (aCount == iMetrics.Count()), Panic(EFbsPanicGlyphMetricsArrayInvalidState)); |
|
157 |
|
158 return err; |
|
159 } |
|
160 /** |
|
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. |
|
165 |
|
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 |
|
171 completion. |
|
172 @return KErrNone if successful, otherwise one of the system-wide error codes. |
|
173 |
|
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. |
|
176 */ |
|
177 TInt RFbsGlyphMetricsArray::SendRecvGlyphMetrics(CFbsFont& aFont, TUint* aArrayIndices, TInt aArrayIndicesCount, RArray<TOpenFontCharMetrics>* aMetrics) const |
|
178 { |
|
179 __ASSERT_DEBUG(aArrayIndicesCount > 0, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
180 __ASSERT_DEBUG(aArrayIndicesCount <= KMaxMetricsBatchSize, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
181 __ASSERT_DEBUG(aArrayIndices, Panic(EFbsPanicGlyphDataIteratorInvalidState)); |
|
182 TInt err = KErrNone; |
|
183 |
|
184 TUint glyphCodes[KMaxMetricsBatchSize]; |
|
185 for (TInt i = 0; i < aArrayIndicesCount; ++i) |
|
186 { |
|
187 glyphCodes[i] = iGlyphCodes[aArrayIndices[i]]; |
|
188 } |
|
189 |
|
190 TInt rcvdGlyphMetricsOffsets[KMaxMetricsBatchSize]; |
|
191 TPckg<TUint[KMaxMetricsBatchSize]> argGlyphCodes(glyphCodes); |
|
192 TPckg<TInt[KMaxMetricsBatchSize]> argGlyphMetricsOffsets(rcvdGlyphMetricsOffsets); |
|
193 if (aArrayIndicesCount < KMaxMetricsBatchSize) |
|
194 { |
|
195 argGlyphCodes.SetLength(aArrayIndicesCount * sizeof(TUint)); |
|
196 argGlyphMetricsOffsets.SetLength(aArrayIndicesCount * sizeof(TInt)); |
|
197 } |
|
198 err = aFont.iFbs->SendCommand(EFbsMessGetGlyphMetrics, TIpcArgs(aFont.iHandle, &argGlyphCodes, &argGlyphMetricsOffsets)); |
|
199 |
|
200 if (err == KErrNone) |
|
201 { |
|
202 TInt numRcvdMetrics = argGlyphMetricsOffsets.Length() / sizeof(TInt); |
|
203 __ASSERT_DEBUG(argGlyphMetricsOffsets.Length() % sizeof(TInt) == 0, Panic(EFbsPanicGlyphMetricsArrayInvalidState)); |
|
204 __ASSERT_DEBUG(numRcvdMetrics == aArrayIndicesCount, Panic(EFbsPanicGlyphMetricsArrayInvalidState)); |
|
205 |
|
206 if (numRcvdMetrics == aArrayIndicesCount) |
|
207 { |
|
208 TInt arrayCount = aMetrics->Count(); |
|
209 TUint8* heapBase = aFont.iFbs->HeapBase(); |
|
210 for (TInt rcvdMetricsItem = 0; rcvdMetricsItem < numRcvdMetrics; ++rcvdMetricsItem) |
|
211 { |
|
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)); |
|
216 |
|
217 TInt metricsOffset = rcvdGlyphMetricsOffsets[rcvdMetricsItem]; |
|
218 const TOpenFontCharMetrics* metrics = (const TOpenFontCharMetrics*)(OffsetToPointer(metricsOffset, heapBase)); |
|
219 |
|
220 if (arrayIndex < arrayCount) |
|
221 { |
|
222 // Copy metrics into existing element |
|
223 (*aMetrics)[arrayIndex] = *metrics; |
|
224 } |
|
225 else if (arrayIndex == arrayCount) |
|
226 { |
|
227 // Memory should already be reserved by GetGlyphMetricsArray() |
|
228 (void) aMetrics->Append(*metrics); |
|
229 ++arrayCount; |
|
230 } |
|
231 } |
|
232 } |
|
233 else |
|
234 { |
|
235 // did not receive the same number of glyphs as was asked. |
|
236 err = KErrGeneral; |
|
237 } |
|
238 } |
|
239 return err; |
|
240 } |
|
241 |
|
242 /** |
|
243 Closes the array, and releases the memory for the array. Calling Close() on an |
|
244 already closed RFbsGlyphMetricsArray has no effect. |
|
245 |
|
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. |
|
248 */ |
|
249 EXPORT_C void RFbsGlyphMetricsArray::Close() |
|
250 { |
|
251 iMetrics.Close(); |
|
252 } |
|
253 |
|
254 /** |
|
255 Retrieves the glyph metrics for the glyph which was at position aIndex in the |
|
256 array passed to Get(). |
|
257 |
|
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. |
|
261 */ |
|
262 EXPORT_C const TOpenFontCharMetrics& RFbsGlyphMetricsArray::operator[](TInt aIndex) const |
|
263 { |
|
264 __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMetrics.Count(), Panic(EFbsPanicGlyphMetricsArrayOutOfBounds)); |
|
265 return (iMetrics)[aIndex]; |
|
266 } |
|
267 |
|
268 /** |
|
269 @return The number of glyph metrics held in the array. |
|
270 */ |
|
271 EXPORT_C TInt RFbsGlyphMetricsArray::Count() const |
|
272 { |
|
273 return iMetrics.Count(); |
|
274 } |