[GDI32][LPK] BiDi support for ExtTextOut and GetCharacterPlacement (#534)

Introduce BiDi (bi-directional text) support for ExtTextOut and GetCharacterPlacement, using Wine's GDI BIDI_Reorder function.
Solves the main issue with CORE-7003.

To be compatible with Win2k3+, introduce the "Language Pack" (LPK) dll.
- All the bidi code is removed from gdi32 and replaced by calls to LPK.
  Gdi32 uses dynamic linking to lpk.dll. In case of linking failure no bidi processing will be available.
- Implemented LpkGetCharacterPlacement.
- Implement LpkExtTextOut.
- Add a demo test program to show how the apis should function.
- Added all the remaining code, added special case for lpDx calculation if also GCP_GLYPHSHAPE flag was called.
  Applications that call GCP that use GCP_GLYPHSHAPE flags should also use the GCP_REORDER flag.
  (As written in https://msdn.microsoft.com/en-us/library/windows/desktop/dd144860(v=vs.85).aspx )
- Add ETO_RTLREADING flag handling.
  Imported the ETO_RTLREADING flag handling from wine, which changes the string part order (runs).
  A RRR1LLLRRR2 string without will show as RRR1LLLRRR2 without it, with it RRR2LLLRRR1.
This commit is contained in:
Baruch Rutman 2018-05-30 15:41:22 +03:00 committed by Hermès BÉLUSCA - MAÏTO
parent 3ca1ac639c
commit a4a59ad413
19 changed files with 1434 additions and 86 deletions

View file

@ -1,10 +1,11 @@
add_definitions(-DLANGPACK)
include_directories(include)
spec2def(lpk.dll lpk.spec)
spec2def(lpk.dll lpk.spec ADD_IMPORTLIB)
list(APPEND SOURCE
dllmain.c
bidi.c
lpk.c
stub.c
ros_lpk.h)
@ -14,6 +15,9 @@ add_library(lpk SHARED
${CMAKE_CURRENT_BINARY_DIR}/lpk.def)
set_module_type(lpk win32dll UNICODE)
add_importlibs(lpk user32 usp10 msvcrt kernel32 ntdll)
target_link_libraries(lpk wine)
add_importlibs(lpk usp10 user32 gdi32 msvcrt kernel32 ntdll)
add_pch(lpk ros_lpk.h SOURCE)
add_cd_file(TARGET lpk DESTINATION reactos/system32 FOR all)

687
dll/win32/lpk/bidi.c Normal file
View file

@ -0,0 +1,687 @@
/*
* GDI BiDirectional handling
*
* Copyright 2003 Shachar Shemesh
* Copyright 2007 Maarten Lankhorst
* 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
*
* Code derived from the modified reference implementation
* that was found in revision 17 of http://unicode.org/reports/tr9/
* "Unicode Standard Annex #9: THE BIDIRECTIONAL ALGORITHM"
*
* -- Copyright (C) 1999-2005, ASMUS, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of the Unicode data files and any associated documentation (the
* "Data Files") or Unicode software and any associated documentation (the
* "Software") to deal in the Data Files or Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, and/or sell copies of the Data Files or Software,
* and to permit persons to whom the Data Files or Software are furnished
* to do so, provided that (a) the above copyright notice(s) and this
* permission notice appear with all copies of the Data Files or Software,
* (b) both the above copyright notice(s) and this permission notice appear
* in associated documentation, and (c) there is clear notice in each
* modified Data File or in the Software as well as in the documentation
* associated with the Data File(s) or Software that the data or software
* has been modified.
*/
#include "ros_lpk.h"
#include "wine/unicode.h"
#include "wine/debug.h"
//#include "config.h"
//#include "gdi_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(bidi);
/* HELPER FUNCTIONS AND DECLARATIONS */
#define odd(x) ((x) & 1)
/*------------------------------------------------------------------------
Bidirectional Character Types
as defined by the Unicode Bidirectional Algorithm Table 3-7.
Note:
The list of bidirectional character types here is not grouped the
same way as the table 3-7, since the numberic values for the types
are chosen to keep the state and action tables compact.
------------------------------------------------------------------------*/
enum directions
{
/* input types */
/* ON MUST be zero, code relies on ON = N = 0 */
ON = 0, /* Other Neutral */
L, /* Left Letter */
R, /* Right Letter */
AN, /* Arabic Number */
EN, /* European Number */
AL, /* Arabic Letter (Right-to-left) */
NSM, /* Non-spacing Mark */
CS, /* Common Separator */
ES, /* European Separator */
ET, /* European Terminator (post/prefix e.g. $ and %) */
/* resolved types */
BN, /* Boundary neutral (type of RLE etc after explicit levels) */
/* input types, */
S, /* Segment Separator (TAB) // used only in L1 */
WS, /* White space // used only in L1 */
B, /* Paragraph Separator (aka as PS) */
/* types for explicit controls */
RLO, /* these are used only in X1-X9 */
RLE,
LRO,
LRE,
PDF,
/* resolved types, also resolved directions */
N = ON, /* alias, where ON, WS and S are treated the same */
};
/* HELPER FUNCTIONS */
/* Convert the libwine information to the direction enum */
static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount)
{
static const enum directions dir_map[16] =
{
L, /* unassigned defaults to L */
L,
R,
EN,
ES,
ET,
AN,
CS,
B,
S,
WS,
ON,
AL,
NSM,
BN,
PDF /* also LRE, LRO, RLE, RLO */
};
unsigned i;
for (i = 0; i < uCount; ++i)
{
chartype[i] = dir_map[get_char_typeW(lpString[i]) >> 12];
if (chartype[i] == PDF)
{
switch (lpString[i])
{
case 0x202A: chartype[i] = LRE; break;
case 0x202B: chartype[i] = RLE; break;
case 0x202C: chartype[i] = PDF; break;
case 0x202D: chartype[i] = LRO; break;
case 0x202E: chartype[i] = RLO; break;
}
}
}
}
/* Set a run of cval values at locations all prior to, but not including */
/* iStart, to the new value nval. */
static void SetDeferredRun(BYTE *pval, int cval, int iStart, int nval)
{
int i = iStart - 1;
for (; i >= iStart - cval; i--)
{
pval[i] = nval;
}
}
/* THE PARAGRAPH LEVEL */
/*------------------------------------------------------------------------
Function: resolveParagraphs
Resolves the input strings into blocks over which the algorithm
is then applied.
Implements Rule P1 of the Unicode Bidi Algorithm
Input: Text string
Character count
Output: revised character count
Note: This is a very simplistic function. In effect it restricts
the action of the algorithm to the first paragraph in the input
where a paragraph ends at the end of the first block separator
or at the end of the input text.
------------------------------------------------------------------------*/
static int resolveParagraphs(WORD *types, int cch)
{
/* skip characters not of type B */
int ich = 0;
for(; ich < cch && types[ich] != B; ich++);
/* stop after first B, make it a BN for use in the next steps */
if (ich < cch && types[ich] == B)
types[ich++] = BN;
return ich;
}
/* REORDER */
/*------------------------------------------------------------------------
Function: resolveLines
Breaks a paragraph into lines
Input: Array of line break flags
Character count
In/Out: Array of characters
Returns the count of characters on the first line
Note: This function only breaks lines at hard line breaks. Other
line breaks can be passed in. If pbrk[n] is TRUE, then a break
occurs after the character in pszInput[n]. Breaks before the first
character are not allowed.
------------------------------------------------------------------------*/
static int resolveLines(LPCWSTR pszInput, const BOOL * pbrk, int cch)
{
/* skip characters not of type LS */
int ich = 0;
for(; ich < cch; ich++)
{
if (pszInput[ich] == (WCHAR)'\n' || (pbrk && pbrk[ich]))
{
ich++;
break;
}
}
return ich;
}
/*------------------------------------------------------------------------
Function: resolveWhiteSpace
Resolves levels for WS and S
Implements rule L1 of the Unicode bidi Algorithm.
Input: Base embedding level
Character count
Array of direction classes (for one line of text)
In/Out: Array of embedding levels (for one line of text)
Note: this should be applied a line at a time. The default driver
code supplied in this file assumes a single line of text; for
a real implementation, cch and the initial pointer values
would have to be adjusted.
------------------------------------------------------------------------*/
static void resolveWhitespace(int baselevel, const WORD *pcls, BYTE *plevel, int cch)
{
int cchrun = 0;
BYTE oldlevel = baselevel;
int ich = 0;
for (; ich < cch; ich++)
{
switch(pcls[ich])
{
default:
cchrun = 0; /* any other character breaks the run */
break;
case WS:
cchrun++;
break;
case RLE:
case LRE:
case LRO:
case RLO:
case PDF:
case BN:
plevel[ich] = oldlevel;
cchrun++;
break;
case S:
case B:
/* reset levels for WS before eot */
SetDeferredRun(plevel, cchrun, ich, baselevel);
cchrun = 0;
plevel[ich] = baselevel;
break;
}
oldlevel = plevel[ich];
}
/* reset level before eot */
SetDeferredRun(plevel, cchrun, ich, baselevel);
}
/*------------------------------------------------------------------------
Function: BidiLines
Implements the Line-by-Line phases of the Unicode Bidi Algorithm
Input: Count of characters
Array of character directions
Inp/Out: Input text
Array of levels
------------------------------------------------------------------------*/
static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, const WORD * pclsLine,
BYTE * plevelLine, int cchPara, const BOOL * pbrk)
{
int cchLine = 0;
int done = 0;
int *run;
run = HeapAlloc(GetProcessHeap(), 0, cchPara * sizeof(int));
if (!run)
{
WARN("Out of memory\n");
return;
}
do
{
/* break lines at LS */
cchLine = resolveLines(pszLine, pbrk, cchPara);
/* resolve whitespace */
resolveWhitespace(baselevel, pclsLine, plevelLine, cchLine);
if (pszOutLine)
{
int i;
/* reorder each line in place */
ScriptLayout(cchLine, plevelLine, NULL, run);
for (i = 0; i < cchLine; i++)
pszOutLine[done+run[i]] = pszLine[i];
}
pszLine += cchLine;
plevelLine += cchLine;
pbrk += pbrk ? cchLine : 0;
pclsLine += cchLine;
cchPara -= cchLine;
done += cchLine;
} while (cchPara);
HeapFree(GetProcessHeap(), 0, run);
}
/*************************************************************
* BIDI_Reorder
*
* Returns TRUE if reordering was required and done.
*/
BOOL BIDI_Reorder(
HDC hDC, /*[in] Display DC */
LPCWSTR lpString, /* [in] The string for which information is to be returned */
INT uCount, /* [in] Number of WCHARs in string. */
DWORD dwFlags, /* [in] GetCharacterPlacement compatible flags specifying how to process the string */
DWORD dwWineGCP_Flags, /* [in] Wine internal flags - Force paragraph direction */
LPWSTR lpOutString, /* [out] Reordered string */
INT uCountOut, /* [in] Size of output buffer */
UINT *lpOrder, /* [out] Logical -> Visual order map */
WORD **lpGlyphs, /* [out] reordered, mirrored, shaped glyphs to display */
INT *cGlyphs /* [out] number of glyphs generated */
)
{
WORD *chartype;
BYTE *levels;
INT i, done;
unsigned glyph_i;
BOOL is_complex;
int maxItems;
int nItems;
SCRIPT_CONTROL Control;
SCRIPT_STATE State;
SCRIPT_ITEM *pItems;
HRESULT res;
SCRIPT_CACHE psc = NULL;
WORD *run_glyphs = NULL;
WORD *pwLogClust = NULL;
SCRIPT_VISATTR *psva = NULL;
DWORD cMaxGlyphs = 0;
BOOL doGlyphs = TRUE;
TRACE("%s, %d, 0x%08x lpOutString=%p, lpOrder=%p\n",
debugstr_wn(lpString, uCount), uCount, dwFlags,
lpOutString, lpOrder);
memset(&Control, 0, sizeof(Control));
memset(&State, 0, sizeof(State));
if (lpGlyphs)
*lpGlyphs = NULL;
if (!(dwFlags & GCP_REORDER))
{
FIXME("Asked to reorder without reorder flag set\n");
return FALSE;
}
if (lpOutString && uCountOut < uCount)
{
FIXME("lpOutString too small\n");
return FALSE;
}
chartype = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD));
if (!chartype)
{
WARN("Out of memory\n");
return FALSE;
}
if (lpOutString)
memcpy(lpOutString, lpString, uCount * sizeof(WCHAR));
is_complex = FALSE;
for (i = 0; i < uCount && !is_complex; i++)
{
if ((lpString[i] >= 0x900 && lpString[i] <= 0xfff) ||
(lpString[i] >= 0x1cd0 && lpString[i] <= 0x1cff) ||
(lpString[i] >= 0xa840 && lpString[i] <= 0xa8ff))
is_complex = TRUE;
}
/* Verify reordering will be required */
if ((WINE_GCPW_FORCE_RTL == (dwWineGCP_Flags&WINE_GCPW_DIR_MASK)) ||
((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL))
State.uBidiLevel = 1;
else if (!is_complex)
{
done = 1;
classify(lpString, chartype, uCount);
for (i = 0; i < uCount; i++)
switch (chartype[i])
{
case R:
case AL:
case RLE:
case RLO:
done = 0;
break;
}
if (done)
{
HeapFree(GetProcessHeap(), 0, chartype);
if (lpOrder)
{
for (i = 0; i < uCount; i++)
lpOrder[i] = i;
}
return TRUE;
}
}
levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(BYTE));
if (!levels)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
return FALSE;
}
maxItems = 5;
pItems = HeapAlloc(GetProcessHeap(),0, maxItems * sizeof(SCRIPT_ITEM));
if (!pItems)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
return FALSE;
}
if (lpGlyphs)
{
cMaxGlyphs = 1.5 * uCount + 16;
run_glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * cMaxGlyphs);
if (!run_glyphs)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
return FALSE;
}
pwLogClust = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * uCount);
if (!pwLogClust)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, run_glyphs);
return FALSE;
}
psva = HeapAlloc(GetProcessHeap(),0,sizeof(SCRIPT_VISATTR) * uCount);
if (!psva)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, run_glyphs);
HeapFree(GetProcessHeap(), 0, pwLogClust);
return FALSE;
}
}
done = 0;
glyph_i = 0;
while (done < uCount)
{
INT j;
classify(lpString + done, chartype, uCount - done);
/* limit text to first block */
i = resolveParagraphs(chartype, uCount - done);
for (j = 0; j < i; ++j)
switch(chartype[j])
{
case B:
case S:
case WS:
case ON: chartype[j] = N;
default: continue;
}
if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL)
State.uBidiLevel = 1;
else if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_LTR)
State.uBidiLevel = 0;
if (dwWineGCP_Flags & WINE_GCPW_LOOSE_MASK)
{
for (j = 0; j < i; ++j)
if (chartype[j] == L)
{
State.uBidiLevel = 0;
break;
}
else if (chartype[j] == R || chartype[j] == AL)
{
State.uBidiLevel = 1;
break;
}
}
res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
while (res == E_OUTOFMEMORY)
{
maxItems = maxItems * 2;
pItems = HeapReAlloc(GetProcessHeap(), 0, pItems, sizeof(SCRIPT_ITEM) * maxItems);
if (!pItems)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, run_glyphs);
HeapFree(GetProcessHeap(), 0, pwLogClust);
HeapFree(GetProcessHeap(), 0, psva);
return FALSE;
}
res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
}
if (lpOutString || lpOrder)
for (j = 0; j < nItems; j++)
{
int k;
for (k = pItems[j].iCharPos; k < pItems[j+1].iCharPos; k++)
levels[k] = pItems[j].a.s.uBidiLevel;
}
if (lpOutString)
{
/* assign directional types again, but for WS, S this time */
classify(lpString + done, chartype, i);
BidiLines(State.uBidiLevel, lpOutString + done, lpString + done,
chartype, levels, i, 0);
}
if (lpOrder)
{
int k, lastgood;
for (j = lastgood = 0; j < i; ++j)
if (levels[j] != levels[lastgood])
{
--j;
if (odd(levels[lastgood]))
for (k = j; k >= lastgood; --k)
lpOrder[done + k] = done + j - k;
else
for (k = lastgood; k <= j; ++k)
lpOrder[done + k] = done + k;
lastgood = ++j;
}
if (odd(levels[lastgood]))
for (k = j - 1; k >= lastgood; --k)
lpOrder[done + k] = done + j - 1 - k;
else
for (k = lastgood; k < j; ++k)
lpOrder[done + k] = done + k;
}
if (lpGlyphs && doGlyphs)
{
BYTE *runOrder;
int *visOrder;
SCRIPT_ITEM *curItem;
runOrder = HeapAlloc(GetProcessHeap(), 0, maxItems * sizeof(*runOrder));
visOrder = HeapAlloc(GetProcessHeap(), 0, maxItems * sizeof(*visOrder));
if (!runOrder || !visOrder)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, runOrder);
HeapFree(GetProcessHeap(), 0, visOrder);
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, psva);
HeapFree(GetProcessHeap(), 0, pwLogClust);
return FALSE;
}
for (j = 0; j < nItems; j++)
runOrder[j] = pItems[j].a.s.uBidiLevel;
ScriptLayout(nItems, runOrder, visOrder, NULL);
for (j = 0; j < nItems; j++)
{
int k;
int cChars,cOutGlyphs;
curItem = &pItems[visOrder[j]];
cChars = pItems[visOrder[j]+1].iCharPos - curItem->iCharPos;
res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
while (res == E_OUTOFMEMORY)
{
cMaxGlyphs *= 2;
run_glyphs = HeapReAlloc(GetProcessHeap(), 0, run_glyphs, sizeof(WORD) * cMaxGlyphs);
if (!run_glyphs)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, runOrder);
HeapFree(GetProcessHeap(), 0, visOrder);
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, psva);
HeapFree(GetProcessHeap(), 0, pwLogClust);
HeapFree(GetProcessHeap(), 0, *lpGlyphs);
ScriptFreeCache(&psc);
*lpGlyphs = NULL;
return FALSE;
}
res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
}
if (res)
{
if (res == USP_E_SCRIPT_NOT_IN_FONT)
TRACE("Unable to shape with currently selected font\n");
else
FIXME("Unable to shape string (%x)\n",res);
j = nItems;
doGlyphs = FALSE;
HeapFree(GetProcessHeap(), 0, *lpGlyphs);
*lpGlyphs = NULL;
}
else
{
if (*lpGlyphs)
*lpGlyphs = HeapReAlloc(GetProcessHeap(), 0, *lpGlyphs, sizeof(WORD) * (glyph_i + cOutGlyphs));
else
*lpGlyphs = HeapAlloc(GetProcessHeap(), 0, sizeof(WORD) * (glyph_i + cOutGlyphs));
for (k = 0; k < cOutGlyphs; k++)
(*lpGlyphs)[glyph_i+k] = run_glyphs[k];
glyph_i += cOutGlyphs;
}
}
HeapFree(GetProcessHeap(), 0, runOrder);
HeapFree(GetProcessHeap(), 0, visOrder);
}
done += i;
}
if (cGlyphs)
*cGlyphs = glyph_i;
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, run_glyphs);
HeapFree(GetProcessHeap(), 0, pwLogClust);
HeapFree(GetProcessHeap(), 0, psva);
ScriptFreeCache(&psc);
return TRUE;
}

