Sweden-Number/dlls/usp10/shape.c

153 lines
4.4 KiB
C
Raw Normal View History

2010-05-19 16:17:00 +02:00
/*
* Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
*
* Copyright 2010 CodeWeavers, Aric Stewart
*
* 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
*
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "usp10.h"
#include "usp10_internal.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
#define FIRST_ARABIC_CHAR 0x0600
#define LAST_ARABIC_CHAR 0x06ff
extern const unsigned short wine_shaping_table[];
extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
enum joining_types {
jtU,
jtT,
jtR,
jtL,
jtD,
jtC
};
enum joined_forms {
Xn=0,
Xl,
Xr,
Xm
};
static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
{
if (i + delta < 0)
{
if (psa->fLinkBefore)
return jtR;
else
return jtU;
}
if ( i+ delta >= cchLen)
{
if (psa->fLinkAfter)
return jtL;
else
return jtU;
}
i += delta;
if (context_type[i] == jtT)
return neighbour_joining_type(i,delta,context_type,cchLen,psa);
else
return context_type[i];
}
static inline BOOL right_join_causing(CHAR joining_type)
{
return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
}
static inline BOOL left_join_causing(CHAR joining_type)
{
return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
}
/* SHAPE_ShapeArabicGlyphs
*/
void SHAPE_ShapeArabicGlyphs(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT cMaxGlyphs)
{
CHAR *context_type;
INT *context_shape;
INT dirR, dirL;
int i;
if (psa->eScript != Script_Arabic)
return;
if (!psa->fLogicalOrder && psa->fRTL)
{
dirR = -1;
dirL = 1;
}
else
{
dirR = 1;
dirL = -1;
}
context_type = HeapAlloc(GetProcessHeap(),0,cChars);
context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
for (i = 0; i < cChars; i++)
context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
for (i = 0; i < cChars; i++)
{
if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
context_shape[i] = Xr;
else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
context_shape[i] = Xl;
else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
context_shape[i] = Xm;
else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
context_shape[i] = Xr;
else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
context_shape[i] = Xl;
else
context_shape[i] = Xn;
}
for (i = 0; i < cChars; i++)
{
WORD newGlyph = pwOutGlyphs[i];
if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
{
WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
pwOutGlyphs[i] = newGlyph;
}
}
HeapFree(GetProcessHeap(),0,context_shape);
HeapFree(GetProcessHeap(),0,context_type);
}