usp10.c 54.8 KB
Newer Older
1 2 3 4
/*
 * Implementation of Uniscribe Script Processor (usp10.dll)
 *
 * Copyright 2005 Steven Edwards for CodeWeavers
5
 * Copyright 2006 Hans Leidekker
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22 23 24 25 26 27
 *
 * Notes:
 * Uniscribe allows for processing of complex scripts such as joining
 * and filtering characters and bi-directional text with custom line breaks.
 */

#include <stdarg.h>

28 29
#include "windef.h"
#include "winbase.h"
30
#include "wingdi.h"
31
#include "winuser.h"
32
#include "winnls.h"
33
#include "usp10.h"
34 35

#include "wine/debug.h"
36
#include "wine/unicode.h"
37 38 39

WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
static const SCRIPT_PROPERTIES props[] =
{
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 8, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 25, 0, 0, 0, 0, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 42, 0, 0, 0, 0, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 9, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 18, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 18, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 9, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 13, 0, 1, 0, 1, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 13, 0, 1, 0, 0, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 1, 0, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
    { 1, 1, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
    { 41, 1, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 32, 1, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 90, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0 },
    { 30, 0, 1, 1, 1, 222, 0, 0, 1, 0, 1, 0, 0, 0, 1 },
    { 30, 1, 1, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 30, 0, 1, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 57, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 57, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 73, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 73, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 69, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 69, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 69, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 70, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 70, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 71, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 71, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 72, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 72, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 74, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 74, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 75, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 75, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 76, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 76, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 81, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0 },
    { 81, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 84, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0 },
    { 84, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 83, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 83, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 85, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
    { 85, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 80, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 80, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 94, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 94, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 101, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 93, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 92, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 9, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 91, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 9, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
    { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};

static const SCRIPT_PROPERTIES *script_props[] =
{
    &props[0], &props[1], &props[2], &props[3],
    &props[4], &props[5], &props[6], &props[7],
    &props[8], &props[9], &props[11], &props[12],
    &props[13], &props[14], &props[15], &props[16],
    &props[17], &props[18], &props[19], &props[20],
    &props[21], &props[22], &props[23], &props[24],
    &props[25], &props[26], &props[27], &props[28],
    &props[29], &props[30], &props[31], &props[32],
    &props[33], &props[34], &props[35], &props[36],
    &props[37], &props[38], &props[39], &props[40],
    &props[41], &props[42], &props[43], &props[44],
    &props[45], &props[46], &props[47], &props[48],
    &props[49], &props[50], &props[51], &props[52],
    &props[53], &props[54], &props[55], &props[56],
    &props[57], &props[58], &props[59], &props[60],
    &props[61], &props[62], &props[63], &props[64],
    &props[65], &props[66], &props[67], &props[68],
    &props[69], &props[70], &props[71], &props[72],
    &props[73]
};
140

141 142 143 144 145
#define GLYPH_BLOCK_SHIFT 8
#define GLYPH_BLOCK_SIZE  (1UL << GLYPH_BLOCK_SHIFT)
#define GLYPH_BLOCK_MASK  (GLYPH_BLOCK_SIZE - 1)
#define GLYPH_MAX         65536

146
typedef struct {
147
    LOGFONTW lf;
148
    TEXTMETRICW tm;
149 150
    WORD *glyphs[GLYPH_MAX / GLYPH_BLOCK_SIZE];
    ABC *widths[GLYPH_MAX / GLYPH_BLOCK_SIZE];
151
} ScriptCache;
152

153 154 155 156 157 158 159 160 161 162 163
typedef struct {
    int numGlyphs;
    WORD* glyphs;
    WORD* pwLogClust;
    int* piAdvance;
    SCRIPT_VISATTR* psva;
    GOFFSET* pGoffset;
    ABC* abc;
} StringGlyphs;

typedef struct {
164
    HDC hdc;
165
    BOOL invalid;
166
    int clip_len;
167
    ScriptCache *sc;
168 169 170 171 172
    int cItems;
    int cMaxGlyphs;
    SCRIPT_ITEM* pItem;
    int numItems;
    StringGlyphs* glyphs;
173
    SCRIPT_LOGATTR* logattrs;
174 175 176
    SIZE* sz;
} StringAnalysis;

177
static inline void *heap_alloc(SIZE_T size)
178 179 180 181
{
    return HeapAlloc(GetProcessHeap(), 0, size);
}

182
static inline void *heap_alloc_zero(SIZE_T size)
183 184 185 186
{
    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
}

187
static inline void *heap_realloc_zero(LPVOID mem, SIZE_T size)
188 189 190 191
{
    return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
}

192
static inline BOOL heap_free(LPVOID mem)
193
{
194
    return HeapFree(GetProcessHeap(), 0, mem);
195 196
}

197
static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
198
{
199
    return ((ScriptCache *)*psc)->tm.tmDefaultChar;
200 201
}

202
static inline LONG get_cache_height(SCRIPT_CACHE *psc)
203
{
204
    return ((ScriptCache *)*psc)->tm.tmHeight;
205 206
}

207
static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
208
{
209 210
    return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
}
211

212
static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, WCHAR c)
213
{
214 215 216 217
    WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];

    if (!block) return 0;
    return block[c & GLYPH_BLOCK_MASK];
218 219
}

220
static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
221
{
222
    WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
223

224 225
    if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
    return ((*block)[c & GLYPH_BLOCK_MASK] = glyph);
226 227
}

228
static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
229
{
230 231
    static const ABC nil;
    ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
232

233 234 235
    if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
    memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
    return TRUE;
236 237
}

238
static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
239
{
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];

    if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
    memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
    return TRUE;
}

static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
{
    ScriptCache *sc;

    if (!psc) return E_INVALIDARG;
    if (*psc) return S_OK;
    if (!hdc) return E_PENDING;

    if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
    if (!GetTextMetricsW(hdc, &sc->tm))
    {
        heap_free(sc);
        return E_INVALIDARG;
    }
    if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
    {
        heap_free(sc);
        return E_INVALIDARG;
    }
    *psc = sc;
    TRACE("<- %p\n", sc);
    return S_OK;
269 270
}

271 272 273 274
/***********************************************************************
 *      DllMain
 *
 */
275 276
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
{
277 278 279 280 281 282 283
    switch(fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hInstDLL);
        break;
    case DLL_PROCESS_DETACH:
        break;
284 285 286 287
    }
    return TRUE;
}

Hans Leidekker's avatar
Hans Leidekker committed
288 289 290
/***********************************************************************
 *      ScriptFreeCache (USP10.@)
 *
291 292 293 294 295 296 297 298
 * Free a script cache.
 *
 * PARAMS
 *   psc [I/O] Script cache.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
Hans Leidekker's avatar
Hans Leidekker committed
299 300 301
 */
HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
{
302
    TRACE("%p\n", psc);
Hans Leidekker's avatar
Hans Leidekker committed
303

304
    if (psc && *psc)
305
    {
306 307 308 309 310 311 312 313
        unsigned int i;
        for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
        {
            heap_free(((ScriptCache *)*psc)->glyphs[i]);
            heap_free(((ScriptCache *)*psc)->widths[i]);
        }
        heap_free(*psc);
        *psc = NULL;
314
    }
315
    return S_OK;
Hans Leidekker's avatar
Hans Leidekker committed
316 317
}

318 319 320
/***********************************************************************
 *      ScriptGetProperties (USP10.@)
 *
321 322 323 324 325 326 327 328 329 330 331 332
 * Retrieve a list of script properties.
 *
 * PARAMS
 *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
 *  num   [I] Pointer to the number of scripts.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
 *
 * NOTES
 *  Behaviour matches WinXP.
333
 */
334
HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
335
{
336
    TRACE("(%p,%p)\n", props, num);
Hans Leidekker's avatar
Hans Leidekker committed
337

338
    if (!props && !num) return E_INVALIDARG;
339

340 341 342 343
    if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
    if (props) *props = script_props;

    return S_OK;
344 345
}

346 347 348
/***********************************************************************
 *      ScriptGetFontProperties (USP10.@)
 *
349 350 351 352 353 354
 * Get information on special glyphs.
 *
 * PARAMS
 *  hdc [I]   Device context.
 *  psc [I/O] Opaque pointer to a script cache.
 *  sfp [O]   Font properties structure.
355
 */
356 357
HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
{
358
    HRESULT hr;
359

360
    TRACE("%p,%p,%p\n", hdc, psc, sfp);
361

362
    if (!sfp) return E_INVALIDARG;
363
    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
364

365 366 367
    if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
        return E_INVALIDARG;

368
    /* return something sensible? */
369
    sfp->wgBlank = 0;
370
    sfp->wgDefault = get_cache_default_char(psc);
371 372
    sfp->wgInvalid = 0;
    sfp->wgKashida = 0xffff;
373
    sfp->iKashidaWidth = 0;
374 375

    return S_OK;
376 377
}

378 379 380
/***********************************************************************
 *      ScriptRecordDigitSubstitution (USP10.@)
 *
381 382 383 384 385 386 387 388 389 390 391 392
 *  Record digit substitution settings for a given locale.
 *
 *  PARAMS
 *   locale [I] Locale identifier.
 *   sds    [I] Structure to record substitution settings.
 *
 *  RETURNS
 *   Success: S_OK
 *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
 *
 *  SEE ALSO
 *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
393
 */
394
HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
395
{
396 397
    DWORD plgid, sub;

398
    TRACE("0x%x, %p\n", locale, sds);
399 400 401 402 403 404

    /* This implementation appears to be correct for all languages, but it's
     * not clear if sds->DigitSubstitute is ever set to anything except 
     * CONTEXT or NONE in reality */

    if (!sds) return E_POINTER;
405

406 407 408 409
    locale = ConvertDefaultLocale(locale);

    if (!IsValidLocale(locale, LCID_INSTALLED))
        return E_INVALIDARG;
410

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
    plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
    sds->TraditionalDigitLanguage = plgid;

    if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
        sds->NationalDigitLanguage = plgid;
    else
        sds->NationalDigitLanguage = LANG_ENGLISH;

    if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
                        (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;

    switch (sub)
    {
    case 0: 
        if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
            sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
        else
            sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
        break;
    case 1:
        sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
        break;
    case 2:
        sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
        break;
    default:
        sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
        break;
    }

    sds->dwReserved = 0;
    return S_OK;
443 444
}

445 446 447
/***********************************************************************
 *      ScriptApplyDigitSubstitution (USP10.@)
 *
448 449 450 451 452 453 454 455 456 457
 *  Apply digit substitution settings.
 *
 *  PARAMS
 *   sds [I] Structure with recorded substitution settings.
 *   sc  [I] Script control structure.
 *   ss  [I] Script state structure.
 *
 *  RETURNS
 *   Success: S_OK
 *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
458
 */
459 460
HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
                                            SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
461
{
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
    SCRIPT_DIGITSUBSTITUTE psds;

    TRACE("%p, %p, %p\n", sds, sc, ss);

    if (!sc || !ss) return E_POINTER;
    if (!sds)
    {
        sds = &psds;
        if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
            return E_INVALIDARG;
    }

    sc->uDefaultLanguage = LANG_ENGLISH;
    sc->fContextDigits = 0;
    ss->fDigitSubstitute = 0;

    switch (sds->DigitSubstitute) {
        case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
        case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
        case SCRIPT_DIGITSUBSTITUTE_NONE:
        case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
            return S_OK;
        default:
            return E_INVALIDARG;
    }
487 488
}

489 490 491
/***********************************************************************
 *      ScriptItemize (USP10.@)
 *
492 493 494 495 496 497 498 499 500 501 502 503 504 505
 * Split a Unicode string into shapeable parts.
 *
 * PARAMS
 *  pwcInChars [I] String to split.
 *  cInChars   [I] Number of characters in pwcInChars.
 *  cMaxItems  [I] Maximum number of items to return.
 *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
 *  psState    [I] Pointer to a SCRIPT_STATE structure.
 *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
 *  pcItems    [O] Number of script items returned.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
506
 */
507 508
HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
                             const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
509 510
                             SCRIPT_ITEM *pItems, int *pcItems)
{
511

512 513 514 515 516 517 518 519 520 521
#define Numeric_start 0x0030
#define Numeric_stop  0x0039
#define Numeric_space 0x0020
#define Arabic_start  0x0600
#define Arabic_stop   0x06ff
#define Latin_start   0x0001
#define Latin_stop    0x024f
#define Script_Arabic  6
#define Script_Latin   1
#define Script_Numeric 5
522 523
#define Script_CR      22
#define Script_LF      23
524 525 526 527 528

    int   cnt = 0, index = 0;
    int   New_Script = SCRIPT_UNDEFINED;

    TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
529
          psControl, psState, pItems, pcItems);
Hans Leidekker's avatar
Hans Leidekker committed
530 531 532 533

    if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
        return E_INVALIDARG;

534 535 536
    pItems[index].iCharPos = 0;
    memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));

537 538 539 540 541 542
    if  (pwcInChars[cnt] == '\r')
        pItems[index].a.eScript = Script_CR;
    else
    if  (pwcInChars[cnt] == '\n')
        pItems[index].a.eScript = Script_LF;
    else
