|
1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Creates test data files that are used by TC_SHAP_shapeText.cpp test. |
|
16 * This tool uses the Unicode test input text defined in inputData.h and |
|
17 * shapes the text by calling the IcuLayoutEngine API ShapeText(). |
|
18 * The result, along with the input text is stored in the test data files with |
|
19 * extensions .dat |
|
20 * First, the reference input data is stored in the data files in the following format, seperated by a delimiter - | : |
|
21 * Length (of the input data string) Font typeface name | Font file name | Starting offset in the input string | End offset in the input string | Input text string |
|
22 * Then the result of the shaping is stored in data files in the following format: |
|
23 * Output glyph count Output glyphs Glyph X and Y coordinates Glyph advances Glyph indices Output character count |
|
24 * The TC_SHAP_shape_Text test is programmed to read in files in this format, and this format only. |
|
25 * This tool needs to be run, and new test data files need to be created everytime the |
|
26 * IcuLayoutEngine shaping rules are changed/edited/appended. |
|
27 * IN ORDER TO CREATE NEW TEST DATA FILES USING THIS UTILITY, YOU WILL NEED TO: |
|
28 * 1. Add a new TInputData entry in inputData.txt |
|
29 * 2. Delete any old data files in %EPOCROOT%epoc32\winscw\c\ |
|
30 * 3. Run the test. |
|
31 * IN ORDER TO GET THE TC_SHAP_shapeText TEST FILE TO USE THIS NEW DATA, YOU WILL NEED TO: |
|
32 * 1. Add your new test file in perforce to: |
|
33 * IcuLayoutEngine/test/testdata/... |
|
34 * They will have been added to %EPOCROOT%epoc32\winscw\c |
|
35 * 2. Update the bld.inf file for IcuLayoutEngine to export this file to z:\test\data\... |
|
36 * 3. Update the .cpp file by adding the a new literal at the top of the file with the new filename to be used. |
|
37 * 4. Update the TC_SHAP_shapeText.iby file in IcuLayoutEngine/test to include the new file. |
|
38 * THIS TOOL SHOULD ONLY BE RUN BY SOMEONE WHO KNOWS WHAT HE/SHE IS DOING!! |
|
39 * |
|
40 */ |
|
41 |
|
42 |
|
43 #include <e32def.h> |
|
44 #include <e32test.h> |
|
45 #include <e32std.h> |
|
46 #include <f32file.h> |
|
47 #include <fntstore.h> |
|
48 #include <s32file.h> |
|
49 |
|
50 #include <graphics/openfontrasterizer.h> |
|
51 #include <graphics/openfontconstants.h> |
|
52 #include <graphics/shapeimpl.h> |
|
53 #include "inputData.h" |
|
54 |
|
55 const TUint32 KDevanagariScriptCode = 0x64657661; |
|
56 const TUint32 KKannadaScriptCode = 0x6B6E6461; |
|
57 const TUint32 KHindiLanguageCode = 0x48494E20; |
|
58 const TUint32 KKannadaLanguageCode = 0x4B414E20; |
|
59 const TUint32 KGujaratiScriptCode = 0x67756A72; |
|
60 const TUint32 KGujaratiLanguageCode = 0x47554A20; |
|
61 const TUint32 KBengaliScriptCode = 0x62656E67; |
|
62 const TUint32 KBengaliLanguageCode = 0x42454E20; |
|
63 const TUint32 KTamilScriptCode = 0x74616D6C; |
|
64 const TUint32 KTamilLanguageCode = 0x54414D20; |
|
65 const TUint32 KTeluguScriptCode = 0x74656C75; |
|
66 const TUint32 KTeluguLanguageCode = 0x54454C20; |
|
67 const TUint32 KGurmukhiScriptCode = 0x67757275; |
|
68 const TUint32 KGurmukhiLanguageCode = 0; |
|
69 const TUint32 KMalayalamScriptCode = 0x6d6c796d; |
|
70 const TUint32 KMalayalamLanguageCode = 0x4d4c5220; |
|
71 |
|
72 |
|
73 _LIT16(KDelimiter, "|"); |
|
74 |
|
75 //RTest Macros etc |
|
76 static RTest TheTest(_L("T_SHAP_createTestData")); |
|
77 static void Check(TInt aValue, TInt aLine) |
|
78 { |
|
79 if(!aValue) |
|
80 { |
|
81 TheTest(EFalse, aLine); |
|
82 } |
|
83 } |
|
84 |
|
85 static void Check(TInt aValue, TInt aExpected, TInt aLine) |
|
86 { |
|
87 if(aValue != aExpected) |
|
88 { |
|
89 RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue); |
|
90 TheTest(EFalse, aLine); |
|
91 } |
|
92 } |
|
93 |
|
94 #define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__) |
|
95 #define TEST(arg) ::Check((arg), __LINE__) |
|
96 |
|
97 /* |
|
98 Used for cleanup of RImplInfoArray implementationArray below |
|
99 This method is stolen from FbsTop.cpp |
|
100 */ |
|
101 LOCAL_C void ResetAndDestroyRImplInfoPtrArray(TAny* aPtr) |
|
102 { |
|
103 RImplInfoPtrArray* array = reinterpret_cast <RImplInfoPtrArray*> (aPtr); |
|
104 array->ResetAndDestroy(); |
|
105 } |
|
106 |
|
107 /* |
|
108 Load all ECOM implemented rasterizer DLLs. |
|
109 This method is stolen from CFbTop::LoadOpenFontLibraries() |
|
110 */ |
|
111 LOCAL_C void LoadOpenFontLibraries(CFontStore* aFontStore) |
|
112 { |
|
113 |
|
114 RImplInfoPtrArray implementationArray; |
|
115 TCleanupItem cleanup(ResetAndDestroyRImplInfoPtrArray, &implementationArray); |
|
116 CleanupStack::PushL(cleanup); |
|
117 TInt error; |
|
118 TInt ecomerror; |
|
119 TInt ecomnotready; |
|
120 TUid uid = {KUidOpenFontRasterizerPlunginInterface}; |
|
121 |
|
122 // Making sure that no race situation arises |
|
123 // If ECom is not ready, give it another chance and try again. if it still doesn't work |
|
124 // after the third try, then it just carries on quietly and fails... |
|
125 for (ecomnotready =0; ecomnotready <3; ecomnotready++) |
|
126 { |
|
127 TRAP(ecomerror,REComSession::ListImplementationsL(uid,implementationArray)); |
|
128 if (!ecomerror) |
|
129 { |
|
130 break; |
|
131 } |
|
132 else |
|
133 { |
|
134 ecomerror = 0; |
|
135 User::After(0); |
|
136 } |
|
137 } |
|
138 |
|
139 const TInt availCount = implementationArray.Count(); |
|
140 for (TInt count=0;count<availCount;++count) |
|
141 { |
|
142 const CImplementationInformation* info = implementationArray[count]; |
|
143 TUid rasterizerUid = info->ImplementationUid(); |
|
144 // Create a rasterizer |
|
145 COpenFontRasterizer* rasterizer=0; |
|
146 TRAP(error,rasterizer = COpenFontRasterizer::NewL(rasterizerUid)); |
|
147 if (!error) |
|
148 { |
|
149 // Install it in the font store. |
|
150 TRAP(error,aFontStore->InstallRasterizerL(rasterizer)); |
|
151 if (error) |
|
152 delete rasterizer; |
|
153 } |
|
154 } |
|
155 CleanupStack::PopAndDestroy(&implementationArray); |
|
156 |
|
157 } |
|
158 |
|
159 LOCAL_C void WriteInputData(RWriteStream& aStream, const TInputData& aInputData) |
|
160 { |
|
161 //output the input data to the file |
|
162 TPtrC input = aInputData.TextInput(); |
|
163 TInt length = input.Length(); |
|
164 TInt start = aInputData.iStart; |
|
165 if (start < 0) |
|
166 start += length; |
|
167 TInt end = aInputData.iEnd; |
|
168 if (end <= 0) |
|
169 end += length; |
|
170 |
|
171 aStream.WriteInt16L(length); |
|
172 |
|
173 aStream.WriteL(aInputData.TypeFaceName()); |
|
174 aStream.WriteL(KDelimiter); |
|
175 |
|
176 aStream.WriteL(aInputData.FontFilename()); |
|
177 aStream.WriteL(KDelimiter); |
|
178 |
|
179 aStream.WriteInt16L(start); |
|
180 aStream.WriteL(KDelimiter); |
|
181 aStream.WriteInt16L(end); |
|
182 aStream.WriteL(KDelimiter); |
|
183 |
|
184 aStream.WriteL(input); |
|
185 aStream.WriteL(KDelimiter); |
|
186 } |
|
187 |
|
188 static void WriteOutputData(RWriteStream& aStream, const TInputData& aInputData, |
|
189 TUint32 aScript, TUint32 aLanguage) |
|
190 { |
|
191 //SHAPE THE TEXT |
|
192 |
|
193 TPtrC input = aInputData.TextInput(); |
|
194 TInt length = input.Length(); |
|
195 TInt start = aInputData.iStart; |
|
196 if (start < 0) |
|
197 start += length; |
|
198 TInt end = aInputData.iEnd; |
|
199 if (end <= 0) |
|
200 end += length; |
|
201 |
|
202 //set up font store and install rasterizer(s) |
|
203 CFontStore* fontStore = CFontStore::NewL(&User::Heap()); |
|
204 fontStore->iKPixelWidthInTwips = 11860; |
|
205 fontStore->iKPixelHeightInTwips = 11860; |
|
206 CleanupStack::PushL(fontStore); |
|
207 LoadOpenFontLibraries(fontStore); |
|
208 |
|
209 //add required font file |
|
210 TRAPD( err, fontStore->AddFileL(aInputData.FontFilename()) ); |
|
211 TEST(err==KErrNone); |
|
212 |
|
213 CBitmapFont* font; |
|
214 TFontSpec fontSpec(aInputData.TypeFaceName(), 12); |
|
215 fontStore->GetNearestFontToDesignHeightInPixels((CFont*&)font, fontSpec); |
|
216 CleanupStack::PushL(font); |
|
217 |
|
218 CShaper* theShaper = NULL; |
|
219 CShaperFactory* shaperFactory = NULL; |
|
220 |
|
221 RImplInfoPtrArray implementationArray; |
|
222 TCleanupItem cleanup(ResetAndDestroyRImplInfoPtrArray, &implementationArray); |
|
223 CleanupStack::PushL(cleanup); |
|
224 TInt error; |
|
225 TInt ecomerror; |
|
226 TInt ecomnotready; |
|
227 TUid uid = {KUidShaperFactoryPlunginInterface}; |
|
228 |
|
229 // Making sure that no race situation arises between FBserv and Ecom |
|
230 // If ECom is not ready, give it another chance and try again. if it still doesn't work |
|
231 // after the third try, then it just carries on quietly and fails... |
|
232 for (ecomnotready =0; ecomnotready <3; ecomnotready++) |
|
233 { |
|
234 TRAP(ecomerror,REComSession::ListImplementationsL(uid,implementationArray)); |
|
235 if (!ecomerror) |
|
236 { |
|
237 break; |
|
238 } |
|
239 else |
|
240 { |
|
241 ecomerror = 0; |
|
242 User::After(0); |
|
243 } |
|
244 } |
|
245 |
|
246 const TInt availCount = implementationArray.Count(); |
|
247 for (TInt count=0;count<availCount;++count) |
|
248 { |
|
249 const CImplementationInformation* info = implementationArray[count]; |
|
250 TUid shaperFactoryUid = info->ImplementationUid(); |
|
251 // Create a shaper factory |
|
252 //CShaperFactory* shaperFactory = 0; |
|
253 TRAP(error,shaperFactory = CShaperFactory::NewL(shaperFactoryUid)); |
|
254 TEST2(error, KErrNone); |
|
255 // Create a shaper |
|
256 TRAPD(err, theShaper = shaperFactory->NewShaperL(font, aScript, aLanguage, &User::Heap())); |
|
257 TEST2(err, KErrNone); |
|
258 } |
|
259 CleanupStack::PopAndDestroy(&implementationArray); |
|
260 |
|
261 CleanupStack::PushL(shaperFactory); |
|
262 CleanupStack::PushL(theShaper); |
|
263 |
|
264 // create the data to be shaped |
|
265 // this uses testData, defined in testData.h |
|
266 CShaper::TInput shaperInput; |
|
267 shaperInput.iText = &input; |
|
268 shaperInput.iStart = start; |
|
269 shaperInput.iEnd = end; |
|
270 |
|
271 TShapeHeader* output = NULL; |
|
272 err = theShaper->ShapeText(output, shaperInput, &User::Heap()); |
|
273 TEST2(err,KErrNone); |
|
274 CleanupStack::PushL(output); |
|
275 |
|
276 |
|
277 //AND FILL THE FILE UP WITH THE RESULTS |
|
278 |
|
279 //first the glyph count |
|
280 aStream.WriteInt16L(output->iGlyphCount); |
|
281 TInt glyphCount(output->iGlyphCount); |
|
282 TInt i; |
|
283 |
|
284 //then the Glyphs |
|
285 TUint32* shapePtr32 = (reinterpret_cast<TUint32*>(&output->iBuffer[0])); |
|
286 for(i=0; i <glyphCount; i++) |
|
287 { |
|
288 aStream.WriteInt32L(*shapePtr32); |
|
289 shapePtr32++; |
|
290 } |
|
291 |
|
292 //then the X and Y positions |
|
293 TUint16* shapePtr16 = (reinterpret_cast<TUint16*>(shapePtr32)); |
|
294 for(i=0; i<glyphCount*2; i++) |
|
295 { |
|
296 aStream.WriteInt16L(*shapePtr16); |
|
297 shapePtr16++; |
|
298 } |
|
299 |
|
300 //then the advance |
|
301 aStream.WriteInt16L(*shapePtr16); |
|
302 shapePtr16++; |
|
303 aStream.WriteInt16L(*shapePtr16); |
|
304 shapePtr16++; |
|
305 |
|
306 //then the indices |
|
307 for(i=0; i<glyphCount; i++) |
|
308 { |
|
309 aStream.WriteInt16L(*shapePtr16); |
|
310 shapePtr16++; |
|
311 } |
|
312 |
|
313 //then the character count |
|
314 aStream.WriteInt16L(output->iCharacterCount); |
|
315 |
|
316 CleanupStack::PopAndDestroy(output); |
|
317 CleanupStack::PopAndDestroy(theShaper); |
|
318 CleanupStack::PopAndDestroy(shaperFactory); |
|
319 REComSession::FinalClose(); |
|
320 |
|
321 CleanupStack::Pop(font); |
|
322 fontStore->ReleaseFont(font); |
|
323 CleanupStack::PopAndDestroy(fontStore); |
|
324 |
|
325 //close the ecom session opened by LoadOpenFontLibraries() |
|
326 REComSession::FinalClose(); |
|
327 } |
|
328 |
|
329 static void MainL() |
|
330 { |
|
331 RFs fs; |
|
332 RFile file; |
|
333 RFileBuf buf; |
|
334 |
|
335 // Create the Devanagari test data files |
|
336 const TInt numberOfTests |
|
337 = sizeof(TNR_Dev_OTInputData)/sizeof(TNR_Dev_OTInputData[0]); |
|
338 for (TInt i = 0; i != numberOfTests; ++i) |
|
339 { |
|
340 const TInputData& data = TNR_Dev_OTInputData[i]; |
|
341 User::LeaveIfError(fs.Connect()); |
|
342 CleanupClosePushL(fs); |
|
343 // note this uses RFile::Create so that users of this utility cannot accidentally write over |
|
344 // files created before. If this test fails, you need to ensure that the file specified by |
|
345 // KFileName is correct, and if so delete it before running this utility. |
|
346 TEST2(file.Create(fs, data.OutputFilename(), EFileWrite), KErrNone); |
|
347 |
|
348 CleanupClosePushL(buf); |
|
349 buf.Attach(file); |
|
350 RWriteStream stream(&buf); |
|
351 |
|
352 //write to the stream |
|
353 WriteInputData(stream, data); |
|
354 WriteOutputData(stream, data, KDevanagariScriptCode, KHindiLanguageCode); |
|
355 |
|
356 CleanupStack::PopAndDestroy(2); //buf, fs |
|
357 } |
|
358 |
|
359 // Create the Kannada test data files |
|
360 const TInt numberOfKanTests = sizeof(Kannada_InputData)/sizeof(Kannada_InputData[0]); |
|
361 for (TInt i = 0; i != numberOfKanTests; i++) |
|
362 { |
|
363 const TInputData& kan_data = Kannada_InputData[i]; |
|
364 User::LeaveIfError(fs.Connect()); |
|
365 CleanupClosePushL(fs); |
|
366 TEST2(file.Create(fs, kan_data.OutputFilename(), EFileWrite), KErrNone); |
|
367 CleanupClosePushL(buf); |
|
368 buf.Attach(file); |
|
369 RWriteStream stream(&buf); |
|
370 |
|
371 WriteInputData(stream, kan_data); |
|
372 WriteOutputData(stream, kan_data, KKannadaScriptCode, KKannadaLanguageCode); |
|
373 |
|
374 CleanupStack::PopAndDestroy(2); |
|
375 } |
|
376 |
|
377 |
|
378 // Create the Gujarati test data files |
|
379 const TInt numberOfGujTests = sizeof(Gujarati_InputData)/sizeof(Gujarati_InputData[0]); |
|
380 for (TInt i = 0; i != numberOfGujTests; i++) |
|
381 { |
|
382 const TInputData& kan_data = Gujarati_InputData[i]; |
|
383 User::LeaveIfError(fs.Connect()); |
|
384 CleanupClosePushL(fs); |
|
385 TEST2(file.Create(fs, kan_data.OutputFilename(), EFileWrite), KErrNone); |
|
386 CleanupClosePushL(buf); |
|
387 buf.Attach(file); |
|
388 RWriteStream stream(&buf); |
|
389 |
|
390 WriteInputData(stream, kan_data); |
|
391 WriteOutputData(stream, kan_data, KGujaratiScriptCode, KGujaratiLanguageCode); |
|
392 |
|
393 CleanupStack::PopAndDestroy(2); |
|
394 } |
|
395 |
|
396 |
|
397 // Create the Bengali test data files |
|
398 const TInt numberOfBenTests = sizeof(Bengali_InputData)/sizeof(Bengali_InputData[0]); |
|
399 for (TInt i = 0; i != numberOfBenTests; i++) |
|
400 { |
|
401 const TInputData& ben_data = Bengali_InputData[i]; |
|
402 User::LeaveIfError(fs.Connect()); |
|
403 CleanupClosePushL(fs); |
|
404 TEST2(file.Create(fs, ben_data.OutputFilename(), EFileWrite), KErrNone); |
|
405 CleanupClosePushL(buf); |
|
406 buf.Attach(file); |
|
407 RWriteStream stream(&buf); |
|
408 |
|
409 WriteInputData(stream, ben_data); |
|
410 WriteOutputData(stream, ben_data, KBengaliScriptCode, KBengaliLanguageCode); |
|
411 |
|
412 CleanupStack::PopAndDestroy(2); |
|
413 } |
|
414 |
|
415 // Create the Tamil test data files |
|
416 const TInt numberOfTamTests = sizeof(Tamil_InputData)/sizeof(Tamil_InputData[0]); |
|
417 for (TInt i = 0; i != numberOfTamTests; i++) |
|
418 { |
|
419 const TInputData& tam_data = Tamil_InputData[i]; |
|
420 User::LeaveIfError(fs.Connect()); |
|
421 CleanupClosePushL(fs); |
|
422 TEST2(file.Create(fs, tam_data.OutputFilename(), EFileWrite), KErrNone); |
|
423 CleanupClosePushL(buf); |
|
424 buf.Attach(file); |
|
425 RWriteStream stream(&buf); |
|
426 |
|
427 WriteInputData(stream, tam_data); |
|
428 WriteOutputData(stream, tam_data, KTamilScriptCode, KTamilLanguageCode); |
|
429 |
|
430 CleanupStack::PopAndDestroy(2); |
|
431 } |
|
432 |
|
433 // Create the Telugu test data files |
|
434 const TInt numberOfTelTests = sizeof(Telugu_InputData)/sizeof(Telugu_InputData[0]); |
|
435 for (TInt i = 0; i != numberOfTelTests; i++) |
|
436 { |
|
437 const TInputData& tel_data = Telugu_InputData[i]; |
|
438 User::LeaveIfError(fs.Connect()); |
|
439 CleanupClosePushL(fs); |
|
440 TEST2(file.Create(fs, tel_data.OutputFilename(), EFileWrite), KErrNone); |
|
441 CleanupClosePushL(buf); |
|
442 buf.Attach(file); |
|
443 RWriteStream stream(&buf); |
|
444 |
|
445 WriteInputData(stream, tel_data); |
|
446 WriteOutputData(stream, tel_data, KTeluguScriptCode, KTeluguLanguageCode); |
|
447 |
|
448 CleanupStack::PopAndDestroy(2); |
|
449 } |
|
450 |
|
451 // Create the Gurmukhi test data files |
|
452 const TInt numberOfGurTests = sizeof(Gurmukhi_InputData)/sizeof(Gurmukhi_InputData[0]); |
|
453 for (TInt i = 0; i != numberOfGurTests; i++) |
|
454 { |
|
455 const TInputData& tel_data = Gurmukhi_InputData[i]; |
|
456 User::LeaveIfError(fs.Connect()); |
|
457 CleanupClosePushL(fs); |
|
458 TEST2(file.Create(fs, tel_data.OutputFilename(), EFileWrite), KErrNone); |
|
459 CleanupClosePushL(buf); |
|
460 buf.Attach(file); |
|
461 RWriteStream stream(&buf); |
|
462 |
|
463 WriteInputData(stream, tel_data); |
|
464 WriteOutputData(stream, tel_data, KGurmukhiScriptCode, KGurmukhiLanguageCode); |
|
465 |
|
466 CleanupStack::PopAndDestroy(2); |
|
467 } |
|
468 |
|
469 // Create the Malayalam test data files |
|
470 const TInt numberOfMalaTests = sizeof(Malayalam_InputData)/sizeof(Malayalam_InputData[0]); |
|
471 for (TInt i = 0; i != numberOfMalaTests; i++) |
|
472 { |
|
473 const TInputData& tel_data = Malayalam_InputData[i]; |
|
474 User::LeaveIfError(fs.Connect()); |
|
475 CleanupClosePushL(fs); |
|
476 TEST2(file.Create(fs, tel_data.OutputFilename(), EFileWrite), KErrNone); |
|
477 CleanupClosePushL(buf); |
|
478 buf.Attach(file); |
|
479 RWriteStream stream(&buf); |
|
480 |
|
481 WriteInputData(stream, tel_data); |
|
482 WriteOutputData(stream, tel_data, KMalayalamScriptCode, KMalayalamLanguageCode); |
|
483 |
|
484 CleanupStack::PopAndDestroy(2); |
|
485 } |
|
486 } |
|
487 |
|
488 TInt E32Main() |
|
489 { |
|
490 __UHEAP_MARK; |
|
491 |
|
492 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
493 if(!cleanup) |
|
494 return KErrNoMemory; |
|
495 |
|
496 TRAPD(err, MainL()); |
|
497 TEST2(err, KErrNone); |
|
498 |
|
499 delete cleanup; |
|
500 __UHEAP_MARKEND; |
|
501 |
|
502 return KErrNone; |
|
503 } |
|
504 |