You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1278 lines
42 KiB
1278 lines
42 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Module Name : LPK_GDI.c //
|
|
// //
|
|
// Entry points (formal interfaces) for GDI32 to call //
|
|
// and route their APIs, so that we can implement our language-specific //
|
|
// features. //
|
|
// //
|
|
// Created : Oct 24, 1996 //
|
|
// Author : Mohamed AbdEl Hamid [mhamid] //
|
|
// //
|
|
// Copyright (c) 1996, Microsoft Corporation. All rights reserved. //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "precomp.hxx"
|
|
|
|
|
|
//// FontHasWesternScript
|
|
//
|
|
// Detect if the current selected font in the hdc has Western script or not by using
|
|
// the cached data g_FontIDCache. and also add the selected font to the cache it it is
|
|
// not cached before.
|
|
// All calles used inside this function is Client-mode calls except if the font will be
|
|
// cached then calling GetGlyphIndices (Kernel-mode call) will take place.
|
|
// This function used in the optimization checking for ExtTextOut and GetTextExtent.
|
|
//
|
|
// entry hdc - Device context
|
|
//
|
|
// return value: TRUE if font has western script. FALSE otherwise.
|
|
//
|
|
|
|
BOOL FontHasWesternScript(HDC hdc)
|
|
{
|
|
REALIZATION_INFO ri;
|
|
int i;
|
|
WORD Glyphs[4];
|
|
BOOL fRet;
|
|
|
|
if (!GdiRealizationInfo(hdc, &ri)) {
|
|
return FALSE;
|
|
}
|
|
|
|
EnterCriticalSection(&csFontIdCache);
|
|
|
|
if (g_cCachedFontsID > 0) {
|
|
for (i=0 ; i<g_cCachedFontsID ; i++) {
|
|
if (ri.uFontFileID == g_FontIDCache[i].uFontFileID) {
|
|
fRet = g_FontIDCache[i].bHasWestern;
|
|
LeaveCriticalSection(&csFontIdCache);
|
|
return (fRet);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((GetGlyphIndicesW(hdc , L"dMr\"" , 4 , Glyphs , GGI_MARK_NONEXISTING_GLYPHS) == 4) &&
|
|
(Glyphs[0] != 0xFFFF && Glyphs[1] != 0xFFFF && Glyphs[2] != 0xFFFF && Glyphs[3] != 0xFFFF)) {
|
|
|
|
g_FontIDCache[g_pCurrentAvailablePos].bHasWestern = fRet = TRUE;
|
|
} else {
|
|
g_FontIDCache[g_pCurrentAvailablePos].bHasWestern = fRet = FALSE;
|
|
}
|
|
g_FontIDCache[g_pCurrentAvailablePos].uFontFileID = ri.uFontFileID ;
|
|
|
|
g_pCurrentAvailablePos++;
|
|
if (g_pCurrentAvailablePos >= MAX_FONT_ID_CACHE) {
|
|
g_pCurrentAvailablePos = 0;
|
|
}
|
|
if (g_cCachedFontsID < MAX_FONT_ID_CACHE) {
|
|
g_cCachedFontsID++;
|
|
}
|
|
LeaveCriticalSection(&csFontIdCache);
|
|
return (fRet);
|
|
}
|
|
|
|
|
|
|
|
//// InternalTextOut
|
|
//
|
|
// Display text with possible font association
|
|
//
|
|
// entry hdc - Device context
|
|
// x,y - Starting coords (Unless TA_UPDATECP)
|
|
// uOptions - Flags (see below)
|
|
// prc - Pointer to clipping rectangle
|
|
// pString - Unicode string
|
|
// cbCount - String length in unicode characters
|
|
// pdx - Overriding logical dx array
|
|
// iCharset - Original ANSI iCharset, or -1 if unicode
|
|
//
|
|
// exit TRUE if string drawn OK
|
|
//
|
|
// options ETO_CLIPPED - Clip to clipping rectangle
|
|
// ETO_OPAQUE - Extend background colour to bounds of clipping rectangle
|
|
// ETO_RTLREADING - Render text with right to left reading order
|
|
// ETO_NUMERICSLOCAL
|
|
// ETO_NUMERICSLATIN
|
|
// ETO_PDY - lpdx array contains DX,DY pairs - causes LPK to be bypassed
|
|
//
|
|
// note LpkExtTextOut also obeys options set by SetTextAlign:
|
|
// TA_LEFT - x,y is position of left edge of displayed glyphs
|
|
// TA_CENTRE - x,y is position at centre of diplayed glyphs
|
|
// TA_RIGHT - x,y is position at right edge of displayed glyphs
|
|
// TA_RTLREADING - Render text with right to left reading order
|
|
// TA_UPDATECP - Get x,y from current position, ignoring x,y parameters,
|
|
// update current position following textout.
|
|
//
|
|
// history Oct 22, 1996 -by- Samer Arafeh [samera]
|
|
// Oct 24, 1996 -by- Mohamed AbdEl Hamid [mhamid]
|
|
// Feb 18, 1887 dbrown - Support font association
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///// InternalTextOut
|
|
//
|
|
//
|
|
|
|
BOOL InternalTextOut(
|
|
HDC hdc,
|
|
int x,
|
|
int y,
|
|
UINT uOptions,
|
|
const RECT *prc,
|
|
const WCHAR *pStr,
|
|
UINT cbCount,
|
|
const int *piDX,
|
|
int iCharset,
|
|
int *piWidth,
|
|
int iRequiredWidth) {
|
|
|
|
BOOL fRTLreading;
|
|
int iDigitSubstitute;
|
|
int iTextAlign;
|
|
HRESULT hr;
|
|
DWORD dwObjType;
|
|
DWORD dwSicFlags; // Flags for ScriptIsComplex
|
|
int iCurrentCharSet;
|
|
STRING_ANALYSIS *psa;
|
|
|
|
UNREFERENCED_PARAMETER(iRequiredWidth) ;
|
|
|
|
|
|
if (!cbCount || !pStr) {
|
|
|
|
// Empty string - no glyph processing required. Optimise ...
|
|
|
|
return ExtTextOutW(hdc, x, y, uOptions|ETO_GLYPH_INDEX, prc,
|
|
pStr, cbCount, piDX);
|
|
}
|
|
|
|
|
|
// ETO_PDY is not relevant for complex script strings. Let GDI
|
|
// handle it. (APps wanting to adjust the y coordinate of glyphs in
|
|
// complex script strings should use Uniscribe and manipulate the
|
|
// pGoffset parameter to ScriptTextOut.
|
|
|
|
if (uOptions & ETO_PDY) {
|
|
return ExtTextOutW(hdc, x, y, uOptions | ETO_IGNORELANGUAGE, prc,
|
|
pStr, cbCount, piDX);
|
|
}
|
|
|
|
// Establish Bidi reading order.
|
|
//
|
|
// Note, it is possible for us to be passed an hdc that does not
|
|
// support GetTextAlign, in which case GetTextAlign will return -1.
|
|
// Treat this as left to right reading order.
|
|
|
|
fRTLreading = ((uOptions & ETO_RTLREADING)
|
|
|| (((iTextAlign = GetTextAlign(hdc)) & TA_RTLREADING) && (iTextAlign != -1)))
|
|
? TRUE : FALSE;
|
|
|
|
|
|
// Interpret ETO_NUMERICS* flags:
|
|
// If both bits are set, the digit substitute = context. This is a win95
|
|
// compatability issue and is used mainly by Access.
|
|
|
|
if ((uOptions&(ETO_NUMERICSLOCAL|ETO_NUMERICSLATIN)) == (ETO_NUMERICSLOCAL|ETO_NUMERICSLATIN)) {
|
|
iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
|
|
} else if (uOptions & ETO_NUMERICSLOCAL) {
|
|
iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
|
|
} else if (uOptions & ETO_NUMERICSLATIN) {
|
|
iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
|
|
} else {
|
|
iDigitSubstitute = -1;
|
|
}
|
|
|
|
uOptions = uOptions & ~(ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN);
|
|
|
|
|
|
// Check for plain text that can bypass the LPK entirely
|
|
|
|
dwSicFlags = SIC_COMPLEX;
|
|
|
|
if ( iDigitSubstitute == SCRIPT_DIGITSUBSTITUTE_CONTEXT
|
|
|| iDigitSubstitute == SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
|
|
|| g_DigitSubstitute.DigitSubstitute != SCRIPT_DIGITSUBSTITUTE_NONE) {
|
|
dwSicFlags |= SIC_ASCIIDIGIT;
|
|
}
|
|
|
|
if (fRTLreading != !!(GetLayout(hdc) & LAYOUT_RTL)) {
|
|
dwSicFlags |= SIC_NEUTRAL;
|
|
}
|
|
|
|
if (( ScriptIsComplex(pStr,cbCount,dwSicFlags) == S_FALSE
|
|
&& FontHasWesternScript(hdc))
|
|
|| GetTextCharacterExtra(hdc) != 0)
|
|
{
|
|
// No complex script processing required
|
|
|
|
return ExtTextOutW(hdc, x, y, uOptions | ETO_IGNORELANGUAGE, prc,
|
|
pStr, cbCount, piDX);
|
|
}
|
|
|
|
|
|
dwObjType = GetObjectType(hdc);
|
|
|
|
// Analyse the string
|
|
|
|
hr = LpkStringAnalyse(
|
|
hdc, pStr, cbCount, 0, -1,
|
|
SSA_GLYPHS
|
|
| (dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_DONTGLYPH : 0)
|
|
| (iCharset==-1 || GdiIsPlayMetafileDC(hdc) ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
|
|
| (fRTLreading ? SSA_RTL : 0),
|
|
iDigitSubstitute, iRequiredWidth,
|
|
NULL, NULL,
|
|
piDX,
|
|
NULL, NULL,
|
|
&psa);
|
|
if (FAILED(hr)) {
|
|
ASSERTHR(hr, ("InternalTextOut - LpkStringAnalyse"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Return string width if required (for DrawText)
|
|
|
|
if (piWidth) {
|
|
*piWidth = psa->size.cx;
|
|
}
|
|
|
|
|
|
hr = ScriptStringOut(psa, x, y, uOptions, prc, 0, 0, FALSE);
|
|
|
|
ScriptStringFree((void**)&psa);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
return TRUE;
|
|
} else {
|
|
ASSERTHR(hr, ("InternalTextOut - ScriptStringOut"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL LpkExtTextOut(
|
|
HDC hdc,
|
|
int x,
|
|
int y,
|
|
UINT uOptions,
|
|
CONST RECT *prc,
|
|
PCWSTR pStr,
|
|
UINT cbCount,
|
|
CONST INT *pDx,
|
|
int iCharset) {
|
|
|
|
return InternalTextOut(hdc, x, y, uOptions, prc, pStr, cbCount, pDx, iCharset, NULL, -1);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// GDI32 GetTextExtentExPoint will call this function for supporting //
|
|
// Multilingual Text handling. //
|
|
// //
|
|
// LpkGetTextExtentExPoint( HDC hdc, PWSTR pStr, int cchString, //
|
|
// int nMaxExtent, PINT pnFit, PINT pDx, PSIZE pSize, int iCharset) //
|
|
// //
|
|
// hDC Identifies the device context //
|
|
// pStr Points to string for which extents are to be retrieved. //
|
|
// cchString Count of characters in input string //
|
|
// nMaxExtent Specifies the maximum allowable width, in logical units, //
|
|
// of the formatted string. //
|
|
// pnFit Maximum characters that fit in the formatted string //
|
|
// When the pnFit parameter is NULL, the nMaxExtent parameter //
|
|
// is ignored. //
|
|
// //
|
|
// pDx address of array for partial string widths //
|
|
// pSize Address for string dimension //
|
|
// fl ???? //
|
|
// iCharset Indicates character set of codes. to optimizing the work. ??//
|
|
// //
|
|
// Return //
|
|
// If the function succeeds, the return value is TRUE. //
|
|
// If the function fails, the return value is FALSE. //
|
|
// And we seted the error by call SetLastError. //
|
|
// To get extended error information, call GetLastError. //
|
|
// //
|
|
// History //
|
|
// Oct 22, 1996 -by- Samer Arafeh [samera] //
|
|
// Oct 25, 1996 -by- MOhammed Abdul Hammed [mhamid] //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL LpkGetTextExtentExPoint(
|
|
HDC hdc,
|
|
PCWSTR pStr,
|
|
int cchString,
|
|
int nMaxExtent,
|
|
PINT pnFit,
|
|
PINT pDx,
|
|
PSIZE pSize,
|
|
FLONG fl,
|
|
int iCharset)
|
|
{
|
|
int iTextAlign;
|
|
BOOL fRTLreading;
|
|
int i;
|
|
HRESULT hr;
|
|
DWORD dwObjType;
|
|
DWORD dwSicFlags; // Flags for ScriptIsComplex
|
|
int iCurrentCharSet;
|
|
STRING_ANALYSIS *psa;
|
|
STRING_ANALYSIS *psaFit;
|
|
UNREFERENCED_PARAMETER(fl) ;
|
|
|
|
|
|
// Check required parameters
|
|
|
|
if (!hdc || !pSize) {
|
|
|
|
ASSERTS(hdc, ("LpkGetTextExtentPoint - required parameter hdc is NULL"));
|
|
ASSERTS(pSize, ("LpkGetTextExtentPoint - required parameter pSize is NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//Do we have a string
|
|
if (!cchString || !pStr) {
|
|
//no then go away
|
|
pSize->cx = 0;
|
|
pSize->cy = 0;
|
|
if (pnFit) {
|
|
*pnFit = 0;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
iTextAlign = GetTextAlign(hdc);
|
|
fRTLreading = (iTextAlign & TA_RTLREADING) && (iTextAlign != -1);
|
|
|
|
|
|
// Check for plain text that can bypass the LPK entirely
|
|
|
|
dwSicFlags = SIC_COMPLEX;
|
|
|
|
if (g_DigitSubstitute.DigitSubstitute != SCRIPT_DIGITSUBSTITUTE_NONE) {
|
|
dwSicFlags |= SIC_ASCIIDIGIT;
|
|
}
|
|
|
|
if (fRTLreading != !!(GetLayout(hdc) & LAYOUT_RTL)) {
|
|
dwSicFlags |= SIC_NEUTRAL;
|
|
}
|
|
|
|
if (( ScriptIsComplex(pStr, cchString, dwSicFlags) == S_FALSE
|
|
&& FontHasWesternScript(hdc))
|
|
|| GetTextCharacterExtra(hdc) != 0)
|
|
{
|
|
// No complex script processing required
|
|
|
|
return GetTextExtentExPointWPri(hdc, pStr, cchString, nMaxExtent, pnFit, pDx, pSize);
|
|
}
|
|
|
|
|
|
dwObjType = GetObjectType(hdc);
|
|
|
|
// Analyse the string
|
|
|
|
hr = LpkStringAnalyse(
|
|
hdc, pStr, cchString, 0, -1,
|
|
SSA_GLYPHS
|
|
// if the DC is Meta-File DC, we should enable the FallBack because it is enabled for ETOA while playing any Meta-File.
|
|
| (iCharset==-1 || dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
|
|
| (fRTLreading ? SSA_RTL : 0)
|
|
| (pnFit ? SSA_FULLMEASURE : 0),
|
|
-1, nMaxExtent,
|
|
NULL, NULL, NULL, NULL, NULL,
|
|
&psa);
|
|
if (FAILED(hr)) {
|
|
ASSERTHR(hr, ("LpkGetTextExtentExPoint - LpkStringAnalyse"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (pDx) {
|
|
|
|
// if we have pnFit and psa->cOutChars>=cchString so we should fill lpDx.
|
|
if (!pnFit || psa->cOutChars>=cchString) {
|
|
ScriptStringGetLogicalWidths(psa, pDx);
|
|
}
|
|
|
|
// we need to update the width of last fit glyph.
|
|
if (pnFit && psa->cOutChars<cchString && psa->cOutChars>0) {
|
|
hr = LpkStringAnalyse(
|
|
hdc, pStr, psa->cOutChars, 0, -1,
|
|
SSA_GLYPHS
|
|
// if the DC is Meta-File DC, we should enable the FallBack because it is enabled for ETOA while playing any Meta-File.
|
|
| (iCharset==-1 || dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
|
|
| (fRTLreading ? SSA_RTL : 0),
|
|
-1, 0,
|
|
NULL, NULL, NULL, NULL, NULL,
|
|
&psaFit);
|
|
|
|
if (FAILED(hr)) {
|
|
ScriptStringFree((void**)&psa);
|
|
ASSERTHR(hr, ("LpkGetTextExtentExPoint - LpkStringAnalyse"));
|
|
return FALSE;
|
|
}
|
|
ScriptStringGetLogicalWidths(psaFit, pDx);
|
|
ScriptStringFree((void**)&psaFit);
|
|
}
|
|
|
|
// Accumulate extents
|
|
for (i=1; i<(pnFit==NULL?cchString:psa->cOutChars); i++) {
|
|
pDx[i] += pDx[i-1];
|
|
}
|
|
}
|
|
|
|
if (pnFit) {
|
|
*pnFit = psa->cOutChars;
|
|
}
|
|
|
|
*pSize = psa->size;
|
|
|
|
ScriptStringFree((void**)&psa);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// GetCharacterPlacement support
|
|
//
|
|
//
|
|
|
|
|
|
|
|
|
|
//// GCPgenerateOutString
|
|
//
|
|
// Creates a reordered copy of the input string
|
|
|
|
|
|
void GCPgenerateOutString(
|
|
STRING_ANALYSIS *psa,
|
|
WCHAR *pwOutString) {
|
|
|
|
int i,j;
|
|
int iItem;
|
|
int iStart;
|
|
int iLen;
|
|
WCHAR *pwch;
|
|
|
|
|
|
// Copy items one by one in visual order
|
|
|
|
for (i=0; i<psa->cItems; i++) {
|
|
|
|
iItem = psa->piVisToLog[i];
|
|
iStart = psa->pItems[iItem].iCharPos;
|
|
iLen = psa->pItems[iItem+1].iCharPos - iStart;
|
|
|
|
if (psa->pItems[iItem].a.fRTL) {
|
|
|
|
// Right to left item
|
|
|
|
pwch = psa->pwInChars + iStart + iLen - 1;
|
|
for (j=0; j<iLen; j++) {
|
|
*pwOutString++ = *pwch--;
|
|
}
|
|
|
|
} else {
|
|
|
|
// Left to right item
|
|
|
|
memcpy(pwOutString, psa->pwInChars+iStart, sizeof(WCHAR) * iLen);
|
|
pwOutString += iLen;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// GCPgenerateClass
|
|
//
|
|
// Creates an array of character classifications using
|
|
// GetCharacterPlacement legacy definitons
|
|
|
|
|
|
void GCPgenerateClass(
|
|
STRING_ANALYSIS *psa,
|
|
BYTE *pbClass) {
|
|
|
|
int iItem;
|
|
int iStart;
|
|
int iLen;
|
|
int iClass;
|
|
int iChar;
|
|
|
|
|
|
// Map LogClust entries item by item in logical order
|
|
|
|
for (iItem=0; iItem<psa->cItems; iItem++) {
|
|
|
|
iStart = psa->pItems[iItem].iCharPos;
|
|
iLen = psa->pItems[iItem+1].iCharPos - iStart;
|
|
|
|
if (g_ppScriptProperties[psa->pItems[iItem].a.eScript]->fNumeric) {
|
|
|
|
if (psa->pItems[iItem].a.fLayoutRTL) {
|
|
iClass = GCPCLASS_LOCALNUMBER;
|
|
} else {
|
|
iClass = GCPCLASS_LATINNUMBER;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (psa->pItems[iItem].a.fLayoutRTL) {
|
|
iClass = GCPCLASS_ARABIC; // (Same constant as GCPCLASS_HEBREW)
|
|
} else {
|
|
iClass = GCPCLASS_LATIN;
|
|
}
|
|
}
|
|
|
|
memset(pbClass, iClass, iLen);
|
|
pbClass += iLen;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GCPJustification
|
|
*
|
|
* Justifies text according to piJustify and returns proper pwgi and piDx
|
|
* arrays.
|
|
*
|
|
* IMPORTANT : Caller should free (USPFREE(*ppwgi)) allocated buffer if
|
|
* the fn succeeds (SUCCEEDED(hr)) and return code isn't S_FALSE.
|
|
* S_FALSE means no justification is to be applied here since the piJustify and
|
|
* piDx are either identical or the total width to justify for is less than the
|
|
* min kashida width.
|
|
*
|
|
* All param are DWORD aligned.
|
|
*
|
|
* History :
|
|
*
|
|
* Mar 23, 1998 -by- Samer Arafeh [samera]
|
|
* wrote it
|
|
\**************************************************************************/
|
|
#define BlankPriority 10
|
|
HRESULT GCPJustification( WORD **ppwgi, // Out Output buffer width justified glyphs
|
|
int **ppiJustifyDx, // Out Newly generated piDx buffer
|
|
WORD *pwgi, // In Incoming GIs
|
|
const int *piAdvWidth, // In Advance wdiths
|
|
const SCRIPT_VISATTR *pVisAttr, // In Visual attributes
|
|
int *piJustify, // In Justification advanced widths
|
|
int cGlyphs, // In number of glyphs
|
|
int iKashidaWidth, // In Minimum width of kashida
|
|
int *pcJustifiedGlyphs, // Out Receives the total # of glyphs in output buf
|
|
DWORD dwgKashida, // In Kashida GI
|
|
DWORD dwgSpace) // In Space GI
|
|
{
|
|
DWORD dwSize;
|
|
int iInsert=0L, iGlyph, iAmount, iJustDx;
|
|
int cNewGlyphs = cGlyphs;
|
|
WORD *pwNewGlyph;
|
|
int *piNewAdvWidth;
|
|
int cMaxGlyphs = *pcJustifiedGlyphs;
|
|
int cNonArabicGlyph;
|
|
int cNonBlank;
|
|
int iDelta;
|
|
HRESULT hr;
|
|
INT iPartialKashida;
|
|
|
|
//
|
|
// Point to caller's data initially
|
|
//
|
|
*ppwgi = pwgi;
|
|
*ppiJustifyDx = (INT *)piJustify;
|
|
*pcJustifiedGlyphs = cGlyphs;
|
|
|
|
//
|
|
// If Kashida width is less than or equal 0, then justify with spaces only.
|
|
//
|
|
if(iKashidaWidth <= 0L) {
|
|
iKashidaWidth = -1;
|
|
}
|
|
|
|
//
|
|
// 1- Analyze input buffer to see how many kashida to insert, If Kashida is used.
|
|
//
|
|
if (iKashidaWidth != -1 ) {
|
|
cNonArabicGlyph = 0;
|
|
cNonBlank = 0;
|
|
iDelta = 0;
|
|
|
|
for( iGlyph=cGlyphs-1 ; iGlyph >= 0L ; iGlyph-- )
|
|
{
|
|
if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_NONE) ||
|
|
(pVisAttr[iGlyph].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL)) {
|
|
|
|
iAmount = piJustify[iGlyph]-piAdvWidth[iGlyph];
|
|
if (iAmount > 0 && cNewGlyphs < cMaxGlyphs){
|
|
iPartialKashida = iAmount % iKashidaWidth;
|
|
iAmount /= iKashidaWidth;
|
|
if (iPartialKashida > 0 && iAmount>0)
|
|
{
|
|
iAmount++;
|
|
}
|
|
if (cNewGlyphs + iAmount > cMaxGlyphs) {
|
|
iAmount = (cMaxGlyphs - cNewGlyphs) * iKashidaWidth;
|
|
cNewGlyphs = cMaxGlyphs;
|
|
iDelta += piJustify[iGlyph] - piAdvWidth[iGlyph] - iAmount;
|
|
piJustify[iGlyph] = piAdvWidth[iGlyph] + iAmount;
|
|
} else {
|
|
cNewGlyphs += iAmount;
|
|
}
|
|
} else {
|
|
iDelta += iAmount;
|
|
piJustify[iGlyph] = piAdvWidth[iGlyph];
|
|
}
|
|
} else {
|
|
|
|
if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK) ||
|
|
(pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_BLANK)) {
|
|
cNonBlank++;
|
|
} else {
|
|
cNonArabicGlyph++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (iDelta > 0 && cNonArabicGlyph+cNonBlank>0) {
|
|
// The Space has 10-times higher priority than Latin characters.
|
|
iAmount = iDelta / (cNonArabicGlyph + (cNonBlank * BlankPriority));
|
|
|
|
for( iGlyph=0 ; iGlyph < cGlyphs ; iGlyph++ )
|
|
{
|
|
if( (pVisAttr[iGlyph].uJustification != SCRIPT_JUSTIFY_NONE) &&
|
|
(pVisAttr[iGlyph].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL)) {
|
|
|
|
|
|
if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK) ||
|
|
(pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_BLANK)) {
|
|
|
|
piJustify[iGlyph] += BlankPriority * iAmount;
|
|
iDelta -= BlankPriority * iAmount;
|
|
} else {
|
|
piJustify[iGlyph] += iAmount;
|
|
iDelta -= iAmount;
|
|
}
|
|
cNonArabicGlyph = iGlyph;
|
|
}
|
|
|
|
}
|
|
if (iDelta > 0) {
|
|
piJustify[cNonArabicGlyph] += iDelta;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 2- Allocate for new glyphs and piDx
|
|
//
|
|
|
|
dwSize = (cNewGlyphs * (sizeof(INT)+sizeof(WORD)));
|
|
hr = USPALLOCTEMP( dwSize , (void **)&pwNewGlyph );
|
|
if(FAILED(hr))
|
|
{
|
|
ASSERTHR(hr, ("Not ennough memory for JustifiyArabicStringWithKashida()"));
|
|
return hr;
|
|
}
|
|
piNewAdvWidth = (INT *)(pwNewGlyph+cNewGlyphs);
|
|
|
|
|
|
//
|
|
// 3- Begin inserting and formulating the justified buffer
|
|
//
|
|
int iJustReminder = 0;
|
|
|
|
for( iGlyph=cGlyphs-1, iInsert=cNewGlyphs-1; iGlyph >= 0L && iInsert>=0; iGlyph-- )
|
|
{
|
|
iJustDx = (piJustify[iGlyph] - piAdvWidth[iGlyph]) + iJustReminder;
|
|
|
|
iJustReminder = 0;
|
|
|
|
if( iJustDx > 0)
|
|
{
|
|
if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_NONE) ||
|
|
(pVisAttr[iGlyph].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL))
|
|
{
|
|
//Arabic glyph then justify with kashida
|
|
if(( iJustDx >= iKashidaWidth ) && (iKashidaWidth != -1))
|
|
{
|
|
|
|
pwNewGlyph[iInsert] = pwgi[iGlyph];
|
|
piNewAdvWidth[iInsert] = piAdvWidth[iGlyph];
|
|
iInsert--;
|
|
|
|
while( (iJustDx >= iKashidaWidth) && (iInsert >= 0L) )
|
|
{
|
|
pwNewGlyph[iInsert] = (WORD)dwgKashida;
|
|
piNewAdvWidth[iInsert] = iKashidaWidth;
|
|
iInsert--;
|
|
|
|
iJustDx -= iKashidaWidth;
|
|
}
|
|
|
|
if(( iJustDx > 0L ) && (iInsert >= 0L))
|
|
{
|
|
pwNewGlyph[iInsert] = (WORD)dwgKashida;
|
|
piNewAdvWidth[iInsert] = iJustDx;
|
|
iInsert--;
|
|
iJustDx = 0L;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pwNewGlyph[iInsert] = pwgi[iGlyph];
|
|
piNewAdvWidth[iInsert] = piAdvWidth[iGlyph];
|
|
iJustReminder = iJustDx;
|
|
iInsert--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pwNewGlyph[iInsert] = pwgi[iGlyph];
|
|
piNewAdvWidth[iInsert] = piAdvWidth[iGlyph] + iJustDx;
|
|
iInsert--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pwNewGlyph[iInsert] = pwgi[iGlyph];
|
|
piNewAdvWidth[iInsert] = piJustify[iGlyph];
|
|
iInsert--;
|
|
}
|
|
}
|
|
|
|
//
|
|
// In case there is a space glyph, it will be expanded in locatio rather
|
|
// than inserting kashida GIs
|
|
//
|
|
while( iInsert >= 0L )
|
|
{
|
|
piNewAdvWidth[iInsert] = 0L;
|
|
pwNewGlyph[iInsert] = (WORD)dwgSpace;
|
|
iInsert--;
|
|
}
|
|
|
|
//
|
|
// 4- Update results
|
|
//
|
|
*ppwgi = pwNewGlyph;
|
|
*ppiJustifyDx = piNewAdvWidth;
|
|
*pcJustifiedGlyphs = cNewGlyphs;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// GDI32 GetCharacterPlacement will call this function for //
|
|
// supporting Multilingual Text handling. //
|
|
// //
|
|
// LpkGetCharacterPlacement( HDC hdc, PWSTR pStr, int nCount, //
|
|
// int nMaxExtent, LPGCP_RESULTSW pResults, DWORD dwFlags, //
|
|
// int iCharset) //
|
|
// //
|
|
// hDC : Handle to device context //
|
|
// pStr : Input string //
|
|
// nCount : Count of characters in input string //
|
|
// nMaxExtent : Maximum width for formatting string //
|
|
// pResults : Pointer to GCP_RESULTS strucutre for output //
|
|
// dwFlags : GCP Processing Flags //
|
|
// iCharset : Origianl character set of pStr //
|
|
// //
|
|
// Return //
|
|
// If the function succeeds, the return value is Width an the Height //
|
|
// of the string //
|
|
// If the function fails, the return value is 0. //
|
|
// And we seted the error by call SetLastError. //
|
|
// To get extended error information, call GetLastError. //
|
|
// //
|
|
// History : //
|
|
// Oct 22, 1996 -by- Samer Arafeh [samera] //
|
|
// Oct 29, 1996 -by- MOhammed Abdul Hammed [mhamid] //
|
|
// Jan 13, 1997 -by- David C Brown (dbrown) //
|
|
// New justification widths buffer //
|
|
// ANALYSE field name changes //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD LpkGetCharacterPlacement(
|
|
HDC hdc,
|
|
const WCHAR *pwcInChars,
|
|
int cInChars,
|
|
int nMaxExtent,
|
|
GCP_RESULTSW *pResults,
|
|
DWORD dwFlags,
|
|
int iCharset) {
|
|
|
|
UINT uBufferOptions;
|
|
int iDigitSubstitute, i, cMaxGlyphs;
|
|
int *pLocalDX;
|
|
DWORD dwRet = 0;
|
|
HRESULT hr;
|
|
DWORD dwSSAflags;
|
|
SCRIPT_CONTROL scriptControl = {0}; // Analysis control
|
|
SCRIPT_STATE scriptState = {0}; // Initial state
|
|
STRING_ANALYSIS *psa;
|
|
SCRIPT_FONTPROPERTIES sfp;
|
|
WORD *pwLocalGlyphs;
|
|
|
|
|
|
|
|
TRACE(GDI, ("LpkGetCharacterPlacement begins"));
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 1-Check parameters //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Check required parameters
|
|
ASSERTS(hdc, ("LpkGetCharacterPlacement - required parameter hdc is NULL"));
|
|
|
|
//GCP_MAXEXTENT and no nMaxExtent
|
|
if ((dwFlags & GCP_MAXEXTENT) && (nMaxExtent < 0)) {
|
|
TRACEMSG(("LpkGetCharacterPlacement: Invalid parameter - GCP_MAXEXTENT and no nMaxExtent"));
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
//GCP_CLASSIN set and no pClass
|
|
if ((dwFlags & GCP_CLASSIN) && !(pResults->lpClass)) {
|
|
TRACEMSG(("LpkGetCharacterPlacement: Invalid parameter - GCP_CLASSIN set and no pClass"));
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 2 - Interpret control flags //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
switch (dwFlags & (GCP_NUMERICSLOCAL|GCP_NUMERICSLATIN)) {
|
|
|
|
case GCP_NUMERICSLOCAL:
|
|
iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
|
|
break;
|
|
|
|
case GCP_NUMERICSLOCAL|GCP_NUMERICSLATIN:
|
|
iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
|
|
break;
|
|
|
|
case GCP_NUMERICSLATIN:
|
|
iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
|
|
break;
|
|
|
|
default:
|
|
iDigitSubstitute = -1;
|
|
}
|
|
|
|
|
|
dwSSAflags = 0;
|
|
|
|
if (dwFlags & GCP_REORDER) {
|
|
if (GetTextAlign(hdc) & TA_RTLREADING ? 1 : 0) {
|
|
dwSSAflags |= SSA_RTL;
|
|
}
|
|
} else {
|
|
scriptState.fOverrideDirection = TRUE;
|
|
}
|
|
|
|
if (dwFlags & GCP_DISPLAYZWG) scriptState.fDisplayZWG = TRUE;
|
|
if (!(dwFlags & GCP_LIGATE)) scriptState.fInhibitLigate = TRUE;
|
|
if (dwFlags & GCP_SYMSWAPOFF) scriptState.fInhibitSymSwap = TRUE;
|
|
if (dwFlags & GCP_NEUTRALOVERRIDE) scriptControl.fNeutralOverride = TRUE;
|
|
if (dwFlags & GCP_NUMERICOVERRIDE) scriptControl.fNumericOverride = TRUE;
|
|
|
|
if (pResults->lpGlyphs) {
|
|
scriptControl.fLinkStringBefore = pResults->lpGlyphs[0] & GCPGLYPH_LINKBEFORE ? TRUE : FALSE;
|
|
scriptControl.fLinkStringAfter = pResults->lpGlyphs[0] & GCPGLYPH_LINKAFTER ? TRUE : FALSE;
|
|
}
|
|
|
|
if (dwFlags & GCP_MAXEXTENT) {
|
|
dwSSAflags |= SSA_CLIP;
|
|
if (dwFlags & GCP_JUSTIFY) {
|
|
dwSSAflags |= SSA_FIT;
|
|
if (!(dwFlags & GCP_KASHIDA) || !(dwFlags & (GCP_GLYPHSHAPE | GCP_LIGATE))) {
|
|
dwSSAflags |= SSA_NOKASHIDA;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dwFlags & GCP_CLASSIN) {
|
|
if (((const BYTE *)pResults->lpClass)[0] & (GCPCLASS_PREBOUNDLTR | GCPCLASS_PREBOUNDRTL)) {
|
|
scriptControl.fInvertPreBoundDir = (((const BYTE *)pResults->lpClass)[0] & GCPCLASS_PREBOUNDRTL ? 1 : 0)
|
|
^ (dwSSAflags & SSA_RTL ? 1 : 0);
|
|
}
|
|
|
|
if (((const BYTE *)pResults->lpClass)[0] & (GCPCLASS_POSTBOUNDLTR | GCPCLASS_POSTBOUNDRTL)) {
|
|
scriptControl.fInvertPostBoundDir = (((const BYTE *)pResults->lpClass)[0] & GCPCLASS_POSTBOUNDRTL ? 1 : 0)
|
|
^ (dwSSAflags & SSA_RTL ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 3-Call LPK_ANA to do Layout and Shaping //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
if (dwFlags & GCP_CLASSIN) {
|
|
hr = LpkStringAnalyse(
|
|
hdc, pwcInChars, cInChars, pResults->nGlyphs, -1,
|
|
dwSSAflags | SSA_GLYPHS | SSA_GCP,
|
|
iDigitSubstitute, nMaxExtent,
|
|
&scriptControl, &scriptState,
|
|
NULL,
|
|
NULL,
|
|
(BYTE*)pResults->lpClass,
|
|
&psa);
|
|
} else {
|
|
hr = LpkStringAnalyse(
|
|
hdc, pwcInChars, cInChars, pResults->nGlyphs, -1,
|
|
dwSSAflags | SSA_GLYPHS | SSA_GCP,
|
|
iDigitSubstitute, nMaxExtent,
|
|
&scriptControl, &scriptState,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&psa);
|
|
}
|
|
if (FAILED(hr)) {
|
|
ASSERTHR(hr, ("LpkGetTextExtentExPoint - LpkStringAnalyse"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If the user's suppled buffer isn't sufficient to hold the
|
|
// output, then let's truncate it.
|
|
//
|
|
if (pResults->nGlyphs < (UINT) psa->cOutGlyphs) {
|
|
psa->cOutGlyphs = (UINT) pResults->nGlyphs;
|
|
}
|
|
|
|
if (pResults->lpOutString) {
|
|
GCPgenerateOutString(psa, pResults->lpOutString);
|
|
}
|
|
|
|
|
|
if (pResults->lpOrder) {
|
|
ScriptStringGetOrder(psa, pResults->lpOrder);
|
|
}
|
|
|
|
|
|
if (pResults->lpClass) {
|
|
GCPgenerateClass(psa, (PBYTE) pResults->lpClass);
|
|
}
|
|
|
|
BOOL bGlyphsCopied = FALSE;
|
|
|
|
if (pResults->lpDx) {
|
|
if (psa->piJustify && (dwFlags & GCP_JUSTIFY)) {
|
|
sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
|
|
hr = ScriptGetFontProperties(hdc,
|
|
&psa->sc[0],
|
|
&sfp);
|
|
if(SUCCEEDED(hr)) {
|
|
if (!(dwFlags & GCP_KASHIDA) || !(dwFlags & (GCP_GLYPHSHAPE | GCP_LIGATE)))
|
|
sfp.iKashidaWidth = -1;
|
|
else {
|
|
ASSERTS(sfp.wgKashida, ("LpkGetCharacterPlacement - ther is no Kashida glyph"));
|
|
}
|
|
|
|
cMaxGlyphs = pResults->nGlyphs;
|
|
|
|
hr = GCPJustification( (WORD **)&pwLocalGlyphs,
|
|
(int **)&pLocalDX,
|
|
(WORD *)psa->pwGlyphs,
|
|
(int *)psa->piAdvance,
|
|
psa->pVisAttr,
|
|
psa->piJustify,
|
|
psa->cOutGlyphs,
|
|
sfp.iKashidaWidth,
|
|
&cMaxGlyphs,
|
|
sfp.wgKashida,
|
|
sfp.wgBlank);
|
|
if(SUCCEEDED(hr)) {
|
|
int iOffset = 0;
|
|
if (cMaxGlyphs > (int)pResults->nGlyphs) {
|
|
iOffset = cMaxGlyphs - pResults->nGlyphs;
|
|
cMaxGlyphs = pResults->nGlyphs;
|
|
}
|
|
|
|
psa->cOutGlyphs = cMaxGlyphs;
|
|
|
|
if (pResults->lpGlyphs) {
|
|
memcpy (pResults->lpGlyphs, (LPVOID)(pwLocalGlyphs+iOffset), sizeof(WORD) * cMaxGlyphs);
|
|
bGlyphsCopied = TRUE;
|
|
}
|
|
|
|
psa->size.cx = 0;
|
|
for (i=0; i<cMaxGlyphs; i++) {
|
|
pResults->lpDx[i] = pLocalDX[i+iOffset];
|
|
psa->size.cx += pLocalDX[i+iOffset];
|
|
}
|
|
USPFREE((LPVOID)pwLocalGlyphs);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
memcpy(pResults->lpDx, psa->piAdvance, sizeof(int) * psa->cOutGlyphs);
|
|
}
|
|
}
|
|
|
|
if (!bGlyphsCopied && pResults->lpGlyphs) {
|
|
memcpy(pResults->lpGlyphs, psa->pwGlyphs, sizeof(WORD) * psa->cOutGlyphs);
|
|
}
|
|
|
|
|
|
if (dwFlags & (GCP_GLYPHSHAPE | GCP_LIGATE))
|
|
pResults->nGlyphs = psa->cOutGlyphs;
|
|
else
|
|
pResults->nGlyphs = cInChars;
|
|
|
|
pResults->nMaxFit = psa->cOutChars;
|
|
|
|
|
|
// If there was justification we may have zero glyphs
|
|
|
|
if (!psa->cOutGlyphs) {
|
|
|
|
pResults->nGlyphs = 0;
|
|
|
|
ScriptStringFree((void**)&psa);
|
|
|
|
|
|
// Weird Middle East Win95 compatability rules
|
|
|
|
if ( (dwFlags & GCP_MAXEXTENT)
|
|
|| !(dwFlags & GCP_GLYPHSHAPE)
|
|
|| !pResults->lpGlyphs) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 4-Generate lpCaretPos //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
if (pResults->lpCaretPos) {
|
|
char *pbClass = NULL;
|
|
INT *piAdvance = pResults->lpDx ? pResults->lpDx : psa->piAdvance;
|
|
UINT *puiOrder = NULL;
|
|
INT *pCaretCalc;
|
|
INT iWidth = 0;
|
|
UINT j, uOrder;
|
|
|
|
hr = USPALLOC(sizeof(INT)*pResults->nGlyphs, (void **)&pCaretCalc);
|
|
|
|
if(FAILED(hr)) {
|
|
ScriptStringFree((void**)&psa);
|
|
return 0;
|
|
}
|
|
|
|
// Allocate for pbClass if pResults->lpClass is NULL otherwise us it.
|
|
if (pResults->lpClass == NULL) {
|
|
hr = USPALLOC(sizeof(char)*cInChars, (void **)&pbClass);
|
|
if(FAILED(hr)) {
|
|
USPFREE(pCaretCalc);
|
|
ScriptStringFree((void**)&psa);
|
|
return 0;
|
|
}
|
|
GCPgenerateClass(psa, (PBYTE) pbClass);
|
|
} else {
|
|
pbClass = pResults->lpClass;
|
|
}
|
|
|
|
// Allocate for puiOrder if pResults->lpOrder is NULL otherwise us it.
|
|
if (pResults->lpOrder == NULL) {
|
|
hr = USPALLOC(sizeof(UINT)*cInChars, (void **)&puiOrder);
|
|
if(FAILED(hr)) {
|
|
if (pResults->lpClass == NULL) {
|
|
USPFREE(pbClass);
|
|
}
|
|
USPFREE(pCaretCalc);
|
|
ScriptStringFree((void**)&psa);
|
|
return 0;
|
|
}
|
|
ScriptStringGetOrder(psa, puiOrder);
|
|
} else {
|
|
puiOrder = pResults->lpOrder;
|
|
}
|
|
|
|
// simple-minded loop used to generate glyph-offsets
|
|
// as the same code used in NT4/MET.
|
|
|
|
UINT caretPosCount = min(pResults->nGlyphs, (UINT)cInChars);
|
|
|
|
for( j=0 ; j<caretPosCount ; j++ ) {
|
|
if (pbClass[j] == GCPCLASS_ARABIC) {
|
|
iWidth += piAdvance[j];
|
|
pCaretCalc[j] = iWidth - 1;
|
|
if (iWidth == 0) {
|
|
pCaretCalc[j] = 0;
|
|
}
|
|
} else {
|
|
pCaretCalc[j] = iWidth;
|
|
iWidth += piAdvance[j];
|
|
}
|
|
}
|
|
|
|
if (pResults->nGlyphs > (UINT)cInChars)
|
|
{
|
|
for( j=cInChars ; j<pResults->nGlyphs ; j++)
|
|
{
|
|
pCaretCalc[j] = iWidth;
|
|
iWidth += piAdvance[j];
|
|
}
|
|
}
|
|
|
|
// Convert to char-indexing. We need to take care if the
|
|
// user supplied in sufficient visual buffers
|
|
for( j=0 ; j<(UINT)cInChars ; j++ ) {
|
|
uOrder = puiOrder[j];
|
|
if ((uOrder+1) > (UINT)psa->cOutGlyphs) {
|
|
uOrder = 0;
|
|
}
|
|
pResults->lpCaretPos[j] = pCaretCalc[uOrder];
|
|
}
|
|
|
|
if (pResults->lpOrder == NULL) {
|
|
USPFREE(puiOrder);
|
|
}
|
|
if (pResults->lpClass == NULL) {
|
|
USPFREE(pbClass);
|
|
}
|
|
USPFREE(pCaretCalc);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 5 - Return width and height //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
dwRet = (psa->size.cx & 0xffff) + (psa->size.cy << 16);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 6 - Free allocated memory and exit //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ScriptStringFree((void**)&psa);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL LpkUseGDIWidthCache( HDC hDC , LPCSTR psz , int count ,
|
|
* LONG fl , BOOL fUnicode)
|
|
*
|
|
* Checks whether the LPK can use GDI cached widths for the ASCII (0<=x<=127)
|
|
* by inspecting the following variables :
|
|
* - System numeric shape setting
|
|
* - DC Align state
|
|
* - The selected font has Western script
|
|
* - The string code points in range 0<=x<=127 with Ansi calls
|
|
*
|
|
* Returns TRUE if it is OK to use GDI width cache, otherwise FALSE
|
|
*
|
|
* History:
|
|
* 28-Aug-1997 -by- Samer Arafeh [SamerA]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
BOOL LpkUseGDIWidthCache( HDC hDC , LPCSTR psz , int count , LONG fl , BOOL fUnicode)
|
|
{
|
|
BOOL bRet;
|
|
int i;
|
|
BYTE cTest;
|
|
LPSTR pstr;
|
|
|
|
//
|
|
// Let's make sure that :
|
|
// 1- Text is LTR Reading
|
|
// 2- Digits shape setting is Arabic
|
|
// 3- if Unicode call, make sure the font has Western script
|
|
// if Ansi call check if all code points less than 0x80 and font has Wetern script.
|
|
|
|
bRet = (!!(fl & TA_RTLREADING) == !!(GetLayout(hDC) & LAYOUT_RTL))
|
|
&& g_DigitSubstitute.DigitSubstitute == SCRIPT_DIGITSUBSTITUTE_NONE;
|
|
|
|
TRACE( GDI, ("LpkUseGDIWidthCache: g_DigitSubstitute.DigitSubstitute=%x, bRet=%x",
|
|
g_DigitSubstitute.DigitSubstitute, bRet));
|
|
|
|
|
|
if (bRet) {
|
|
|
|
// We don't need this check for Unicdoe calls because it is done in GDI.
|
|
if (!fUnicode) {
|
|
cTest = 0;
|
|
i = count;
|
|
pstr = (LPSTR) psz;
|
|
|
|
unroll_here:
|
|
switch(i)
|
|
{
|
|
default:
|
|
cTest |= pstr[9];
|
|
case 9:
|
|
cTest |= pstr[8];
|
|
case 8:
|
|
cTest |= pstr[7];
|
|
case 7:
|
|
cTest |= pstr[6];
|
|
case 6:
|
|
cTest |= pstr[5];
|
|
case 5:
|
|
cTest |= pstr[4];
|
|
case 4:
|
|
cTest |= pstr[3];
|
|
case 3:
|
|
cTest |= pstr[2];
|
|
case 2:
|
|
cTest |= pstr[1];
|
|
case 1:
|
|
cTest |= pstr[0];
|
|
}
|
|
|
|
if ((i > 10) && !(cTest & 0x80))
|
|
{
|
|
i -= 10;
|
|
pstr += 10;
|
|
goto unroll_here;
|
|
}
|
|
|
|
bRet = !(cTest & 0x80);
|
|
}
|
|
|
|
return (bRet && FontHasWesternScript(hDC));
|
|
}
|
|
|
|
return bRet ;
|
|
}
|
|
|