543 544 545 546 547 548 549 550
    if  (pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
        pItems[index].a.eScript = Script_Numeric;
    else
    if  (pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
        pItems[index].a.eScript = Script_Arabic;
    else
    if  (pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
        pItems[index].a.eScript = Script_Latin;
551

552
    if  (pItems[index].a.eScript  == Script_Arabic)
553
        pItems[index].a.s.uBidiLevel = 1;
554

555 556
    TRACE("New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
          New_Script, pItems[index].a.eScript, index, cnt,
557
          pItems[index].iCharPos);
558

559
    for (cnt=1; cnt < cInChars; cnt++)
560
    {
561 562 563 564 565 566
        if  (pwcInChars[cnt] == '\r')
            New_Script = Script_CR;
        else
        if  (pwcInChars[cnt] == '\n')
            New_Script = Script_LF;
        else
567 568 569 570 571 572 573 574
        if  ((pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
             || (New_Script == Script_Numeric && pwcInChars[cnt] == Numeric_space))
            New_Script = Script_Numeric;
        else
        if  ((pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
             || (New_Script == Script_Arabic && pwcInChars[cnt] == Numeric_space))
            New_Script = Script_Arabic;
        else
575 576
        if  ((pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
             || (New_Script == Script_Latin && pwcInChars[cnt] == Numeric_space))
577 578 579
            New_Script = Script_Latin;
        else
            New_Script = SCRIPT_UNDEFINED;
580

581 582 583 584 585 586
        if  (New_Script != pItems[index].a.eScript)
        {
            TRACE("New_Script=%d, eScript=%d ", New_Script, pItems[index].a.eScript);
            index++;
            if  (index+1 > cMaxItems)
                return E_OUTOFMEMORY;
587

588
            pItems[index].iCharPos = cnt;
589 590
            memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));

591 592
            if  (New_Script == Script_Arabic)
                pItems[index].a.s.uBidiLevel = 1;
593

594 595 596
            pItems[index].a.eScript = New_Script;
            if  (New_Script == Script_Arabic)
                pItems[index].a.s.uBidiLevel = 1;
597

598
            TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
599 600
        }
    }
601

602 603
    /* While not strictly necessary according to the spec, make sure the n+1
     * item is set up to prevent random behaviour if the caller erroneously
604
     * checks the n+1 structure                                              */
605 606
    memset(&pItems[index+1].a, 0, sizeof(SCRIPT_ANALYSIS));

607
    TRACE("index=%d cnt=%d iCharPos=%d\n", index+1, cnt, pItems[index+1].iCharPos = cnt);
608 609

    /*  Set one SCRIPT_STATE item being returned  */
610
    if (pcItems) *pcItems = index + 1;
611 612

    /*  Set SCRIPT_ITEM                                     */
613
    pItems[index+1].iCharPos = cnt;       /* the last + 1 item
614
                                             contains the ptr to the lastchar */
615
    return S_OK;
616
}
617

618 619 620 621
/***********************************************************************
 *      ScriptStringAnalyse (USP10.@)
 *
 */
622 623 624 625 626 627
HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
                                   int cGlyphs, int iCharset, DWORD dwFlags,
                                   int iReqWidth, SCRIPT_CONTROL *psControl,
                                   SCRIPT_STATE *psState, const int *piDx,
                                   SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
                                   SCRIPT_STRING_ANALYSIS *pssa)
628
{
629 630 631
    HRESULT hr = E_OUTOFMEMORY;
    StringAnalysis *analysis = NULL;
    int i, num_items = 255;
632 633

    TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
634 635
          hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
          psControl, psState, piDx, pTabdef, pbInClass, pssa);
636

637 638 639 640 641
    if (iCharset != -1)
    {
        FIXME("Only Unicode strings are supported\n");
        return E_INVALIDARG;
    }
642 643
    if (cString < 1 || !pString) return E_INVALIDARG;
    if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
644

645 646
    if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
    if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
647

648 649
    /* FIXME: handle clipping */
    analysis->clip_len = cString;
650
    analysis->hdc = hdc;
651

652 653
    hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
                       &analysis->numItems);
654

655 656 657
    while (hr == E_OUTOFMEMORY)
    {
        SCRIPT_ITEM *tmp;
658

659
        num_items *= 2;
660
        if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
661
            goto error;
662

663 664 665
        analysis->pItem = tmp;
        hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
                           &analysis->numItems);
666
    }
667
    if (hr != S_OK) goto error;
668

669
    if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
670
        ScriptBreak(pString, cString, (SCRIPT_STRING_ANALYSIS)analysis, analysis->logattrs);
671 672
    else
        goto error;
673

674
    if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
675
        goto error;
676

677
    for (i = 0; i < analysis->numItems; i++)
678
    {
679
        SCRIPT_CACHE *sc = (SCRIPT_CACHE *)&analysis->sc;
680 681
        int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
        int numGlyphs = 1.5 * cChar + 16;
682 683 684 685 686 687
        WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
        WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
        int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
        SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * cChar);
        GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
        ABC *abc = heap_alloc_zero(sizeof(ABC));
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
        int numGlyphsReturned;

        /* FIXME: non unicode strings */
        WCHAR* pStr = (WCHAR*)pString;
        hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
                         cChar, numGlyphs, &analysis->pItem[i].a,
                         glyphs, pwLogClust, psva, &numGlyphsReturned);
        hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
                         piAdvance, pGoffset, abc);

        analysis->glyphs[i].numGlyphs = numGlyphsReturned;
        analysis->glyphs[i].glyphs = glyphs;
        analysis->glyphs[i].pwLogClust = pwLogClust;
        analysis->glyphs[i].piAdvance = piAdvance;
        analysis->glyphs[i].psva = psva;
        analysis->glyphs[i].pGoffset = pGoffset;
        analysis->glyphs[i].abc = abc;
    }

    *pssa = analysis;
    return S_OK;
709 710

error:
711 712 713 714 715
    heap_free(analysis->glyphs);
    heap_free(analysis->logattrs);
    heap_free(analysis->pItem);
    heap_free(analysis->sc);
    heap_free(analysis);
716
    return hr;
717 718
}

719 720 721
/***********************************************************************
 *      ScriptStringOut (USP10.@)
 *
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
 * This function takes the output of ScriptStringAnalyse and joins the segments
 * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
 * only processes glyphs.
 *
 * Parameters:
 *  ssa       [I] buffer to hold the analysed string components
 *  iX        [I] X axis displacement for output
 *  iY        [I] Y axis displacement for output
 *  uOptions  [I] flags controling output processing
 *  prc       [I] rectangle coordinates
 *  iMinSel   [I] starting pos for substringing output string
 *  iMaxSel   [I] ending pos for substringing output string
 *  fDisabled [I] controls text highlighting
 *
 *  RETURNS
 *   Success: S_OK
 *   Failure: is the value returned by ScriptTextOut
739
 */
740 741
HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
                               int iX,
742 743 744 745
                               int iY, 
                               UINT uOptions, 
                               const RECT *prc, 
                               int iMinSel, 
746
                               int iMaxSel,
