📄 usp10.c
字号:
/*
* Implementation of Uniscribe Script Processor (usp10.dll)
*
* Copyright 2005 Steven Edwards for CodeWeavers
* Copyright 2006 Hans Leidekker
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* 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>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "usp10.h"
#include "wine/debug.h"
#include "wine/unicode.h"
DWORD STDCALL GetGlyphIndicesW( HDC hdc, LPCWSTR lpstr, int c, LPWORD pgi, DWORD fl);
BOOL STDCALL GetCharABCWidthsI(HDC hdc, UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc);
/**
* some documentation here:
* http://www.microsoft.com/typography/developers/uniscribe/uniscribe.htm
*/
WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
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]
};
typedef struct {
HDC hdc;
LONG height;
WCHAR default_char;
} ScriptCache;
typedef struct {
int numGlyphs;
WORD* glyphs;
WORD* pwLogClust;
int* piAdvance;
SCRIPT_VISATTR* psva;
GOFFSET* pGoffset;
ABC* abc;
} StringGlyphs;
typedef struct {
BOOL invalid;
int clip_len;
ScriptCache *sc;
int cItems;
int cMaxGlyphs;
SCRIPT_ITEM* pItem;
int numItems;
StringGlyphs* glyphs;
SCRIPT_LOGATTR* logattrs;
SIZE* sz;
} StringAnalysis;
static inline void *usp_alloc(SIZE_T size)
{
return HeapAlloc(GetProcessHeap(), 0, size);
}
static inline void *usp_zero_alloc(SIZE_T size)
{
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
}
static inline void *usp_zero_realloc(LPVOID mem, SIZE_T size)
{
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
}
static inline void usp_free(LPVOID mem)
{
HeapFree(GetProcessHeap(), 0, mem);
}
static HDC get_cache_hdc(SCRIPT_CACHE *psc)
{
return ((ScriptCache *)*psc)->hdc;
}
static WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
{
return ((ScriptCache *)*psc)->default_char;
}
static LONG get_cache_height(SCRIPT_CACHE *psc)
{
return ((ScriptCache *)*psc)->height;
}
static HRESULT init_script_cache(const HDC hdc, ScriptCache *sc)
{
TEXTMETRICW metric;
if (!GetTextMetricsW(hdc, &metric)) return E_INVALIDARG;
sc->height = metric.tmHeight;
sc->default_char = metric.tmDefaultChar;
sc->hdc = hdc;
return S_OK;
}
static HRESULT get_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
{
if (!psc) return E_INVALIDARG;
if (!*psc)
{
HRESULT ret;
ScriptCache *sc;
if (!hdc) return E_PENDING;
if (!(sc = usp_zero_alloc(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
if ((ret = init_script_cache(hdc, sc)))
{
usp_free(sc);
return ret;
}
*psc = sc;
}
TRACE("<- %p\n", *psc);
return S_OK;
}
/***********************************************************************
* DllMain
*
*/
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInstDLL);
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/***********************************************************************
* ScriptFreeCache (USP10.@)
*
* Free a script cache.
*
* PARAMS
* psc [I/O] Script cache.
*
* RETURNS
* Success: S_OK
* Failure: Non-zero HRESULT value.
*/
HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
{
TRACE("%p\n", psc);
if (psc)
{
usp_free(*psc);
*psc = NULL;
}
return S_OK;
}
/***********************************************************************
* ScriptGetProperties (USP10.@)
*
* 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.
*/
HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
{
TRACE("(%p,%p)\n", props, num);
if (!props && !num) return E_INVALIDARG;
if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
if (props) *props = script_props;
return S_OK;
}
/***********************************************************************
* ScriptGetFontProperties (USP10.@)
*
* Get information on special glyphs.
*
* PARAMS
* hdc [I] Device context.
* psc [I/O] Opaque pointer to a script cache.
* sfp [O] Font properties structure.
*/
HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
{
HRESULT hr;
TRACE("%p,%p,%p\n", hdc, psc, sfp);
if (!sfp) return E_INVALIDARG;
if ((hr = get_script_cache(hdc, psc))) return hr;
if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
return E_INVALIDARG;
/* return something sensible? */
sfp->wgBlank = 0;
sfp->wgDefault = get_cache_default_char(psc);
sfp->wgInvalid = 0;
sfp->wgKashida = 0xffff;
sfp->iKashidaWidth = 0;
return S_OK;
}
/***********************************************************************
* ScriptRecordDigitSubstitution (USP10.@)
*
* 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
*/
HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
{
DWORD plgid, sub;
TRACE("0x%x, %p\n", locale, sds);
/* 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;
locale = ConvertDefaultLocale(locale);
if (!IsValidLocale(locale, LCID_INSTALLED))
return E_INVALIDARG;
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;
}
/***********************************************************************
* ScriptApplyDigitSubstitution (USP10.@)
*
* Apply digit substitution settings.
*
* PARAMS
* sds [I] Structure with recorded substitution settings.
* sc [I] Script control structure.
* ss [I] Script state structure.
*
* RETURNS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -