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