747 748
                               BOOL fDisabled)
{
749 750 751 752 753 754
    StringAnalysis *analysis;
    WORD *glyphs;
    int   item, cnt, x;
    HRESULT hr;

    TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
755
         ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
756

757
    if (!(analysis = ssa)) return E_INVALIDARG;
758 759 760 761 762

    /*
     * Get storage for the output buffer for the consolidated strings
     */
    cnt = 0;
763
    for (item = 0; item < analysis->numItems; item++)
764 765
    {
        cnt += analysis->glyphs[item].numGlyphs;
766
    }
767
    if (!(glyphs = heap_alloc(sizeof(WCHAR) * cnt))) return E_OUTOFMEMORY;
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794

    /*
     * ScriptStringOut only processes glyphs hence set ETO_GLYPH_INDEX
     */
    uOptions |= ETO_GLYPH_INDEX;
    analysis->pItem[0].a.fNoGlyphIndex = FALSE; /* say that we have glyphs */

    /*
     * Copy the string items into the output buffer
     */

    TRACE("numItems %d\n", analysis->numItems);

    cnt = 0;
    for (item = 0; item < analysis->numItems; item++)
    {
        memcpy(&glyphs[cnt], analysis->glyphs[item].glyphs,
              sizeof(WCHAR) * analysis->glyphs[item].numGlyphs);

        TRACE("Item %d, Glyphs %d ", item, analysis->glyphs[item].numGlyphs);
        for (x = cnt; x < analysis->glyphs[item].numGlyphs + cnt; x ++)
            TRACE("%04x", glyphs[x]);
        TRACE("\n");

        cnt += analysis->glyphs[item].numGlyphs; /* point to the end of the copied text */
    }

795
    hr = ScriptTextOut(analysis->hdc, (SCRIPT_CACHE *)&analysis->sc, iX, iY,
796 797
                       uOptions, prc, &analysis->pItem->a, NULL, 0, glyphs, cnt,
                       analysis->glyphs->piAdvance, NULL, analysis->glyphs->pGoffset);
798 799 800 801 802
    TRACE("ScriptTextOut hr=%08x\n", hr);

    /*
     * Free the output buffer and script cache
     */
803
    heap_free(glyphs);
804
    return hr;
805 806
}

807 808 809 810 811 812
/***********************************************************************
 *      ScriptStringCPtoX (USP10.@)
 *
 */
HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
{
813 814 815 816
    int i, j;
    int runningX = 0;
    int runningCp = 0;
    StringAnalysis* analysis = ssa;
817

818 819
    TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);

820
    if (!ssa || !pX) return S_FALSE;
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850

    /* icp out of range */
    if(icp < 0)
    {
        analysis->invalid = TRUE;
        return E_INVALIDARG;
    }

    for(i=0; i<analysis->numItems; i++)
    {
        for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
        {
            if(runningCp == icp && fTrailing == FALSE)
            {
                *pX = runningX;
                return S_OK;
            }
            runningX += analysis->glyphs[i].piAdvance[j];
            if(runningCp == icp && fTrailing == TRUE)
            {
                *pX = runningX;
                return S_OK;
            }
            runningCp++;
        }
    }

    /* icp out of range */
    analysis->invalid = TRUE;
    return E_INVALIDARG;
851 852 853 854 855 856 857 858
}

/***********************************************************************
 *      ScriptStringXtoCP (USP10.@)
 *
 */
HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing) 
{
859 860 861 862 863 864 865 866 867
    StringAnalysis* analysis = ssa;
    int i;
    int j;
    int runningX = 0;
    int runningCp = 0;
    int width;

    TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);

868
    if (!ssa || !piCh || !piTrailing) return S_FALSE;
869 870 871 872 873 874

    /* out of range */
    if(iX < 0)
    {
        *piCh = -1;
        *piTrailing = TRUE;
875
        return S_OK;
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
    }

    for(i=0; i<analysis->numItems; i++)
    {
        for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
        {
            width = analysis->glyphs[i].piAdvance[j];
            if(iX < (runningX + width))
            {
                *piCh = runningCp;
                if((iX - runningX) > width/2)
                    *piTrailing = TRUE;
                else
                    *piTrailing = FALSE;
                return S_OK;
            }
            runningX += width;
            runningCp++;
        }
    }

    /* out of range */
    *piCh = analysis->pItem[analysis->numItems].iCharPos;
    *piTrailing = FALSE;

901 902 903
    return S_OK;
}

904

905 906 907
/***********************************************************************
 *      ScriptStringFree (USP10.@)
 *
908 909 910 911 912 913 914 915
 * Free a string analysis.
 *
 * PARAMS
 *  pssa [I] string analysis.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
916
 */
917 918 919 920 921
HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
{
    StringAnalysis* analysis;
    BOOL invalid;
    int i;
922

923
    TRACE("(%p)\n", pssa);
924

925
    if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
926 927
    invalid = analysis->invalid;

928
    for (i = 0; i < analysis->numItems; i++)
929
    {
930 931 932 933 934 935
        heap_free(analysis->glyphs[i].glyphs);
        heap_free(analysis->glyphs[i].pwLogClust);
        heap_free(analysis->glyphs[i].piAdvance);
        heap_free(analysis->glyphs[i].psva);
        heap_free(analysis->glyphs[i].pGoffset);
        heap_free(analysis->glyphs[i].abc);
936 937
    }

938 939 940 941 942 943
    heap_free(analysis->glyphs);
    heap_free(analysis->pItem);
    heap_free(analysis->logattrs);
    heap_free(analysis->sz);
    heap_free(analysis->sc);
    heap_free(analysis);
944

945
    if (invalid) return E_INVALIDARG;
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
    return S_OK;
}

/***********************************************************************
 *      ScriptCPtoX (USP10.@)
 *
 */
HRESULT WINAPI ScriptCPtoX(int iCP,
                           BOOL fTrailing,
                           int cChars,
                           int cGlyphs,
                           const WORD *pwLogClust,
                           const SCRIPT_VISATTR *psva,
                           const int *piAdvance,
                           const SCRIPT_ANALYSIS *psa,
                           int *piX)
{
963 964 965 966
    int  item;
    int  iPosX;
    float  fMaxPosX = 0;
    TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
967 968
          iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
          psa, piX);
969 970 971 972 973 974 975 976
    for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
        fMaxPosX += piAdvance[item];
    iPosX = (fMaxPosX/cGlyphs)*(iCP+fTrailing);
    if  (iPosX > fMaxPosX)
        iPosX = fMaxPosX;
    *piX = iPosX;                                    /* Return something in range */

    TRACE("*piX=%d\n", *piX);
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
    return S_OK;
}

/***********************************************************************
 *      ScriptXtoCP (USP10.@)
 *
 */
HRESULT WINAPI ScriptXtoCP(int iX,
                           int cChars,
                           int cGlyphs,
                           const WORD *pwLogClust,
                           const SCRIPT_VISATTR *psva,
                           const int *piAdvance,
                           const SCRIPT_ANALYSIS *psa,
                           int *piCP,
                           int *piTrailing)
{
994
    int item;
995
    int iPosX;
996 997 998
    float fMaxPosX = 1;
    float fAvePosX;
    TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
999 1000
          iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
          psa, piCP, piTrailing);
1001 1002 1003 1004 1005 1006
    if  (iX < 0)                                    /* iX is before start of run */
    {
        *piCP = -1;
        *piTrailing = TRUE;
        return S_OK;
    }
1007

1008 1009 1010 1011 1012 1013 1014 1015
    for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
        fMaxPosX += piAdvance[item];

    if  (iX >= fMaxPosX)                            /* iX too large              */
    {
        *piCP = cChars;
        *piTrailing = FALSE;
        return S_OK;
1016
    }
1017 1018

    fAvePosX = fMaxPosX / cGlyphs;
1019 1020 1021
    iPosX = fAvePosX;
    for (item = 1; item < cGlyphs  && iPosX < iX; item++)
        iPosX += fAvePosX;
1022 1023 1024
    if  (iPosX - iX > fAvePosX/2)
        *piTrailing = 0;
    else
1025
        *piTrailing = 1;                            /* yep we are over halfway */
1026

1027 1028
    *piCP = item -1;                                /* Return character position */
    TRACE("*piCP=%d iPposX=%d\n", *piCP, iPosX);
1029 1030 1031 1032 1033 1034
    return S_OK;
}

/***********************************************************************
 *      ScriptBreak (USP10.@)
 *
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
 *  Retrieve line break information.
 *
 *  PARAMS
 *   chars [I] Array of characters.
 *   sa    [I] String analysis.
 *   la    [I] Array of logical attribute structures.
 *
 *  RETURNS
 *   Success: S_OK
 *   Failure: S_FALSE
1045
 */
1046
HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
1047
{
1048
    int i;
1049

1050
    TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
1051 1052 1053 1054 1055 1056 1057

    if (!la) return S_FALSE;

    for (i = 0; i < count; i++)
    {
        memset(&la[i], 0, sizeof(SCRIPT_LOGATTR));

1058
        /* FIXME: set the other flags */
1059
        la[i].fWhiteSpace = (chars[i] == ' ');
1060
        la[i].fCharStop = 1;
1061 1062 1063 1064 1065 1066

        if (i > 0 && la[i - 1].fWhiteSpace)
        {
            la[i].fSoftBreak = 1;
            la[i].fWordStop = 1;
        }
1067
    }
1068
    return S_OK;
1069 1070
}