View file

@ -1,47 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS
* PURPOSE: LPK Library
* PROGRAMMER: Magnus Olsen (greatlrd)
*
*/
#include "ros_lpk.h"
LPK_LPEDITCONTROL_LIST LpkEditControl = {EditCreate, EditIchToXY, EditMouseToIch, EditCchInWidth,
EditGetLineWidth, EditDrawText, EditHScroll, EditMoveSelection,
EditVerifyText, EditNextWord, EditSetMenu, EditProcessMenu,
EditCreateCaret, EditAdjustCaret};
BOOL
WINAPI
DllMain (
HANDLE hDll,
DWORD dwReason,
LPVOID lpReserved)
{
return LpkDllInitialize(hDll,dwReason,lpReserved);
}
BOOL
WINAPI
LpkDllInitialize (
HANDLE hDll,
DWORD dwReason,
LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hDll);
/* Tell usp10 it is activated usp10 */
//LpkPresent();
break;
default:
break;
}
return TRUE;
}

181
dll/win32/lpk/lpk.c Normal file
View file

@ -0,0 +1,181 @@
/*
* PROJECT: ReactOS LPK
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Language Pack DLL.
* PROGRAMMERS: Magnus Olsen (greatlrd)
* Baruch Rutman (peterooch at gmail dot com)
*/
#include "ros_lpk.h"
LPK_LPEDITCONTROL_LIST LpkEditControl = {EditCreate, EditIchToXY, EditMouseToIch, EditCchInWidth,
EditGetLineWidth, EditDrawText, EditHScroll, EditMoveSelection,
EditVerifyText, EditNextWord, EditSetMenu, EditProcessMenu,
EditCreateCaret, EditAdjustCaret};
BOOL
WINAPI
DllMain(
HANDLE hDll,
DWORD dwReason,
LPVOID lpReserved)
{
return LpkDllInitialize(hDll,dwReason,lpReserved);
}
BOOL
WINAPI
LpkDllInitialize(
HANDLE hDll,
DWORD dwReason,
LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hDll);
/* Tell usp10 it is activated usp10 */
//LpkPresent();
break;
default:
break;
}
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
LpkExtTextOut(
HDC hdc,
int x,
int y,
UINT fuOptions,
const RECT *lprc,
LPCWSTR lpString,
UINT uCount,
const INT *lpDx,
INT unknown)
{
LPWORD glyphs = NULL;
INT cGlyphs;
UNREFERENCED_PARAMETER(unknown);
if (!(fuOptions & ETO_IGNORELANGUAGE))
fuOptions |= ETO_IGNORELANGUAGE;
/* Check text direction */
if ((GetLayout(hdc) & LAYOUT_RTL) || (GetTextAlign(hdc) & TA_RTLREADING))
{
if (!(fuOptions & ETO_RTLREADING))
fuOptions |= ETO_RTLREADING;
}
/* Check if the string requires complex script processing and not a "glyph indices" array */
if (ScriptIsComplex(lpString, uCount, SIC_COMPLEX) == S_OK && !(fuOptions & ETO_GLYPH_INDEX))
{
BIDI_Reorder(hdc, lpString, uCount, GCP_REORDER,
(fuOptions & ETO_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
NULL, uCount, NULL, &glyphs, &cGlyphs);
fuOptions |= ETO_GLYPH_INDEX;
if (uCount > cGlyphs)
cGlyphs = uCount;
return ExtTextOutW(hdc, x, y, fuOptions, lprc, (LPWSTR)glyphs, cGlyphs, lpDx);
}
return ExtTextOutW(hdc, x, y, fuOptions, lprc, lpString, uCount, lpDx);
}
/*
* @implemented
*/
DWORD
WINAPI
LpkGetCharacterPlacement(
HDC hdc,
LPCWSTR lpString,
INT uCount,
INT nMaxExtent,
LPGCP_RESULTSW lpResults,
DWORD dwFlags,
DWORD dwUnused)
{
LPWORD lpGlyphs = NULL;
SIZE size;
DWORD ret = 0;
UINT nSet, i;
INT cGlyphs;
UNREFERENCED_PARAMETER(dwUnused);
/* Sanity check (most likely a direct call) */
if (!(dwFlags & GCP_REORDER))
return GetCharacterPlacementW(hdc, lpString, uCount, nMaxExtent, lpResults, dwFlags);
nSet = (UINT)uCount;
if (nSet > lpResults->nGlyphs)
nSet = lpResults->nGlyphs;
BIDI_Reorder(hdc, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
nSet, lpResults->lpOrder, &lpGlyphs, &cGlyphs);
lpResults->nGlyphs = (UINT)cGlyphs;
if (lpResults->lpGlyphs)
wcscpy(lpResults->lpGlyphs, lpGlyphs);
if (lpResults->lpDx && !(dwFlags & GCP_GLYPHSHAPE))
{
int c;
for (i = 0; i < nSet; i++)
{
if (GetCharWidth32W(hdc, lpResults->lpOutString[i], lpResults->lpOutString[i], &c))
lpResults->lpDx[i] = c;
}
}
/* If glyph shaping was requested */
else if (lpResults->lpDx && (dwFlags & GCP_GLYPHSHAPE))
{
int c;
if (lpResults->lpGlyphs)
{
for (i = 0; i < lpResults->nGlyphs; i++)
{
if (GetCharWidth32W(hdc, lpGlyphs[i], lpGlyphs[i], &c))
lpResults->lpDx[i] = c;
}
}
}
/* FIXME: Currently not bidi compliant! */
if (lpResults->lpCaretPos)
{
int pos = 0;
lpResults->lpCaretPos[0] = 0;
for (i = 1; i < nSet; i++)
{
if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
lpResults->lpCaretPos[i] = (pos += size.cx);
}
}
if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
ret = MAKELONG(size.cx, size.cy);
HeapFree(GetProcessHeap(), 0, lpGlyphs);
return ret;
}

View file

@ -3,8 +3,8 @@
@ stdcall LpkDllInitialize(ptr long ptr)
@ stdcall LpkDrawTextEx(long long long long long long long long long long)
@ extern LpkEditControl
@ stdcall LpkExtTextOut(long long long long long long long long long)
@ stdcall LpkGetCharacterPlacement(long long long long long long long)
@ stdcall LpkExtTextOut(long long long long ptr wstr long ptr long)
@ stdcall LpkGetCharacterPlacement(long wstr long long ptr long long)
@ stdcall LpkGetTextExtentExPoint(long long long long long long long long long)
@ stdcall LpkPSMTextOut(long long long long long long)
@ stdcall LpkUseGDIWidthCache(long long long long long)

View file

@ -14,6 +14,9 @@
#define WIN32_NO_STATUS
#include <windef.h>
#include <winbase.h>
#include <wingdi.h>
#include <winnls.h>
#include <usp10.h>
/* FIXME USP10 api that does not have prototype in any include file */
VOID WINAPI LpkPresent(VOID);
@ -61,11 +64,38 @@ DWORD WINAPI LpkInitialize(DWORD x1);
DWORD WINAPI LpkTabbedTextOut(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8,DWORD x9,DWORD x10,DWORD x11,DWORD x12);
BOOL WINAPI LpkDllInitialize (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
DWORD WINAPI LpkDrawTextEx(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8,DWORD x9, DWORD x10);
DWORD WINAPI LpkExtTextOut(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8,DWORD x9);
DWORD WINAPI LpkGetCharacterPlacement(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6, DWORD x7);
DWORD WINAPI LpkGetTextExtentExPoint(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8,DWORD x9);
DWORD WINAPI LpkPSMTextOut(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6);
DWORD WINAPI LpkUseGDIWidthCache(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5);
DWORD WINAPI ftsWordBreak(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5);
/* Implemented */
BOOL WINAPI LpkExtTextOut(HDC hdc, int x, int y, UINT fuOptions, const RECT *lprc,
LPCWSTR lpString, UINT uCount , const INT *lpDx, INT unknown);
DWORD WINAPI LpkGetCharacterPlacement(HDC hdc, LPCWSTR lpString, INT uCount, INT nMaxExtent,
GCP_RESULTSW *lpResults, DWORD dwFlags, DWORD dwUnused);
/* bidi.c */
#define WINE_GCPW_FORCE_LTR 0
#define WINE_GCPW_FORCE_RTL 1
#define WINE_GCPW_LOOSE_LTR 2
#define WINE_GCPW_LOOSE_RTL 3
#define WINE_GCPW_DIR_MASK 3
#define WINE_GCPW_LOOSE_MASK 2
BOOL BIDI_Reorder(
_In_ HDC hDC, /* [in] Display DC */
_In_ LPCWSTR lpString, /* [in] The string for which information is to be returned */
_In_ INT uCount, /* [in] Number of WCHARs in string. */
_In_ DWORD dwFlags, /* [in] GetCharacterPlacement compatible flags specifying how to process the string */
_In_ DWORD dwWineGCP_Flags, /* [in] Wine internal flags - Force paragraph direction */
_Out_ LPWSTR lpOutString, /* [out] Reordered string */
_In_ INT uCountOut, /* [in] Size of output buffer */
_Out_ UINT *lpOrder, /* [out] Logical -> Visual order map */
_Out_ WORD **lpGlyphs, /* [out] reordered, mirrored, shaped glyphs to display */
_Out_ INT *cGlyphs /* [out] number of glyphs generated */
);
#endif /* _LPK_H */

View file

@ -39,24 +39,6 @@ DWORD WINAPI LpkDrawTextEx(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6
return 0;
}
/*
* @unimplemented
*/
DWORD WINAPI LpkExtTextOut(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8,DWORD x9)
{
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/
DWORD WINAPI LpkGetCharacterPlacement(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6, DWORD x7)
{
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/

View file

@ -286,6 +286,9 @@ kernel32 -
reactos/dll/win32/kernel32/winnls/string/nls.c # Synced in r52754
reactos/dll/win32/kernel32/winnls/string/sortkey.c # Synced to WineStaging-3.3
lpk -
reactos/dll/win32/lpk/bidi.c # Synced to WineStaging-3.7
msvcrt -
reactos/sdk/lib/crt/conio/cputs.c # Synced to WineStaging-1.9.16
reactos/sdk/lib/crt/except/cpp.c # Synced at 20080528

View file

@ -1,2 +1,3 @@
add_subdirectory(biditext)
add_subdirectory(paintdesktop)
add_subdirectory(sysicon)

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Supports Windows Vista / Server 2008 -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Supports Windows 7 / Server 2008 R2 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Supports Windows 8 / Server 2012 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Supports Windows 8.1 / Server 2012 R2 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Supports Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
</assembly>

View file

@ -0,0 +1,6 @@
add_rc_deps(biditext.rc ${CMAKE_CURRENT_SOURCE_DIR}/Application.ico)
add_executable(biditext biditext.c biditext.rc)
set_module_type(biditext win32gui UNICODE)
add_importlibs(biditext lpk gdi32 user32 shell32 comctl32 msvcrt kernel32 ntdll)
add_rostests_file(TARGET biditext SUBDIR suppl)

View file

@ -0,0 +1,273 @@
/*
* PROJECT: ReactOS Tests
* FILE: rostests/win32/user32/biditext/biditext.c
* PURPOSE: Demonstrates how ExtTextOut and GetCharacterPlacement
* handle bidirectional text strings via certain selection
* of flags provided to them.
*
* PROGRAMMER: Program skeleton: https://github.com/TransmissionZero/MinGW-Win32-Application
* Test code by Baruch Rutman
*/
#include "biditext.h"
/* Prototypes */
DWORD WINAPI LpkGetCharacterPlacement(HDC hdc, LPCWSTR lpString, INT uCount, INT nMaxExtent,
GCP_RESULTSW *lpResults, DWORD dwFlags, DWORD dwUnused);
BOOL WINAPI LpkExtTextOut(HDC hdc, int x, int y,
UINT fuOptions, const RECT *lprc, LPCWSTR lpString,
UINT uCount , const INT *lpDx, INT unknown);
/* Global instance handle */
HINSTANCE g_hInstance = NULL;
/* Our application entry point */
int WINAPI
wWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpszCmdLine,
int nCmdShow)
{
INITCOMMONCONTROLSEX icc;
HWND hWnd;
HACCEL hAccelerators;
MSG msg;
/* Assign global HINSTANCE */
g_hInstance = hInstance;
/* Initialise common controls */
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icc);
/* Register our main window class, or error */
if (!RegisterMainWindowClass())
{
MessageBox(NULL, TEXT("Error registering main window class."), TEXT("Error"), MB_ICONERROR | MB_OK);
return 0;
}
/* Create our main window, or error */
if (!(hWnd = CreateMainWindow()))
{
MessageBox(NULL, TEXT("Error creating main window."), TEXT("Error"), MB_ICONERROR | MB_OK);
return 0;
}
/* Load accelerators */
hAccelerators = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR));
/* Show main window and force a paint */
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
/* Main message loop */
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
if (!TranslateAccelerator(hWnd, hAccelerators, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
/* Dialog procedure for our "about" dialog */
INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
{
WORD id = LOWORD(wParam);
switch (id)
{
case IDOK:
case IDCANCEL:
{
EndDialog(hwndDlg, (INT_PTR)id);
return (INT_PTR)TRUE;
}
}
break;
}
case WM_INITDIALOG:
{
return (INT_PTR)TRUE;
}
}
return (INT_PTR)FALSE;
}
/* Show our "about" dialog */
void ShowAboutDialog(HWND owner)
{
DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ABOUTDIALOG), owner, &AboutDialogProc);
}
/* Main window class and title */
static LPCTSTR MainWndClass = TEXT("BiDi Test");
/* Window procedure for our main window */
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
{
WORD id = LOWORD(wParam);
switch (id)
{
case ID_HELP_ABOUT:
{
ShowAboutDialog(hWnd);
return 0;
}
case ID_FILE_EXIT:
{
DestroyWindow(hWnd);
return 0;
}
}
break;
}
case WM_GETMINMAXINFO:
{
/* Prevent our window from being sized too small */
MINMAXINFO *minMax = (MINMAXINFO*)lParam;
minMax->ptMinTrackSize.x = 220;
minMax->ptMinTrackSize.y = 110;
return 0;
}
/* Item from system menu has been invoked */
case WM_SYSCOMMAND:
{
WORD id = LOWORD(wParam);
switch (id)
{
/* Show "about" dialog on about system menu item */
case ID_HELP_ABOUT:
{
ShowAboutDialog(hWnd);
return 0;
}
}
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
LPWSTR szString = L"אבגדהABCDוזחטי";
int Len = (int)wcslen(szString);
WCHAR Glyphs[100] = { 0 };
WCHAR OutString[100] = { 0 };
GCP_RESULTSW Results = { 0 };
Results.lStructSize = sizeof(Results);
Results.lpOutString = OutString;
Results.lpGlyphs = Glyphs;
Results.nGlyphs = 100;
TextOutW(hdc, 10, 10, L"Proper (string being used):", 27);
TextOutW(hdc, 200, 10, szString, 14);
TextOutW(hdc, 10, 30, L"Reversed (example):", 19);
TextOutW(hdc, 200, 30, L"הדגבאABCDיטחזו", 14);
TextOutW(hdc, 10, 50, L"String with NULL LpkETO call (not reversed):", 44);
LpkExtTextOut(hdc, 10, 70, 0, NULL, szString, Len, NULL, 0);
TextOutW(hdc, 10, 90, L"String with ETO_IGNORELANGUAGE LpkETO call (not reversed):", 58);
LpkExtTextOut(hdc, 10, 110, ETO_IGNORELANGUAGE, NULL, szString, Len, NULL, 0);
TextOutW(hdc, 10, 130, L"String with GCP_REORDER and ETO_GLYPH_INDEX LpkGCP call (not reversed):", 71);
LpkGetCharacterPlacement(hdc, szString, Len, 0, &Results, GCP_REORDER, 0);
LpkExtTextOut(hdc, 10, 150, ETO_GLYPH_INDEX, NULL, Glyphs, Results.nGlyphs, NULL, 0);
TextOutW(hdc, 10, 170, L"String with GCP_REORDER and ETO_IGNORELANGUAGE LpkGCP call (not reversed, lpOutString):", 87);
ExtTextOutW(hdc, 10, 190, ETO_IGNORELANGUAGE, NULL, OutString, Results.nGlyphs, NULL);
TextOutW(hdc, 10, 210, L"String without GCP_REORDER and ETO_GLYPH_INDEX LpkGCP call (reversed):", 70);
LpkGetCharacterPlacement(hdc, szString, Len, 0, &Results, 0, 0);
LpkExtTextOut(hdc, 10, 230, ETO_GLYPH_INDEX, NULL, Glyphs, Results.nGlyphs, NULL, 0);
TextOutW(hdc, 10, 250, L"String without GCP_REORDER and ETO_IGNORELANGUAGE LpkGCP call (reversed, lpOutString):", 86);
ExtTextOutW(hdc, 10, 270, ETO_IGNORELANGUAGE, NULL, OutString, Len, NULL);
TextOutW(hdc, 10, 290, L"String with ETO_IGNORELANGUAGE ETO call (reversed, not Lpk direct call!):", 73);
ExtTextOutW(hdc, 10, 310, ETO_IGNORELANGUAGE, NULL, szString, Len, NULL);
TextOutW(hdc, 10, 330, L"String with ETO_RTLREADING LpkETO call (slight order change)", 60);
LpkExtTextOut(hdc, 10, 350, ETO_RTLREADING, NULL, szString, Len, NULL, 0);
TextOutW(hdc, 10, 370, L"String with ETO_RTLREADING ETO call (slight order change)", 57);
ExtTextOutW(hdc, 10, 390, ETO_RTLREADING, NULL, szString, Len, NULL);
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
/* Register a class for our main window */
BOOL RegisterMainWindowClass()
{
WNDCLASSEX wc;
/* Class for our main window */
wc.cbSize = sizeof(wc);
wc.style = 0;
wc.lpfnWndProc = &MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInstance;
wc.hIcon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE |
LR_DEFAULTCOLOR | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
wc.lpszClassName = MainWndClass;
wc.hIconSm = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
return (RegisterClassEx(&wc)) ? TRUE : FALSE;
}
/* Create an instance of our main window */
HWND CreateMainWindow()
{
/* Create instance of main window */
HWND hWnd = CreateWindowEx(0, MainWndClass, MainWndClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
NULL, NULL, g_hInstance, NULL);
if (hWnd)
{
/* Add "about" to the system menu */
HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
InsertMenu(hSysMenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
InsertMenu(hSysMenu, 6, MF_BYPOSITION, ID_HELP_ABOUT, TEXT("About"));
}
return hWnd;
}

View file

@ -0,0 +1,34 @@
#pragma once
#include <windows.h>
#include <commctrl.h>
/* Global instance handle */
extern HINSTANCE g_hInstance;
/* Window procedure for our main window */
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
/* Register a class for our main window */
BOOL RegisterMainWindowClass(void);
/* Create an instance of our main window */
HWND CreateMainWindow(void);
/* Dialog procedure for our "about" dialog */
INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
/* Show our "about" dialog */
void ShowAboutDialog(HWND owner);
#define IDI_APPICON 101
#define IDR_MAINMENU 102
#define IDR_ACCELERATOR 103
#define IDD_ABOUTDIALOG 104
#define ID_FILE_EXIT 40001
#define ID_HELP_ABOUT 40002
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif

View file

@ -0,0 +1,69 @@
#include "biditext.h"
/* Our main menu */
IDR_MAINMENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", ID_FILE_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About", ID_HELP_ABOUT
END
END
/* Application manifest */
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "Application.manifest"
/* Executable version information */
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG | VS_FF_PRERELEASE
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080904b0"
BEGIN
VALUE "CompanyName", "Transmission Zero"
VALUE "FileDescription", "Win32 Example Application"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "Win32App"
VALUE "LegalCopyright", "©2017 Transmission Zero"
VALUE "OriginalFilename", "Win32App.exe"
VALUE "ProductName", "Win32 Example Application"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x809, 1200
END
END
/* Our "about" dialog */
IDD_ABOUTDIALOG DIALOGEX 0, 0, 147, 67
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
ICON IDI_APPICON,IDC_STATIC,7,7,20,20
LTEXT "Win32 Example Application",IDC_STATIC,34,7,89,8
LTEXT "©2017 Transmission Zero",IDC_STATIC,34,17,86,8
DEFPUSHBUTTON "OK",IDOK,90,46,50,14,WS_GROUP
END
/* Our accelerators */
IDR_ACCELERATOR ACCELERATORS
BEGIN
"A", ID_HELP_ABOUT, VIRTKEY, ALT, NOINVERT
END

View file

@ -27,6 +27,34 @@ typedef INT
HANDLE hPageQuery
);
typedef BOOL
(WINAPI* LPKETO)(
HDC hdc,
int x,
int y,
UINT fuOptions,
const RECT *lprc,
LPCWSTR lpString,
UINT uCount,
const INT *lpDx,
INT unknown
);
typedef DWORD
(WINAPI* LPKGCP)(
HDC hdc,
LPCWSTR lpString,
INT uCount,
INT nMaxExtent,
LPGCP_RESULTSW lpResults,
DWORD dwFlags,
DWORD dwUnused
);
extern HINSTANCE hLpk;
extern LPKETO LpkExtTextOut;
extern LPKGCP LpkGetCharacterPlacement;
/* DEFINES *******************************************************************/
#define HANDLE_LIST_INC 20
@ -36,6 +64,9 @@ typedef INT
#define SAPCALLBACKDELAY 244
#define LPK_ETO 1
#define LPK_GCP 2
/* MACRO ********************************************************************/
#define ROP_USES_SOURCE(Rop) (((Rop) << 2 ^ Rop) & 0xCC0000)
@ -282,6 +313,12 @@ EnumLogFontExW2A(
LPENUMLOGFONTEXA fontA,
CONST ENUMLOGFONTEXW *fontW );
BOOL
WINAPI
LoadLPK(
INT LpkFunctionID
);
BOOL
WINAPI
GetETM(HDC hdc,

View file

@ -448,35 +448,34 @@ GetCharacterPlacementW(
UINT i, nSet;
DPRINT("GetCharacterPlacementW\n");
if(dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
if(lpResults->lpClass) DPRINT("classes not implemented\n");
if (dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
if (lpResults->lpClass) DPRINT("classes not implemented\n");
if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
DPRINT("Caret positions for complex scripts not implemented\n");
nSet = (UINT)uCount;
if(nSet > lpResults->nGlyphs)
if (nSet > lpResults->nGlyphs)
nSet = lpResults->nGlyphs;
/* return number of initialized fields */
lpResults->nGlyphs = nSet;
/*if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
{*/
if (dwFlags & GCP_REORDER)
{
if (LoadLPK(LPK_GCP))
return LpkGetCharacterPlacement(hdc, lpString, uCount, nMaxExtent, lpResults, dwFlags, 0);
}
/* Treat the case where no special handling was requested in a fastpath way */
/* copy will do if the GCP_REORDER flag is not set */
if(lpResults->lpOutString)
/* copy will do if the GCP_REORDER flag is not set */
if (lpResults->lpOutString)
lstrcpynW( lpResults->lpOutString, lpString, nSet );
if(lpResults->lpOrder)
if (lpResults->lpOrder)
{
for(i = 0; i < nSet; i++)
for (i = 0; i < nSet; i++)
lpResults->lpOrder[i] = i;
}
/*} else
{
BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
nSet, lpResults->lpOrder );
}*/
/* FIXME: Will use the placement chars */
if (lpResults->lpDx)

View file

@ -500,6 +500,12 @@ ExtTextOutW(
cwc,
lpDx);
if (!(fuOptions & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)))
{
if (LoadLPK(LPK_ETO))
return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0);
}
return NtGdiExtTextOutW(hdc,
x,
y,

View file

@ -1,5 +1,10 @@
#include <precomp.h>
/* LoadLPK global variables */
HINSTANCE hLpk = NULL;
LPKETO LpkExtTextOut = NULL;
LPKGCP LpkGetCharacterPlacement = NULL;
/**
* @name CalculateColorTableSize
*
@ -408,3 +413,51 @@ EnumLogFontExW2A( LPENUMLOGFONTEXA fontA, CONST ENUMLOGFONTEXW *fontW )
fontA->elfScript[LF_FACESIZE-1] = '\0';
}
/*
* LPK.DLL loader function
*
* Returns TRUE if a valid parameter was passed and loading was successful,
* retruns FALSE otherwise.
*/
BOOL WINAPI LoadLPK(INT LpkFunctionID)
{
if(!hLpk) // Check if the DLL is already loaded
hLpk = LoadLibraryW(L"lpk.dll");
if (hLpk)
{
switch (LpkFunctionID)
{
case LPK_ETO:
if (!LpkExtTextOut) // Check if the function is already loaded
LpkExtTextOut = (LPKETO) GetProcAddress(hLpk, "LpkExtTextOut");
if (!LpkExtTextOut)
{
FreeLibrary(hLpk);
return FALSE;
}
return TRUE;
case LPK_GCP:
if (!LpkGetCharacterPlacement) // Check if the function is already loaded
LpkGetCharacterPlacement = (LPKGCP) GetProcAddress(hLpk, "LpkGetCharacterPlacement");
if (!LpkGetCharacterPlacement)
{
FreeLibrary(hLpk);
return FALSE;
}
return TRUE;
default:
FreeLibrary(hLpk);
return FALSE;
}
}
else
return FALSE;
}