diff --git a/dll/win32/lpk/CMakeLists.txt b/dll/win32/lpk/CMakeLists.txt index 4bd68b34863..858e468bc48 100644 --- a/dll/win32/lpk/CMakeLists.txt +++ b/dll/win32/lpk/CMakeLists.txt @@ -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) diff --git a/dll/win32/lpk/bidi.c b/dll/win32/lpk/bidi.c new file mode 100644 index 00000000000..a380e1f2ed6 --- /dev/null +++ b/dll/win32/lpk/bidi.c @@ -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; +} diff --git a/dll/win32/lpk/dllmain.c b/dll/win32/lpk/dllmain.c deleted file mode 100644 index f54beb950bf..00000000000 --- a/dll/win32/lpk/dllmain.c +++ /dev/null @@ -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; -} diff --git a/dll/win32/lpk/lpk.c b/dll/win32/lpk/lpk.c new file mode 100644 index 00000000000..fde181cc521 --- /dev/null +++ b/dll/win32/lpk/lpk.c @@ -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; +} diff --git a/dll/win32/lpk/lpk.spec b/dll/win32/lpk/lpk.spec index 01ed057bf63..910d3dc65db 100644 --- a/dll/win32/lpk/lpk.spec +++ b/dll/win32/lpk/lpk.spec @@ -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) diff --git a/dll/win32/lpk/ros_lpk.h b/dll/win32/lpk/ros_lpk.h index 5c5a4c88a34..d82a4498bcd 100644 --- a/dll/win32/lpk/ros_lpk.h +++ b/dll/win32/lpk/ros_lpk.h @@ -14,6 +14,9 @@ #define WIN32_NO_STATUS #include #include +#include +#include +#include /* 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 */ diff --git a/dll/win32/lpk/stub.c b/dll/win32/lpk/stub.c index 37072f05b78..51d8eda0e44 100644 --- a/dll/win32/lpk/stub.c +++ b/dll/win32/lpk/stub.c @@ -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 */ diff --git a/media/doc/README.WINE b/media/doc/README.WINE index 632e0ed0691..b75500483f3 100644 --- a/media/doc/README.WINE +++ b/media/doc/README.WINE @@ -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 diff --git a/modules/rostests/win32/user32/CMakeLists.txt b/modules/rostests/win32/user32/CMakeLists.txt index b61af83eceb..8298a919d37 100644 --- a/modules/rostests/win32/user32/CMakeLists.txt +++ b/modules/rostests/win32/user32/CMakeLists.txt @@ -1,2 +1,3 @@ +add_subdirectory(biditext) add_subdirectory(paintdesktop) add_subdirectory(sysicon) diff --git a/modules/rostests/win32/user32/biditext/Application.ico b/modules/rostests/win32/user32/biditext/Application.ico new file mode 100644 index 00000000000..1073447c20c Binary files /dev/null and b/modules/rostests/win32/user32/biditext/Application.ico differ diff --git a/modules/rostests/win32/user32/biditext/Application.manifest b/modules/rostests/win32/user32/biditext/Application.manifest new file mode 100644 index 00000000000..76090d41338 --- /dev/null +++ b/modules/rostests/win32/user32/biditext/Application.manifest @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/rostests/win32/user32/biditext/CMakeLists.txt b/modules/rostests/win32/user32/biditext/CMakeLists.txt new file mode 100644 index 00000000000..042ab63b430 --- /dev/null +++ b/modules/rostests/win32/user32/biditext/CMakeLists.txt @@ -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) diff --git a/modules/rostests/win32/user32/biditext/biditext.c b/modules/rostests/win32/user32/biditext/biditext.c new file mode 100644 index 00000000000..cc714c40f7f --- /dev/null +++ b/modules/rostests/win32/user32/biditext/biditext.c @@ -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; +} diff --git a/modules/rostests/win32/user32/biditext/biditext.h b/modules/rostests/win32/user32/biditext/biditext.h new file mode 100644 index 00000000000..433223776de --- /dev/null +++ b/modules/rostests/win32/user32/biditext/biditext.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +/* 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 diff --git a/modules/rostests/win32/user32/biditext/biditext.rc b/modules/rostests/win32/user32/biditext/biditext.rc new file mode 100644 index 00000000000..cc2a2632f83 --- /dev/null +++ b/modules/rostests/win32/user32/biditext/biditext.rc @@ -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 diff --git a/win32ss/gdi/gdi32/include/gdi32p.h b/win32ss/gdi/gdi32/include/gdi32p.h index dddbfd74b3f..1b7c51856d5 100644 --- a/win32ss/gdi/gdi32/include/gdi32p.h +++ b/win32ss/gdi/gdi32/include/gdi32p.h @@ -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, diff --git a/win32ss/gdi/gdi32/objects/font.c b/win32ss/gdi/gdi32/objects/font.c index 56998ab84bc..0763ff7df23 100644 --- a/win32ss/gdi/gdi32/objects/font.c +++ b/win32ss/gdi/gdi32/objects/font.c @@ -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) diff --git a/win32ss/gdi/gdi32/objects/text.c b/win32ss/gdi/gdi32/objects/text.c index 31ee3ca2ff4..1242020639e 100644 --- a/win32ss/gdi/gdi32/objects/text.c +++ b/win32ss/gdi/gdi32/objects/text.c @@ -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, diff --git a/win32ss/gdi/gdi32/objects/utils.c b/win32ss/gdi/gdi32/objects/utils.c index 5a0bca1e93b..432c6e1482a 100644 --- a/win32ss/gdi/gdi32/objects/utils.c +++ b/win32ss/gdi/gdi32/objects/utils.c @@ -1,5 +1,10 @@ #include +/* 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; +}