1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
static const struct
{
    WCHAR start;
    WCHAR end;
    DWORD flag;
}
complex_ranges[] =
{
    { 0, 0x0b, SIC_COMPLEX },
    { 0x0c, 0x0c, SIC_NEUTRAL },
    { 0x0d, 0x1f, SIC_COMPLEX },
    { 0x20, 0x2f, SIC_NEUTRAL },
    { 0x30, 0x39, SIC_ASCIIDIGIT },
    { 0x3a, 0x40, SIC_NEUTRAL },
    { 0x5b, 0x60, SIC_NEUTRAL },
    { 0x7b, 0x7e, SIC_NEUTRAL },
    { 0x7f, 0x9f, SIC_COMPLEX },
    { 0xa0, 0xa5, SIC_NEUTRAL },
    { 0xa7, 0xa8, SIC_NEUTRAL },
    { 0xab, 0xab, SIC_NEUTRAL },
    { 0xad, 0xad, SIC_NEUTRAL },
    { 0xaf, 0xaf, SIC_NEUTRAL },
    { 0xb0, 0xb1, SIC_NEUTRAL },
    { 0xb4, 0xb4, SIC_NEUTRAL },
    { 0xb6, 0xb8, SIC_NEUTRAL },
    { 0xbb, 0xbf, SIC_NEUTRAL },
    { 0xd7, 0xd7, SIC_NEUTRAL },
    { 0xf7, 0xf7, SIC_NEUTRAL },
    { 0x2b9, 0x2ba, SIC_NEUTRAL },
    { 0x2c2, 0x2cf, SIC_NEUTRAL },
    { 0x2d2, 0x2df, SIC_NEUTRAL },
    { 0x2e5, 0x2e9, SIC_COMPLEX },
    { 0x2ea, 0x2ed, SIC_NEUTRAL },
    { 0x300, 0x362, SIC_COMPLEX },
    { 0x530, 0x60b, SIC_COMPLEX },
    { 0x60c, 0x60d, SIC_NEUTRAL },
    { 0x60e, 0x669, SIC_COMPLEX },
    { 0x66a, 0x66a, SIC_NEUTRAL },
    { 0x66b, 0x6e8, SIC_COMPLEX },
    { 0x6e9, 0x6e9, SIC_NEUTRAL },
    { 0x6ea, 0x7bf, SIC_COMPLEX },
    { 0x900, 0x1360, SIC_COMPLEX },
    { 0x137d, 0x137f, SIC_COMPLEX },
    { 0x1680, 0x1680, SIC_NEUTRAL },
    { 0x1780, 0x18af, SIC_COMPLEX },
    { 0x2000, 0x200a, SIC_NEUTRAL },
    { 0x200b, 0x200f, SIC_COMPLEX },
    { 0x2010, 0x2016, SIC_NEUTRAL },
    { 0x2018, 0x2022, SIC_NEUTRAL },
    { 0x2024, 0x2028, SIC_NEUTRAL },
    { 0x2029, 0x202e, SIC_COMPLEX },
    { 0x202f, 0x2037, SIC_NEUTRAL },
    { 0x2039, 0x203c, SIC_NEUTRAL },
    { 0x2044, 0x2046, SIC_NEUTRAL },
    { 0x206a, 0x206f, SIC_COMPLEX },
    { 0x207a, 0x207e, SIC_NEUTRAL },
    { 0x208a, 0x20aa, SIC_NEUTRAL },
    { 0x20ac, 0x20cf, SIC_NEUTRAL },
    { 0x20d0, 0x20ff, SIC_COMPLEX },
    { 0x2103, 0x2103, SIC_NEUTRAL },
    { 0x2105, 0x2105, SIC_NEUTRAL },
    { 0x2109, 0x2109, SIC_NEUTRAL },
    { 0x2116, 0x2116, SIC_NEUTRAL },
    { 0x2121, 0x2122, SIC_NEUTRAL },
    { 0x212e, 0x212e, SIC_NEUTRAL },
    { 0x2153, 0x2154, SIC_NEUTRAL },
    { 0x215b, 0x215e, SIC_NEUTRAL },
    { 0x2190, 0x2199, SIC_NEUTRAL },
    { 0x21b8, 0x21b9, SIC_NEUTRAL },
    { 0x21d2, 0x21d2, SIC_NEUTRAL },
    { 0x21d4, 0x21d4, SIC_NEUTRAL },
    { 0x21e7, 0x21e7, SIC_NEUTRAL },
    { 0x2200, 0x2200, SIC_NEUTRAL },
    { 0x2202, 0x2203, SIC_NEUTRAL },
    { 0x2207, 0x2208, SIC_NEUTRAL },
    { 0x220b, 0x220b, SIC_NEUTRAL },
    { 0x220f, 0x220f, SIC_NEUTRAL },
    { 0x2211, 0x2213, SIC_NEUTRAL },
    { 0x2215, 0x2215, SIC_NEUTRAL },
    { 0x221a, 0x221a, SIC_NEUTRAL },
    { 0x221d, 0x2220, SIC_NEUTRAL },
    { 0x2223, 0x2223, SIC_NEUTRAL },
    { 0x2225, 0x2225, SIC_NEUTRAL },
    { 0x2227, 0x222c, SIC_NEUTRAL },
    { 0x222e, 0x222e, SIC_NEUTRAL },
    { 0x2234, 0x2237, SIC_NEUTRAL },
    { 0x223c, 0x223d, SIC_NEUTRAL },
    { 0x2248, 0x2248, SIC_NEUTRAL },
    { 0x224c, 0x224c, SIC_NEUTRAL },
    { 0x2252, 0x2252, SIC_NEUTRAL },
    { 0x2260, 0x2261, SIC_NEUTRAL },
    { 0x2264, 0x2267, SIC_NEUTRAL },
    { 0x226a, 0x226b, SIC_NEUTRAL },
    { 0x226e, 0x226f, SIC_NEUTRAL },
    { 0x2282, 0x2283, SIC_NEUTRAL },
    { 0x2286, 0x2287, SIC_NEUTRAL },
    { 0x2295, 0x2295, SIC_NEUTRAL },
    { 0x2299, 0x2299, SIC_NEUTRAL },
    { 0x22a5, 0x22a5, SIC_NEUTRAL },
    { 0x22bf, 0x22bf, SIC_NEUTRAL },
    { 0x2312, 0x2312, SIC_NEUTRAL },
    { 0x24ea, 0x24ea, SIC_COMPLEX },
    { 0x2500, 0x254b, SIC_NEUTRAL },
    { 0x2550, 0x256d, SIC_NEUTRAL },
    { 0x256e, 0x2574, SIC_NEUTRAL },
    { 0x2581, 0x258f, SIC_NEUTRAL },
    { 0x2592, 0x2595, SIC_NEUTRAL },
    { 0x25a0, 0x25a1, SIC_NEUTRAL },
    { 0x25a3, 0x25a9, SIC_NEUTRAL },
    { 0x25b2, 0x25b3, SIC_NEUTRAL },
    { 0x25b6, 0x25b7, SIC_NEUTRAL },
    { 0x25bc, 0x25bd, SIC_NEUTRAL },
    { 0x25c0, 0x25c1, SIC_NEUTRAL },
    { 0x25c6, 0x25c8, SIC_NEUTRAL },
    { 0x25cb, 0x25cb, SIC_NEUTRAL },
    { 0x25ce, 0x25d1, SIC_NEUTRAL },
    { 0x25e2, 0x25e5, SIC_NEUTRAL },
    { 0x25ef, 0x25ef, SIC_NEUTRAL },
    { 0x2605, 0x2606, SIC_NEUTRAL },
    { 0x2609, 0x2609, SIC_NEUTRAL },
    { 0x260e, 0x260f, SIC_NEUTRAL },
    { 0x261c, 0x261c, SIC_NEUTRAL },
    { 0x261e, 0x261e, SIC_NEUTRAL },
    { 0x2640, 0x2640, SIC_NEUTRAL },
    { 0x2642, 0x2642, SIC_NEUTRAL },
    { 0x2660, 0x2661, SIC_NEUTRAL },
    { 0x2663, 0x2665, SIC_NEUTRAL },
    { 0x2667, 0x266a, SIC_NEUTRAL },
    { 0x266c, 0x266d, SIC_NEUTRAL },
    { 0x266f, 0x266f, SIC_NEUTRAL },
    { 0x273d, 0x273d, SIC_NEUTRAL },
    { 0x2e80, 0x312f, SIC_COMPLEX },
    { 0x3190, 0x31bf, SIC_COMPLEX },
    { 0x31f0, 0x31ff, SIC_COMPLEX },
    { 0x3220, 0x325f, SIC_COMPLEX },
    { 0x3280, 0xa4ff, SIC_COMPLEX },
    { 0xd800, 0xdfff, SIC_COMPLEX },
    { 0xe000, 0xf8ff, SIC_NEUTRAL },
    { 0xf900, 0xfaff, SIC_COMPLEX },
    { 0xfb13, 0xfb28, SIC_COMPLEX },
    { 0xfb29, 0xfb29, SIC_NEUTRAL },
    { 0xfb2a, 0xfb4f, SIC_COMPLEX },
    { 0xfd3e, 0xfd3f, SIC_NEUTRAL },
    { 0xfdd0, 0xfdef, SIC_COMPLEX },
    { 0xfe20, 0xfe6f, SIC_COMPLEX },
    { 0xfeff, 0xfeff, SIC_COMPLEX },
    { 0xff01, 0xff5e, SIC_COMPLEX },
    { 0xff61, 0xff9f, SIC_COMPLEX },
    { 0xffe0, 0xffe6, SIC_COMPLEX },
    { 0xffe8, 0xffee, SIC_COMPLEX },
    { 0xfff9, 0xfffb, SIC_COMPLEX },
    { 0xfffe, 0xfffe, SIC_COMPLEX }
};

1225 1226
/***********************************************************************
 *      ScriptIsComplex (USP10.@)
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
 * 
 *  Determine if a string is complex.
 *
 *  PARAMS
 *   chars [I] Array of characters to test.
 *   len   [I] Length in characters.
 *   flag  [I] Flag.
 *
 *  RETURNS
 *   Success: S_OK
 *   Failure: S_FALSE
1238
 *
1239 1240
 *  NOTES
 *   Behaviour matches that of WinXP.
1241
 */
1242 1243
HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
{
1244 1245
    int i;
    unsigned int j;
1246

1247
    TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258

    for (i = 0; i < len; i++)
    {
        for (j = 0; j < sizeof(complex_ranges)/sizeof(complex_ranges[0]); j++)
        {
            if (chars[i] >= complex_ranges[j].start &&
                chars[i] <= complex_ranges[j].end &&
                (flag & complex_ranges[j].flag)) return S_OK;
        }
    }
    return S_FALSE;
1259
}
1260

Jeff Latimer's avatar
Jeff Latimer committed
1261 1262 1263
/***********************************************************************
 *      ScriptShape (USP10.@)
 *
1264 1265 1266 1267 1268 1269 1270 1271
 * Produce glyphs and visual attributes for a run.
 *
 * PARAMS
 *  hdc         [I]   Device context.
 *  psc         [I/O] Opaque pointer to a script cache.
 *  pwcChars    [I]   Array of characters specifying the run.
 *  cChars      [I]   Number of characters in pwcChars.
 *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
1272
 *  psa         [I/O] Script analysis.
1273 1274 1275 1276 1277 1278 1279 1280
 *  pwOutGlyphs [O]   Array of glyphs.
 *  pwLogClust  [O]   Array of logical cluster info.
 *  psva        [O]   Array of visual attributes.
 *  pcGlyphs    [O]   Number of glyphs returned.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
Jeff Latimer's avatar
Jeff Latimer committed
1281 1282 1283
 */
HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars, 
                           int cChars, int cMaxGlyphs,
1284
                           SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
Jeff Latimer's avatar
Jeff Latimer committed
1285 1286
                           SCRIPT_VISATTR *psva, int *pcGlyphs)
{
1287
    HRESULT hr;
1288
    unsigned int i;
1289

1290 1291 1292
    TRACE("(%p, %p, %s, %d, %d, %p, %p, %p, %p, %p)\n", hdc, psc, debugstr_wn(pwcChars, cChars),
          cChars, cMaxGlyphs, psa, pwOutGlyphs, pwLogClust, psva, pcGlyphs);

1293
    if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
1294 1295
                   psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);

1296
    if (!psva || !pcGlyphs) return E_INVALIDARG;
1297
    if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
1298

1299
    *pcGlyphs = cChars;
1300
    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1301

1302 1303
    if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
    {
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313
        for (i = 0; i < cChars; i++)
        {
            if (!(pwOutGlyphs[i] = get_cache_glyph(psc, pwcChars[i])))
            {
                WORD glyph;
                if (!hdc) return E_PENDING;
                if (GetGlyphIndicesW(hdc, &pwcChars[i], 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
                pwOutGlyphs[i] = set_cache_glyph(psc, pwcChars[i], glyph);
            }
        }
1314
    }
1315 1316 1317
    else
    {
        TRACE("no glyph translation\n");
1318
        for (i = 0; i < cChars; i++) pwOutGlyphs[i] = pwcChars[i];
1319
    }
1320

1321 1322
    /* set up a valid SCRIPT_VISATTR and LogClust for each char in this run */
    for (i = 0; i < cChars; i++)
1323
    {
1324 1325 1326 1327 1328 1329 1330 1331 1332
        /* FIXME: set to better values */
        psva[i].uJustification = (pwcChars[i] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
        psva[i].fClusterStart  = 1;
        psva[i].fDiacritic     = 0;
        psva[i].fZeroWidth     = 0;
        psva[i].fReserved      = 0;
        psva[i].fShapeReserved = 0;

        if (pwLogClust) pwLogClust[i] = i;
1333
    }
1334
    return S_OK;
Jeff Latimer's avatar
Jeff Latimer committed
1335
}
1336

Jeff Latimer's avatar
Jeff Latimer committed
1337 1338 1339
/***********************************************************************
 *      ScriptPlace (USP10.@)
 *
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
 * Produce advance widths for a run.
 *
 * PARAMS
 *  hdc       [I]   Device context.
 *  psc       [I/O] Opaque pointer to a script cache.
 *  pwGlyphs  [I]   Array of glyphs.
 *  cGlyphs   [I]   Number of glyphs in pwGlyphs.
 *  psva      [I]   Array of visual attributes.
 *  psa       [I/O] String analysis.
 *  piAdvance [O]   Array of advance widths.
 *  pGoffset  [O]   Glyph offsets.
 *  pABC      [O]   Combined ABC width.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
Jeff Latimer's avatar
Jeff Latimer committed
1356 1357 1358 1359 1360
 */
HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, 
                           int cGlyphs, const SCRIPT_VISATTR *psva,
                           SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
{
1361
    HRESULT hr;
1362
    int i;
1363

1364 1365
    TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n",  hdc, psc, pwGlyphs, cGlyphs, psva, psa,
          piAdvance, pGoffset, pABC);
1366

1367
    if (!psva) return E_INVALIDARG;
1368
    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1369

1370
    if (pABC) memset(pABC, 0, sizeof(ABC));
1371
    for (i = 0; i < cGlyphs; i++)
1372
    {
1373 1374
        ABC abc;
        if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
1375
        {
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
            if (!hdc) return E_PENDING;
            if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
            {
                if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
            }
            else
            {
                INT width;
                if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
                abc.abcB = width;
                abc.abcA = abc.abcC = 0;
            }
            set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
1389 1390 1391
        }
        if (pABC)
        {
1392 1393 1394
            pABC->abcA += abc.abcA;
            pABC->abcB += abc.abcB;
            pABC->abcC += abc.abcC;
1395
        }
1396 1397
        /* FIXME: set to more reasonable values */
        if (pGoffset)  pGoffset[i].du = pGoffset[i].dv = 0;
1398
        if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
1399
    }
1400

1401
    if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
1402
    return S_OK;
Jeff Latimer's avatar
Jeff Latimer committed
1403
}
1404 1405 1406 1407

/***********************************************************************
 *      ScriptGetCMap (USP10.@)
 *
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
 * Retrieve glyph indices.
 *
 * PARAMS
 *  hdc         [I]   Device context.
 *  psc         [I/O] Opaque pointer to a script cache.
 *  pwcInChars  [I]   Array of Unicode characters.
 *  cChars      [I]   Number of characters in pwcInChars.
 *  dwFlags     [I]   Flags.
 *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
1421 1422
 */
HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
1423
                             int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
1424
{
1425
    HRESULT hr;
1426
    int i;
1427

1428 1429
    TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
          cChars, dwFlags, pwOutGlyphs);
1430

1431
    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1432

1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
    if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
    {
        for (i = 0; i < cChars; i++)
        {
            if (!(pwOutGlyphs[i] = get_cache_glyph(psc, pwcInChars[i])))
            {
                WORD glyph;
                if (!hdc) return E_PENDING;
                if (GetGlyphIndicesW(hdc, &pwcInChars[i], 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
                pwOutGlyphs[i] = set_cache_glyph(psc, pwcInChars[i], glyph);
            }
        }
    }
    else
    {
        TRACE("no glyph translation\n");
        for (i = 0; i < cChars; i++) pwOutGlyphs[i] = pwcInChars[i];
    }
    return S_OK;
1452
}
1453 1454 1455 1456 1457 1458 1459

/***********************************************************************
 *      ScriptTextOut (USP10.@)
 *
 */
HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
                             const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
1460
                             int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
1461 1462
                             const int *piJustify, const GOFFSET *pGoffset)
{
1463
    HRESULT hr = S_OK;
1464

1465
    TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
1466 1467 1468
         hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
         piAdvance, piJustify, pGoffset);

1469
    if (!hdc || !psc) return E_INVALIDARG;
1470
    if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
1471

1472 1473
    fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
    if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
1474
        fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
1475

1476
    if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
1477
        hr = S_FALSE;
1478

1479
    return hr;
1480
}
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495

/***********************************************************************
 *      ScriptCacheGetHeight (USP10.@)
 *
 * Retrieve the height of the font in the cache.
 *
 * PARAMS
 *  hdc    [I]    Device context.
 *  psc    [I/O]  Opaque pointer to a script cache.
 *  height [O]    Receives font height.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
 */
