1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *******************************************************************************
3b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius *   Copyright (C) 1999-2014, International Business Machines
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *   Corporation and others.  All Rights Reserved.
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *******************************************************************************
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *   file name:  letest.cpp
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *   created on: 11/06/2000
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *   created by: Eric R. Mader
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/uclean.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/uchar.h"
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/unistr.h"
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/uscript.h"
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/putil.h"
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/ctest.h"
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "layout/LETypes.h"
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "layout/LEScripts.h"
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "layout/LayoutEngine.h"
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "layout/ParagraphLayout.h"
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "layout/RunArrays.h"
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "PortableFontInstance.h"
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "SimpleFontInstance.h"
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "letsutil.h"
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "letest.h"
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "xmlparser.h"
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "putilimp.h" // for uprv_getUTCtime()
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <stdlib.h>
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <string.h>
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_USE
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define CH_COMMA 0x002C
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_BEGIN
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV ScriptTest(void)
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
4985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if ((int)scriptCodeCount != (int)USCRIPT_CODE_LIMIT) {
5085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        log_err("ScriptCodes::scriptCodeCount = %d, but UScriptCode::USCRIPT_CODE_LIMIT = %d\n", scriptCodeCount, USCRIPT_CODE_LIMIT);
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV ParamTest(void)
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEErrorCode status = LE_NO_ERROR;
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    SimpleFontInstance *font = new SimpleFontInstance(12, status);
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status);
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEGlyphID *glyphs    = NULL;
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32  *indices   = NULL;
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    float     *positions = NULL;
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32   glyphCount = 0;
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
64b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->getGlyphCount();
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (glyphCount != 0) {
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount);
67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphs    = NEW_ARRAY(LEGlyphID, glyphCount + 10);
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    indices   = NEW_ARRAY(le_int32, glyphCount + 10);
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    positions = NEW_ARRAY(float, glyphCount + 10);
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphs(NULL, status);
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphs(glyphs, status);
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_NO_LAYOUT_ERROR) {
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphs(NULL, 0xFF000000L, status);
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphs(NULL, 0xFF000000L, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphs(glyphs, 0xFF000000L, status);
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_NO_LAYOUT_ERROR) {
97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphs(glyphs, 0xFF000000L, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getCharIndices(NULL, status);
102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getCharIndices(indices, status);
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_NO_LAYOUT_ERROR) {
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getCharIndices(NULL, 1024, status);
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getCharIndices(indices, 1024, status);
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_NO_LAYOUT_ERROR) {
125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphPositions(NULL, status);
130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphPositions(positions, status);
137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_NO_LAYOUT_ERROR) {
139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    DELETE_ARRAY(positions);
143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    DELETE_ARRAY(indices);
144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    DELETE_ARRAY(glyphs);
145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status);
148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEUnicode chars[] = {
154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634,                 // MEM ALIF KAF NOON TEH WAW SHEEN
156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E                   // " text."
157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    };
158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status);
161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status);
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->layoutChars(chars, 8, 6, -1, TRUE, 0.0, 0.0, status);
175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status);
182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    float x = 0.0, y = 0.0;
188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status);
191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status)) {
193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto bail;
195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphPosition(-1, x, y, status);
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphPosition(glyphCount + 1, x, y, status);
205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querubail:
211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete engine;
212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete font;
213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_BEGIN
217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV FactoryTest(void)
218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEErrorCode status = LE_NO_ERROR;
220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    SimpleFontInstance *font = new SimpleFontInstance(12, status);
221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LayoutEngine *engine = NULL;
222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for(le_int32 scriptCode = 0; scriptCode < scriptCodeCount; scriptCode += 1) {
224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = LE_NO_ERROR;
225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        engine = LayoutEngine::layoutEngineFactory(font, scriptCode, -1, status);
226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (LE_FAILURE(status)) {
228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode)scriptCode));
229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete engine;
232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete font;
235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_BEGIN
239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV AccessTest(void)
240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEErrorCode status = LE_NO_ERROR;
242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    SimpleFontInstance *font = new SimpleFontInstance(12, status);
243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status);
244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 glyphCount;
245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEGlyphID glyphs[6], extraBitGlyphs[6];;
246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 biasedIndices[6], indices[6], glyph;
247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    float positions[6 * 2 + 2];
248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEUnicode chars[] = {
249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634,                 // MEM ALIF KAF NOON TEH WAW SHEEN
251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E                   // " text."
252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    };
253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status)) {
255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Could not create LayoutEngine.\n");
256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto bail;
257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status);
260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status) || glyphCount != 6) {
262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto bail;
264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphs(glyphs, status);
267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getCharIndices(indices, status);
268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphPositions(positions, status);
269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status)) {
271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Could not get glyph, indices and position arrays.\n");
272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto bail;
273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getGlyphs(extraBitGlyphs, 0xFF000000L, status);
276b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
277b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status)) {
278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("getGlyphs(extraBitGlyphs, 0xFF000000L, status); failed.\n");
279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for(glyph = 0; glyph < glyphCount; glyph += 1) {
281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (extraBitGlyphs[glyph] != (glyphs[glyph] | 0xFF000000L)) {
282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                log_err("extraBigGlyphs[%d] != glyphs[%d] | 0xFF000000L: %8X, %8X\n",
283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    glyph, glyph, extraBitGlyphs[glyph], glyphs[glyph]);
284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    engine->getCharIndices(biasedIndices, 1024, status);
291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status)) {
293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (glyph = 0; glyph < glyphCount; glyph += 1) {
296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (biasedIndices[glyph] != (indices[glyph] + 1024)) {
297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n",
298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    glyph, glyph, biasedIndices[glyph], indices[glyph]);
299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = LE_NO_ERROR;
305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (glyph = 0; glyph <= glyphCount; glyph += 1) {
306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        float x = 0.0, y = 0.0;
307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        engine->getGlyphPosition(glyph, x, y, status);
309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (LE_FAILURE(status)) {
311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph);
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            break;
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (x != positions[glyph*2] || y != positions[glyph*2 + 1]) {
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n",
317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                glyph, x, y, positions[glyph*2], positions[glyph*2 + 1]);
318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            break;
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querubail:
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete engine;
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete font;
325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querule_bool compareResults(const char *testID, TestResult *expected, TestResult *actual)
329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */
331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (actual->glyphCount != expected->glyphCount) {
332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            testID, expected->glyphCount, actual->glyphCount);
334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 i;
338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (i = 0; i < actual->glyphCount; i += 1) {
340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (actual->glyphs[i] != expected->glyphs[i]) {
341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                testID, i, expected->glyphs[i], actual->glyphs[i]);
343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (i = 0; i < actual->glyphCount; i += 1) {
348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (actual->indices[i] != expected->indices[i]) {
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                testID, i, expected->indices[i], actual->indices[i]);
351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (i = 0; i <= actual->glyphCount; i += 1) {
356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double xError = uprv_fabs(actual->positions[i * 2] - expected->positions[i * 2]);
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (xError > 0.0001) {
359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n",
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                testID, i, expected->positions[i * 2], actual->positions[i * 2]);
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double yError = uprv_fabs(actual->positions[i * 2 + 1] - expected->positions[i * 2 + 1]);
365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (yError < 0) {
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            yError = -yError;
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (yError > 0.0001) {
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n",
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                testID, i, expected->positions[i * 2 + 1], actual->positions[i * 2 + 1]);
373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
374b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return TRUE;
378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void checkFontVersion(PortableFontInstance *fontInstance, const char *testVersionString,
381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             le_uint32 testChecksum, const char *testID)
382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_uint32 fontChecksum = fontInstance->getFontChecksum();
384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fontChecksum != testChecksum) {
386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const char *fontVersionString = fontInstance->getNameString(NAME_VERSION_STRING,
387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
38885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        const LEUnicode *uFontVersionString = NULL;
38985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
39085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            // The standard recommends that the Macintosh Roman/English name string be present, but
39185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            // if it's not, try the Microsoft Unicode/English string.
39285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            if (fontVersionString == NULL) {
39385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                uFontVersionString = fontInstance->getUnicodeNameString(NAME_VERSION_STRING,
39485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    PLATFORM_MICROSOFT, MICROSOFT_UNICODE_BMP, MICROSOFT_ENGLISH);
39585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            }
396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_info("Test %s: this may not be the same font used to generate the test data.\n", testID);
39885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
39985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (uFontVersionString != NULL) {
40085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            log_info("Your font's version string is \"%S\"\n", uFontVersionString);
40185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            fontInstance->deleteNameString(uFontVersionString);
40285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        } else {
40385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            log_info("Your font's version string is \"%s\"\n", fontVersionString);
40485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            fontInstance->deleteNameString(fontVersionString);
40585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
40685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_info("The expected version string is \"%s\"\n", testVersionString);
408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_info("If you see errors, they may be due to the version of the font you're using.\n");
409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* Returns the path to icu/source/test/testdata/ */
413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst char *getSourceTestData() {
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *srcDataDir = NULL;
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef U_TOPSRCDIR
41659d709d503bab6e2b61931737e662dd293b40578ccornelius    srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#else
418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r");
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (f != NULL) {
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* We're in icu/source/test/letest/ */
423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fclose(f);
424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* We're in icu/source/test/letest/(Debug|Release) */
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return srcDataDir;
431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst char *getPath(char buffer[2048], const char *filename) {
434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *testDataDirectory = getSourceTestData();
435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    strcpy(buffer, testDataDirectory);
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    strcat(buffer, filename);
438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return buffer;
440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querule_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize)
443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offset = -1;
445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    arraySize = 1;
447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        arraySize += 1;
449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
451b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_uint32 *array = NEW_ARRAY(le_uint32, arraySize);
452b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char number[16];
453b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 count = 0;
454b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 start = 0, end = 0;
455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 len = 0;
456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // trim leading whitespace
458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(u_isUWhiteSpace(numbers[start])) {
459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        start += 1;
460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        number[len] = '\0';
465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        start = end + 1;
466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        sscanf(number, "%x", &array[count++]);
468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
469b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // trim whitespace following the comma
470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(u_isUWhiteSpace(numbers[start])) {
471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            start += 1;
472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // trim trailing whitespace
476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    end = numbers.length();
477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(u_isUWhiteSpace(numbers[end - 1])) {
478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        end -= 1;
479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    number[len] = '\0';
483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    sscanf(number, "%x", &array[count]);
484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return array;
486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querufloat *getFloatArray(const UnicodeString &numbers, int32_t &arraySize)
489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offset = -1;
491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    arraySize = 1;
493b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
494b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        arraySize += 1;
495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    float *array = NEW_ARRAY(float, arraySize);
498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char number[32];
499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 count = 0;
500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 start = 0, end = 0;
501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 len = 0;
502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // trim leading whitespace
504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(u_isUWhiteSpace(numbers[start])) {
505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        start += 1;
506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        number[len] = '\0';
511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        start = end + 1;
512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        sscanf(number, "%f", &array[count++]);
514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // trim whiteapce following the comma
516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(u_isUWhiteSpace(numbers[start])) {
517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            start += 1;
518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(u_isUWhiteSpace(numbers[start])) {
522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        start += 1;
523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // trim trailing whitespace
526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    end = numbers.length();
527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(u_isUWhiteSpace(numbers[end - 1])) {
528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        end -= 1;
529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
530b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
531b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    number[len] = '\0';
533b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    sscanf(number, "%f", &array[count]);
534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return array;
536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruLEFontInstance *openFont(const char *fontName, const char *checksum, const char *version, const char *testID)
539b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
540b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char path[2048];
541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    PortableFontInstance *font;
542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEErrorCode fontStatus = LE_NO_ERROR;
543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    font = new PortableFontInstance(getPath(path, fontName), 12, fontStatus);
546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(fontStatus)) {
548b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_info("Test %s: can't open font %s - test skipped.\n", testID, fontName);
549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete font;
550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        le_uint32 cksum = 0;
553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        sscanf(checksum, "%x", &cksum);
555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        checkFontVersion(font, version, cksum, testID);
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return font;
560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_BEGIN
563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV DataDrivenTest(void)
564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
565b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_REGULAR_EXPRESSIONS
566b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
567b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char path[2048];
568b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *testFilePath = getPath(path, "letest.xml");
569b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
570b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UXMLParser  *parser = UXMLParser::createParser(status);
571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UXMLElement *root   = parser->parseFile(testFilePath, status);
572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (root == NULL) {
574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Could not open the test data file: %s\n", testFilePath);
575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete parser;
576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString test_case        = UNICODE_STRING_SIMPLE("test-case");
580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString test_text        = UNICODE_STRING_SIMPLE("test-text");
581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString test_font        = UNICODE_STRING_SIMPLE("test-font");
582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString result_glyphs    = UNICODE_STRING_SIMPLE("result-glyphs");
583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString result_indices   = UNICODE_STRING_SIMPLE("result-indices");
584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions");
585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // test-case attributes
587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString id_attr     = UNICODE_STRING_SIMPLE("id");
588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString script_attr = UNICODE_STRING_SIMPLE("script");
589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString lang_attr   = UNICODE_STRING_SIMPLE("lang");
590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // test-font attributes
592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString name_attr   = UNICODE_STRING_SIMPLE("name");
593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString ver_attr    = UNICODE_STRING_SIMPLE("version");
594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString cksum_attr  = UNICODE_STRING_SIMPLE("checksum");
595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const UXMLElement *testCase;
597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t tc = 0;
598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while((testCase = root->nextChildElement(tc)) != NULL) {
600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (testCase->getTagName().compare(test_case) == 0) {
601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char *id = getCString(testCase->getAttribute(id_attr));
602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char *script = getCString(testCase->getAttribute(script_attr));
603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char *lang   = getCString(testCase->getAttribute(lang_attr));
604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            LEFontInstance *font = NULL;
605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            const UXMLElement *element;
606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t ec = 0;
607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t charCount = 0;
608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t typoFlags = 3; // kerning + ligatures...
609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UScriptCode scriptCode;
610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            le_int32 languageCode = -1;
611b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UnicodeString text, glyphs, indices, positions;
612b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t glyphCount = 0, indexCount = 0, positionCount = 0;
613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TestResult expected = {0, NULL, NULL, NULL};
614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TestResult actual   = {0, NULL, NULL, NULL};
615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            LEErrorCode success = LE_NO_ERROR;
616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            LayoutEngine *engine = NULL;
617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            uscript_getCode(script, &scriptCode, 1, &status);
619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (LE_FAILURE(status)) {
620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                log_err("invalid script name: %s.\n", script);
621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto free_c_strings;
622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
624b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (lang != NULL) {
625b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                languageCode = getLanguageCode(lang);
626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (languageCode < 0) {
628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    log_err("invalid language name: %s.\n", lang);
629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    goto free_c_strings;
630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
633b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while((element = testCase->nextChildElement(ec)) != NULL) {
634b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UnicodeString tag = element->getTagName();
635b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // TODO: make sure that each element is only used once.
637b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (tag.compare(test_font) == 0) {
638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    char *fontName  = getCString(element->getAttribute(name_attr));
639b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    char *fontVer   = getCString(element->getAttribute(ver_attr));
640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    char *fontCksum = getCString(element->getAttribute(cksum_attr));
641b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    font = openFont(fontName, fontCksum, fontVer, id);
643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    freeCString(fontCksum);
644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    freeCString(fontVer);
645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    freeCString(fontName);
646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (font == NULL) {
648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        // warning message already displayed...
649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        goto free_c_strings;
650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else if (tag.compare(test_text) == 0) {
652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    text = element->getText(TRUE);
653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    charCount = text.length();
654b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else if (tag.compare(result_glyphs) == 0) {
655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    glyphs = element->getText(TRUE);
656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else if (tag.compare(result_indices) == 0) {
657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    indices = element->getText(TRUE);
658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else if (tag.compare(result_positions) == 0) {
659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    positions = element->getText(TRUE);
660b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
661b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // an unknown tag...
662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    char *cTag = getCString(&tag);
663b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag);
665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    freeCString(cTag);
666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // TODO: make sure that the font, test-text, result-glyphs, result-indices and result-positions
670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // have all been provided
671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (font == NULL) {
672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                LEErrorCode fontStatus = LE_NO_ERROR;
673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                font = new SimpleFontInstance(12, fontStatus);
675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                typoFlags |= 0x80000000L;  // use CharSubstitutionFilter...
676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            expected.glyphs    = (LEGlyphID *) getHexArray(glyphs, glyphCount);
679b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            expected.indices   = (le_int32 *)  getHexArray(indices, indexCount);
680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            expected.positions = getFloatArray(positions, positionCount);
681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            expected.glyphCount = glyphCount;
683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) {
685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    id, charCount, glyphCount, indexCount, positionCount);
687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto free_expected;
688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            };
689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            engine = LayoutEngine::layoutEngineFactory(font, scriptCode, languageCode, typoFlags, success);
691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (LE_FAILURE(success)) {
693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                log_err("Test %s: could not create a LayoutEngine.\n", id);
694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto free_expected;
695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            actual.glyphCount = engine->layoutChars(text.getBuffer(), 0, charCount, charCount, getRTL(text), 0, 0, success);
698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            actual.glyphs    = NEW_ARRAY(LEGlyphID, actual.glyphCount);
700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            actual.indices   = NEW_ARRAY(le_int32, actual.glyphCount);
701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2);
702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            engine->getGlyphs(actual.glyphs, success);
704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            engine->getCharIndices(actual.indices, success);
705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            engine->getGlyphPositions(actual.positions, success);
706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            compareResults(id, &expected, &actual);
708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
709b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            DELETE_ARRAY(actual.positions);
710b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            DELETE_ARRAY(actual.indices);
711b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            DELETE_ARRAY(actual.glyphs);
712b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
713b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete engine;
714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
71559d709d503bab6e2b61931737e662dd293b40578ccornelius            log_verbose("OK - %4d glyphs: %s\n", actual.glyphCount, id);
716b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querufree_expected:
717b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            DELETE_ARRAY(expected.positions);
718b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            DELETE_ARRAY(expected.indices);
719b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            DELETE_ARRAY(expected.glyphs);
720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
721b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete font;
722b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
723b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querufree_c_strings:
724b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            freeCString(lang);
725b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            freeCString(script);
726b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            freeCString(id);
727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
728b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
730b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete root;
731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete parser;
732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
733b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
736b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_BEGIN
737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * From ticket:5923:
739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Build a paragraph that contains a mixture of left to right and right to left text.
741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Break it into multiple lines and make sure that the glyphToCharMap for run in each
742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * line is correct.
743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Note: it might be a good idea to also check the glyphs and positions for each run,
745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * that we get the expected number of runs per line and that the line breaks are where
746b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * we expect them to be. Really, it would be a good idea to make a whole test suite
747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * for ParagraphLayout.
748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV GlyphToCharTest(void)
750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
751fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#if !UCONFIG_NO_BREAK_ITERATION
752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEErrorCode status = LE_NO_ERROR;
753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEFontInstance *font;
754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    FontRuns fontRuns(0);
755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ParagraphLayout *paragraphLayout;
756b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const ParagraphLayout::Line *line;
757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /*
758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * This is the same text that's in <icu>/source/samples/layout/Sample.txt
759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     */
760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEUnicode chars[] = {
761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079,
762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e,
763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061,
764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077,
765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065,
766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f,
767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079,
768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065,
769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072,
770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e,
771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067,
772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020,
773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020,
774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020,
775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020,
776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020,
777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939,
778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054,
779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22,
780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072,
781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644,
782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020,
783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061,
784b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020,
785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020,
786b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069,
787b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020,
788b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074,
789b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926,
790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917,
791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f,
792b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941,
793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020,
794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930,
795b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909,
796b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d,
797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930,
798b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d,
799b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938,
800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941,
801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020,
802b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a,
803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d,
804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915,
805b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902,
806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027,
807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070,
808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f,
809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020,
810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020,
811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069,
812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b,
813b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645,
814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633,
815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645,
816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627,
817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645,
818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020,
819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648,
820b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020,
821b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628,
822b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f,
823b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627,
824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644,
825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642,
827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627,
828b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643,
829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646,
830b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626,
831b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638,
832b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641,
833b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a,
834b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644,
835b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644,
836b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648,
837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020,
838b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641,
839b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644,
841b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627,
842b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627,
843b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020,
844b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065,
845b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d,
846b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073,
847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074,
848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e,
849b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069,
850b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51,
851b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04,
852b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35,
853b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39,
854b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32,
855b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d,
856b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31,
857b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40,
858b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44,
859b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32,
860b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22,
861b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a,
862b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27,
863b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07,
864b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32,
865b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32,
866b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d,
867b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27,
868b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40,
869b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17,
870b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21,
871b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        0x0e25, 0x0e4c
872b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    };
873b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 charCount = LE_ARRAY_SIZE(chars);
874b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 charIndex = 0, lineNumber = 1;
875b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const float lineWidth = 600;
876b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
877b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    font = new SimpleFontInstance(12, status);
878b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
879b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status)) {
880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto finish;
881b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
882b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
883b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fontRuns.add(font, charCount);
884b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
885b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    paragraphLayout = new ParagraphLayout(chars, charCount, &fontRuns, NULL, NULL, NULL, 0, FALSE, status);
886b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
887b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (LE_FAILURE(status)) {
888b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto close_font;
889b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
890b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
891b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    paragraphLayout->reflow();
892b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while ((line = paragraphLayout->nextLine(lineWidth)) != NULL) {
893b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        le_int32 runCount = line->countRuns();
894b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
895b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for(le_int32 run = 0; run < runCount; run += 1) {
896b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            const ParagraphLayout::VisualRun *visualRun = line->getVisualRun(run);
897b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            le_int32 glyphCount = visualRun->getGlyphCount();
898b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            const le_int32 *glyphToCharMap = visualRun->getGlyphToCharMap();
899b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
900b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (visualRun->getDirection() == UBIDI_RTL) {
901b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                /*
902b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * For a right to left run, make sure that the character indices
903b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * increase from the right most glyph to the left most glyph. If
904b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * there are any one to many glyph substitutions, we might get several
905b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * glyphs in a row with the same character index.
906b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 */
907b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                for(le_int32 i = glyphCount - 1; i >= 0; i -= 1) {
908b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    le_int32 ix = glyphToCharMap[i];
909b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
910b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (ix != charIndex) {
911b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (ix != charIndex - 1) {
912b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            log_err("Bad glyph to char index for glyph %d on line %d: expected %d, got %d\n",
913b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                i, lineNumber, charIndex, ix);
914b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            goto close_paragraph; // once there's one error, we can't count on anything else...
915b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
916b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    } else {
917b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        charIndex += 1;
918b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
919b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
920b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
921b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                /*
922b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * We can't just check the order of the character indices
923b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * for left to right runs because Indic text might have been
924b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * reordered. What we can do is find the minimum and maximum
925b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * character indices in the run and make sure that the minimum
926b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 * is equal to charIndex and then advance charIndex to the maximum.
927b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 */
928b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                le_int32 minIndex = 0x7FFFFFFF, maxIndex = -1;
929b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
930b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                for(le_int32 i = 0; i < glyphCount; i += 1) {
931b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    le_int32 ix = glyphToCharMap[i];
932b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (ix > maxIndex) {
934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        maxIndex = ix;
935b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
936b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
937b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (ix < minIndex) {
938b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        minIndex = ix;
939b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
940b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
942b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (minIndex != charIndex) {
943b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    log_err("Bad minIndex for run %d on line %d: expected %d, got %d\n",
944b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        run, lineNumber, charIndex, minIndex);
945b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    goto close_paragraph; // once there's one error, we can't count on anything else...
946b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
947b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
948b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                charIndex = maxIndex + 1;
949b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
950b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
951b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
952b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        lineNumber += 1;
953b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
954b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclose_paragraph:
955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete paragraphLayout;
956b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclose_font:
958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete font;
959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querufinish:
961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return;
962fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif
963b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
964b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
965b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
966b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void addAllTests(TestNode **root)
967b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
968b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addTest(root, &ScriptTest,      "api/ScriptTest");
969b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addTest(root, &ParamTest,       "api/ParameterTest");
970b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addTest(root, &FactoryTest,     "api/FactoryTest");
971b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addTest(root, &AccessTest,      "layout/AccessTest");
972b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addTest(root, &DataDrivenTest,  "layout/DataDrivenTest");
973b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addTest(root, &GlyphToCharTest, "paragraph/GlyphToCharTest");
974b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
975b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addCTests(root);
976b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
977b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
978b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* returns the path to icu/source/data/out */
979b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char *ctest_dataOutDir()
980b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
981b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static const char *dataOutDir = NULL;
982b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
983b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(dataOutDir) {
984b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return dataOutDir;
985b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
986b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
987b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
988b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              to point to the top of the build hierarchy, which may or
989b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              may not be the same as the source directory, depending on
990b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              the configure options used.  At any rate,
991b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              set the data path to the built data from this directory.
992b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              The value is complete with quotes, so it can be used
993b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              as-is as a string constant.
994b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    */
995b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined (U_TOPBUILDDIR)
996b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
9978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        dataOutDir = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
998b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
999b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#else
1000b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1001b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* On Windows, the file name obtained from __FILE__ includes a full path.
1002b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
1003b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     *             Change to    "wherever\icu\source\data"
1004b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     */
1005b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
1006b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        static char p[sizeof(__FILE__) + 20];
1007b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        char *pBackSlash;
1008b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int i;
1009b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1010b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        strcpy(p, __FILE__);
1011b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* We want to back over three '\' chars.                            */
1012b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /*   Only Windows should end up here, so looking for '\' is safe.   */
1013b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (i=1; i<=3; i++) {
1014b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
1015b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (pBackSlash != NULL) {
1016b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                *pBackSlash = 0;        /* Truncate the string at the '\'   */
1017b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1018b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1019b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1020b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (pBackSlash != NULL) {
1021b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* We found and truncated three names from the path.
1022b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             *  Now append "source\data" and set the environment
1023b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             */
1024b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
1025b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            dataOutDir = p;
1026b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1027b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        else {
1028b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* __FILE__ on MSVC7 does not contain the directory */
1029b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
1030b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (file) {
1031b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                fclose(file);
1032b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1033b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1034b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            else {
1035b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1036b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1037b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1038b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1039b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
1040b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1041b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return dataOutDir;
1042b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1043b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1044b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  ctest_setICU_DATA  - if the ICU_DATA environment variable is not already
1045b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *                       set, try to deduce the directory in which ICU was built,
1046b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *                       and set ICU_DATA to "icu/source/data" in that location.
1047b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *                       The intent is to allow the tests to have a good chance
1048b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *                       of running without requiring that the user manually set
1049b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *                       ICU_DATA.  Common data isn't a problem, since it is
1050b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *                       picked up via a static (build time) reference, but the
1051b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *                       tests dynamically load some data.
1052b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1053b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void ctest_setICU_DATA() {
1054b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1055b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* No location for the data dir was identifiable.
1056b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     *   Add other fallbacks for the test data location here if the need arises
1057b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     */
1058b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (getenv("ICU_DATA") == NULL) {
1059b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* If ICU_DATA isn't set, set it to the usual location */
1060b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        u_setDataDirectory(ctest_dataOutDir());
1061b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1062b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1063b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1064b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint main(int argc, char* argv[])
1065b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1066b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t nerrors = 0;
1067b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TestNode *root = NULL;
1068b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode errorCode = U_ZERO_ERROR;
1069b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate startTime, endTime;
1070b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t diffTime;
1071b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1072b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    startTime = uprv_getUTCtime();
1073b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
107485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (!initArgs(argc, argv, NULL, NULL)) {
107585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        /* Error already displayed. */
107685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return -1;
107785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
107885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
1079b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Check whether ICU will initialize without forcing the build data directory into
1080b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    *  the ICU_DATA path.  Success here means either the data dll contains data, or that
1081b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    *  this test program was run with ICU_DATA set externally.  Failure of this check
1082b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    *  is normal when ICU data is not packaged into a shared library.
1083b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    *
1084b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    *  Whether or not this test succeeds, we want to cleanup and reinitialize
1085b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    *  with a data path so that data loading from individual files can be tested.
1086b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    */
1087b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_init(&errorCode);
1088b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1089b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(errorCode)) {
1090b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fprintf(stderr,
1091b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            "#### Note:  ICU Init without build-specific setDataDirectory() failed.\n");
1092b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1093b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1094b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_cleanup();
1095b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    errorCode = U_ZERO_ERROR;
1096b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
109785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (!initArgs(argc, argv, NULL, NULL)) {
109885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        /* Error already displayed. */
109985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return -1;
110085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
110185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho/* Initialize ICU */
1102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ctest_setICU_DATA();    /* u_setDataDirectory() must happen Before u_init() */
1103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_init(&errorCode);
1104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(errorCode)) {
1106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fprintf(stderr,
1107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
1108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            "*** Check the ICU_DATA environment variable and \n"
1109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
1110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 1;
1111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addAllTests(&root);
111485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    nerrors = runTestRequest(root, argc, argv);
1115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    cleanUpTestTree(root);
1117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_cleanup();
1118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    endTime = uprv_getUTCtime();
1120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    diffTime = (int32_t)(endTime - startTime);
1121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
1122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
1123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
1124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
1125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        (int)(diffTime%U_MILLIS_PER_SECOND));
1126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return nerrors;
1128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1130