1496
HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
1497
{
1498
    HRESULT hr;
1499 1500 1501

    TRACE("(%p, %p, %p)\n", hdc, psc, height);

1502
    if (!height) return E_INVALIDARG;
1503
    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1504

1505
    *height = get_cache_height(psc);
1506 1507
    return S_OK;
}
1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525

/***********************************************************************
 *      ScriptGetGlyphABCWidth (USP10.@)
 *
 * Retrieve the width of a glyph.
 *
 * PARAMS
 *  hdc    [I]    Device context.
 *  psc    [I/O]  Opaque pointer to a script cache.
 *  glyph  [I]    Glyph to retrieve the width for.
 *  abc    [O]    ABC widths of the glyph.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
 */
HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
{
1526
    HRESULT hr;
1527 1528 1529

    TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);

1530
    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1531

1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548
    if (!get_cache_glyph_widths(psc, glyph, abc))
    {
        if (!hdc) return E_PENDING;
        if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
        {
            if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
        }
        else
        {
            INT width;
            if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
            abc->abcB = width;
            abc->abcA = abc->abcC = 0;
        }
        set_cache_glyph_widths(psc, glyph, abc);
    }
    return S_OK;
1549
}
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574

/***********************************************************************
 *      ScriptLayout (USP10.@)
 *
 * Map embedding levels to visual and/or logical order.
 *
 * PARAMS
 *  runs     [I] Size of level array.
 *  level    [I] Array of embedding levels.
 *  vistolog [O] Map of embedding levels from visual to logical order.
 *  logtovis [O] Map of embedding levels from logical to visual order.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: Non-zero HRESULT value.
 *
 * BUGS
 *  This stub works correctly for any sequence of a single
 *  embedding level but not for sequences of different
 *  embedding levels, i.e. mixtures of RTL and LTR scripts.
 */
HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
{
    int i, j = runs - 1, k = 0;

1575
    TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596

    if (!level || (!vistolog && !logtovis))
        return E_INVALIDARG;

    for (i = 0; i < runs; i++)
    {
        if (level[i] % 2)
        {
            if (vistolog) *vistolog++ = j;
            if (logtovis) *logtovis++ = j;
            j--;
        }
        else
        {
            if (vistolog) *vistolog++ = k;
            if (logtovis) *logtovis++ = k;
            k++;
        }
    }
    return S_OK;
}
1597

1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
/***********************************************************************
 *      ScriptStringGetLogicalWidths (USP10.@)
 *
 * Returns logical widths from a string analysis.
 *
 * PARAMS
 *  ssa  [I] string analysis.
 *  piDx [O] logical widths returned.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: a non-zero HRESULT.
 */
HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
{
    int i, j, next = 0;
    StringAnalysis *analysis = ssa;

    TRACE("%p, %p\n", ssa, piDx);

    if (!analysis) return S_FALSE;

    for (i = 0; i < analysis->numItems; i++)
    {
        for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
        {
            piDx[next] = analysis->glyphs[i].piAdvance[j];
            next++;
        }
    }
    return S_OK;
}

1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645
/***********************************************************************
 *      ScriptStringValidate (USP10.@)
 *
 * Validate a string analysis.
 *
 * PARAMS
 *  ssa [I] string analysis.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: S_FALSE if invalid sequences are found
 *           or a non-zero HRESULT if it fails.
 */
HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
{
1646 1647 1648 1649 1650 1651
    StringAnalysis *analysis = ssa;

    TRACE("(%p)\n", ssa);

    if (!analysis) return E_INVALIDARG;
    return (analysis->invalid) ? S_FALSE : S_OK;
1652
}
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667

/***********************************************************************
 *      ScriptString_pSize (USP10.@)
 *
 * Retrieve width and height of an analysed string.
 *
 * PARAMS
 *  ssa [I] string analysis.
 *
 * RETURNS
 *  Success: Pointer to a SIZE structure.
 *  Failure: NULL
 */
const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
{
1668
    int i, j;
1669 1670 1671 1672 1673 1674 1675 1676
    StringAnalysis *analysis = ssa;

    TRACE("(%p)\n", ssa);

    if (!analysis) return NULL;

    if (!analysis->sz)
    {
1677
        if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
1678
        analysis->sz->cy = analysis->sc->tm.tmHeight;
1679 1680 1681 1682 1683 1684 1685 1686

        analysis->sz->cx = 0;
        for (i = 0; i < analysis->numItems; i++)
            for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
                analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
    }
    return analysis->sz;
}
1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708

/***********************************************************************
 *      ScriptString_pLogAttr (USP10.@)
 *
 * Retrieve logical attributes of an analysed string.
 *
 * PARAMS
 *  ssa [I] string analysis.
 *
 * RETURNS
 *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
 *  Failure: NULL
 */
const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
{
    StringAnalysis *analysis = ssa;

    TRACE("(%p)\n", ssa);

    if (!analysis) return NULL;
    return analysis->logattrs;
}
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746

/***********************************************************************
 *      ScriptString_pcOutChars (USP10.@)
 *
 * Retrieve the length of a string after clipping.
 *
 * PARAMS
 *  ssa [I] String analysis.
 *
 * RETURNS
 *  Success: Pointer to the length.
 *  Failure: NULL
 */
const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
{
    StringAnalysis *analysis = ssa;

    TRACE("(%p)\n", ssa);

    if (!analysis) return NULL;
    return &analysis->clip_len;
}

/***********************************************************************
 *      ScriptStringGetOrder (USP10.@)
 *
 * Retrieve a glyph order map.
 *
 * PARAMS
 *  ssa   [I]   String analysis.
 *  order [I/O] Array of glyph positions.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: a non-zero HRESULT.
 */
HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
{
1747 1748
    int i, j;
    unsigned int k;
1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
    StringAnalysis *analysis = ssa;

    TRACE("(%p)\n", ssa);

    if (!analysis) return S_FALSE;

    /* FIXME: handle RTL scripts */
    for (i = 0, k = 0; i < analysis->numItems; i++)
        for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
            order[k] = k;

    return S_OK;
}
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793

/***********************************************************************
 *      ScriptGetLogicalWidths (USP10.@)
 *
 * Convert advance widths to logical widths.
 *
 * PARAMS
 *  sa          [I] Script analysis.
 *  nbchars     [I] Number of characters.
 *  nbglyphs    [I] Number of glyphs.
 *  glyph_width [I] Array of glyph widths.
 *  log_clust   [I] Array of logical clusters.
 *  sva         [I] Visual attributes.
 *  widths      [O] Array of logical widths.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: a non-zero HRESULT.
 */
HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
                                      const int *glyph_width, const WORD *log_clust,
                                      const SCRIPT_VISATTR *sva, int *widths)
{
    int i;

    TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
          sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);

    /* FIXME */
    for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
    return S_OK;
}