Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3259 lines
94 KiB

/*++
Copyright (c) 2001, Microsoft Corporation
Module Name:
uicomp.cpp
Abstract:
This file implements the UIComposition Class.
Author:
Revision History:
Notes:
--*/
#include "private.h"
#include "resource.h"
#include "cicspres.h"
#include "uicomp.h"
#include "globals.h"
#include "ctxtcomp.h"
#include "cic.h"
#include "profile.h"
#include "cregkey.h"
#include "cresstr.h"
#include "delay.h"
#include "fontlink.h"
const TCHAR c_szCUASDefCompKey[] = TEXT("SOFTWARE\\Microsoft\\CTF\\CUAS\\DefaultCompositionWindow");
const TCHAR c_szLeft[] = TEXT("Left");
const TCHAR c_szTop[] = TEXT("Top");
//+---------------------------------------------------------------------------
//
// IsEALang
//
//+---------------------------------------------------------------------------
BOOL IsEALang()
{
TLS* ptls = TLS::GetTLS();
if (ptls)
{
CicProfile* pProfile;
if (pProfile = ptls->GetCicProfile())
{
LANGID langid;
pProfile->GetLangId(&langid);
switch(PRIMARYLANGID(langid))
{
case LANG_JAPANESE:
case LANG_KOREAN:
case LANG_CHINESE:
return TRUE;
}
}
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Internal_PolyTextOutW
//
//+---------------------------------------------------------------------------
BOOL
Internal_PolyTextOutW(
HDC hDC,
CONST POLYTEXTW* pptxt,
int cStrings)
{
for (int i=0; i < cStrings; i++)
{
if (! FLExtTextOutW(hDC,
pptxt[i].x, pptxt[i].y,
pptxt[i].uiFlags,
&pptxt[i].rcl,
pptxt[i].lpstr, pptxt[i].n, pptxt[i].pdx))
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
// CDefCompFrameGripper
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// CDefCompFrameGripper::ctor
//
//+---------------------------------------------------------------------------
CDefCompFrameGripper::CDefCompFrameGripper(CDefCompFrameWindow *pDefCompFrameWindow, RECT *prc, DWORD dwStyle) : CUIFGripper( pDefCompFrameWindow, prc, dwStyle)
{
m_pDefCompFrameWnd = pDefCompFrameWindow;
}
//////////////////////////////////////////////////////////////////////////////
//
// CCompFinalizeButton
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// CCompFinalizeButton::ctor
//
//+---------------------------------------------------------------------------
CCompFinalizeButton::CCompFinalizeButton(CCompFrameWindow *pCompFrameWindow, DWORD dwID, RECT *prc, DWORD dwStyle, DWORD dwSBtnStyle, DWORD dwSBtnShowType) : CUIFToolbarButton(pCompFrameWindow, dwID, prc, dwStyle, dwSBtnStyle, dwSBtnShowType)
{
m_pCompFrameWnd = pCompFrameWindow;
}
//+---------------------------------------------------------------------------
//
// CCompFinalizeButton::dtor
//
//+---------------------------------------------------------------------------
CCompFinalizeButton::~CCompFinalizeButton()
{
HICON hIcon = GetIcon();
if (hIcon)
{
DestroyIcon(hIcon);
SetIcon(NULL);
}
}
//+---------------------------------------------------------------------------
//
// CCompFinalizeButton::OnLeftClick
//
//+---------------------------------------------------------------------------
void CCompFinalizeButton::OnLeftClick()
{
Assert(m_pCompFrameWnd);
//
// complete string at lbutton click.
//
if (m_pCompFrameWnd->GetIMC())
ImmNotifyIME(m_pCompFrameWnd->GetIMC(),
NI_COMPOSITIONSTR,
CPS_COMPLETE,
0);
}
//////////////////////////////////////////////////////////////////////////////
//
// CDefCompFrameWindow
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// CDefCompFrameWindow::CDefCompFrameWindow
//
//+---------------------------------------------------------------------------
CDefCompFrameWindow::CDefCompFrameWindow(HIMC hIMC, DWORD dwStyle) : CCompFrameWindow(hIMC, dwStyle)
{
//
// get the current position from registry
//
LoadPosition();
//
// Set theme
//
SetActiveTheme(L"TASKBAR", TBP_BACKGROUNDBOTTOM, TS_NORMAL );
}
//+---------------------------------------------------------------------------
//
// CDefCompFrameWindow::~CDefCompFrameWindow
//
//+---------------------------------------------------------------------------
CDefCompFrameWindow::~CDefCompFrameWindow()
{
//
// save the current position to registry
//
SavePosition();
}
//+---------------------------------------------------------------------------
//
// CDefCompFrameWindow::OnSetCursor
//
//+---------------------------------------------------------------------------
BOOL CDefCompFrameWindow::OnSetCursor( UINT uMsg, POINT pt )
{
//
// SendMessage(WM_UICOMP_SETCURSOR) will set the cursor if pt is in
// the comp str window.
//
if (IsWindow(m_hwndCompStr))
{
RECT rc;
GetWindowRect(m_hwndCompStr, &rc);
MyScreenToClient(NULL, &rc);
if (PtInRect(&rc, pt))
return TRUE;
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// CDefCompFrameWindow::HandleMouseMsg
//
//+---------------------------------------------------------------------------
void CDefCompFrameWindow::HandleMouseMsg( UINT uMsg, POINT pt )
{
if (IsWindow(m_hwndCompStr))
{
RECT rc;
GetWindowRect(m_hwndCompStr, &rc);
MyScreenToClient(NULL, &rc);
if (PtInRect(&rc, pt))
SendMessage(m_hwndCompStr, WM_UICOMP_SETCURSOR, 0, 0);
}
CUIFWindow::HandleMouseMsg(uMsg, pt );
}
//+---------------------------------------------------------------------------
//
// CDefCompFrameWindow::Init
//
//+---------------------------------------------------------------------------
void CDefCompFrameWindow::Init()
{
if (!m_pGripper)
{
RECT rc;
::SetRect(&rc, 0, 0, 0, 0);
m_pGripper = new CDefCompFrameGripper(this, &rc, 0);
m_pGripper->Initialize();
AddUIObj(m_pGripper);
}
if (!m_pEnterButton)
{
RECT rc;
::SetRect(&rc, 0, 0, 0, 0);
m_pEnterButton = new CCompFinalizeButton(this,
0,
&rc,
0,
UITBBUTTON_BUTTON,
0);
m_pEnterButton->Initialize();
m_pEnterButton->Init();
m_pEnterButton->SetIcon(LoadSmIcon(::GetInstance(),
MAKEINTRESOURCE(IDIC_ENTER_ICON)));
m_pEnterButton->SetToolTip(CRStr2(IDS_ENTER_BTN_TOOLTIP));
AddUIObj(m_pEnterButton);
}
}
//+---------------------------------------------------------------------------
//
// OnCreate
//
//----------------------------------------------------------------------------
void CDefCompFrameWindow::OnCreate(HWND hWnd)
{
//
// Set Window Theme.
//
SetWindowTheme(hWnd, L"TASKBAR", NULL);
//
// Get margins of button theme.
//
CUIFTheme themeBtn;
memset(&_marginsButton, 0, sizeof(_marginsButton));
themeBtn.SetActiveTheme(L"TOOLBAR", TP_BUTTON, 0);
if (SUCCEEDED(themeBtn.OpenThemeData(hWnd)))
{
themeBtn.GetThemeMargins(NULL, TS_NORMAL,
TMT_CONTENTMARGINS,
NULL, &_marginsButton);
}
}
//+---------------------------------------------------------------------------
//
// OnWindowPosChanged
//
//----------------------------------------------------------------------------
LRESULT CDefCompFrameWindow::OnWindowPosChanged(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
IMCLock imc(GetIMC());
if (SUCCEEDED(imc.GetResult()))
{
SendMessage(imc->hWnd,
WM_IME_NOTIFY,
IMN_PRIVATE_ONLAYOUTCHANGE,
(LPARAM)GetIMC());
}
return CUIFWindow::OnWindowPosChanged(hWnd, uMsg, wParam, lParam);
}
//+---------------------------------------------------------------------------
//
// CDefCompFrameWindow::SetCompStrRect
//
//+---------------------------------------------------------------------------
void CDefCompFrameWindow::SetCompStrRect(int dx, int dy, BOOL fShow)
{
int x, y;
int nGripperWidth = GetGripperWidth();
RECT rcWnd;
GetWindowRect(GetWnd(), &rcWnd);
Move(rcWnd.left, rcWnd.top, dx + (DEFFRAME_LEFT_MARGIN * 3) + nGripperWidth + DEFFRAME_ENTER_BTN_CX, dy + DEFFRAME_TOP_MARGIN + DEFFRAME_BOTTOM_MARGIN);
if (m_pGripper)
{
RECT rc;
x = DEFFRAME_LEFT_MARGIN;
y = DEFFRAME_TOP_MARGIN;
::SetRect(&rc,
x,
y,
x + nGripperWidth,
DEFFRAME_TOP_STR_MARGIN + dy);
m_pGripper->SetRect(&rc);
}
if (m_pEnterButton)
{
RECT rc;
x = DEFFRAME_LEFT_MARGIN + nGripperWidth + dx + DEFFRAME_LEFT_MARGIN;
y = DEFFRAME_TOP_MARGIN;
::SetRect(&rc,
x,
y,
x + DEFFRAME_ENTER_BTN_CX + _marginsButton.cxLeftWidth + _marginsButton.cxRightWidth,
y + DEFFRAME_ENTER_BTN_CY + _marginsButton.cyTopHeight + _marginsButton.cyBottomHeight);
m_pEnterButton->SetRect(&rc);
}
Show(fShow);
x = DEFFRAME_LEFT_MARGIN + nGripperWidth;
y = DEFFRAME_TOP_STR_MARGIN;
::MoveWindow(m_hwndCompStr, x, y, dx, dy, TRUE);
::ShowWindow(m_hwndCompStr, fShow ? SW_SHOWNOACTIVATE : SW_HIDE);
}
//+---------------------------------------------------------------------------
//
// GetGripperWidth
//
//----------------------------------------------------------------------------
int CDefCompFrameWindow::GetGripperWidth()
{
if (m_pGripper)
{
if (SUCCEEDED(m_pGripper->EnsureThemeData(GetWnd())))
{
int nRet = -1;
SIZE size;
HDC hdc = GetDC(GetWnd());
if (SUCCEEDED(m_pGripper->GetThemePartSize(hdc,
TS_NORMAL,
NULL,
TS_TRUE,
&size)))
{
nRet = size.cx + CUI_GRIPPER_THEME_MARGIN * 2;
}
ReleaseDC(GetWnd(), hdc);
if (nRet >= 0)
return nRet;
}
}
return 5;
}
//+---------------------------------------------------------------------------
//
// SavePosition
//
//----------------------------------------------------------------------------
void CDefCompFrameWindow::SavePosition()
{
CMyRegKey key;
if (key.Create(HKEY_CURRENT_USER, c_szCUASDefCompKey) == S_OK)
{
key.SetValue((DWORD)_xWnd, c_szLeft);
key.SetValue((DWORD)_yWnd, c_szTop);
}
}
//+---------------------------------------------------------------------------
//
// LoadPosition
//
//----------------------------------------------------------------------------
void CDefCompFrameWindow::LoadPosition()
{
CMyRegKey key;
int x, y;
x = 0;
y = 0;
if (key.Open(HKEY_CURRENT_USER, c_szCUASDefCompKey, KEY_READ) == S_OK)
{
DWORD dw;
if (key.QueryValue(dw, c_szLeft) == S_OK)
x = (int)dw;
if (key.QueryValue(dw, c_szTop) == S_OK)
y = (int)dw;
}
Move(x, y, 0, 0);
}
//////////////////////////////////////////////////////////////////////////////
//
// CCompButtonFrameWindow
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// CCompButtonFrameWindow::CCompButtonFrameWindow
//
//+---------------------------------------------------------------------------
CCompButtonFrameWindow::CCompButtonFrameWindow(HIMC hIMC, DWORD dwStyle) : CCompFrameWindow(hIMC, dwStyle)
{
#ifdef COMPBUTTON_TOOLBARTHEME
//
// Set theme
//
SetActiveTheme(L"TOOLBAR", TBP_BACKGROUNDBOTTOM, TS_NORMAL );
#endif
}
//+---------------------------------------------------------------------------
//
// CCompButtonFrameWindow::~CCompButtonFrameWindow
//
//+---------------------------------------------------------------------------
CCompButtonFrameWindow::~CCompButtonFrameWindow()
{
}
//+---------------------------------------------------------------------------
//
// OnCreate
//
//----------------------------------------------------------------------------
void CCompButtonFrameWindow::OnCreate(HWND hWnd)
{
//
// Set Window Theme.
//
#ifdef COMPBUTTON_TOOLBARTHEME
SetWindowTheme(hWnd, L"TASKBAR", NULL);
#else
SetWindowTheme(hWnd, L"TOOLBAR", NULL);
#endif
//
// Get margins of button theme.
//
CUIFTheme themeBtn;
memset(&_marginsButton, 0, sizeof(_marginsButton));
themeBtn.SetActiveTheme(L"TOOLBAR", TP_BUTTON, 0);
if (SUCCEEDED(themeBtn.OpenThemeData(hWnd)))
{
themeBtn.GetThemeMargins(NULL, TS_NORMAL,
TMT_CONTENTMARGINS,
NULL, &_marginsButton);
}
}
//+---------------------------------------------------------------------------
//
// CCompButtonFrameWindow::Init
//
//+---------------------------------------------------------------------------
void CCompButtonFrameWindow::Init()
{
if (!m_pEnterButton)
{
RECT rc;
::SetRect(&rc, 0, 0, 0, 0);
m_pEnterButton = new CCompFinalizeButton(this,
0,
&rc,
0,
UITBBUTTON_BUTTON,
0);
m_pEnterButton->Initialize();
m_pEnterButton->Init();
m_pEnterButton->SetIcon(LoadSmIcon(::GetInstance(),
MAKEINTRESOURCE(IDIC_ENTER_ICON)));
m_pEnterButton->SetToolTip(CRStr2(IDS_ENTER_BTN_TOOLTIP));
AddUIObj(m_pEnterButton);
}
}
//+---------------------------------------------------------------------------
//
// CCompButtonFrameWindow::MoveShow
//
//+---------------------------------------------------------------------------
void CCompButtonFrameWindow::MoveShow(int x, int y, BOOL fShow)
{
RECT rcWnd;
int cx = DEFFRAME_ENTER_BTN_CX + _marginsButton.cxLeftWidth + _marginsButton.cxRightWidth;
int cy = DEFFRAME_ENTER_BTN_CY + _marginsButton.cyTopHeight + _marginsButton.cyBottomHeight;
GetWindowRect(GetWnd(), &rcWnd);
Move(x, y,
((COMPBTN_LEFT_MARGIN + 1) * 2) + cx,
((COMPBTN_TOP_MARGIN + 1) * 2) + cy);
if (m_pEnterButton)
{
RECT rc;
x = COMPBTN_LEFT_MARGIN;
y = COMPBTN_TOP_MARGIN;
::SetRect(&rc, x, y, x + cx, x + cy);
m_pEnterButton->SetRect(&rc);
}
Show(fShow);
}
//////////////////////////////////////////////////////////////////////////////
//
// UIComposition
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// UIComposition::CompWndProc
//
//+---------------------------------------------------------------------------
/* static */
LRESULT
UIComposition::CompWndProc(
HWND hCompWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_SETCURSOR:
case WM_UICOMP_SETCURSOR:
{
UIComposition* pv = (UIComposition*)GetWindowLongPtr(hCompWnd, GWLP_USERDATA);
HRESULT hr = E_FAIL;
if (pv)
{
HWND hUIWnd = pv->GetUIWnd();
if (IsWindow(hUIWnd))
{
HIMC hImc = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
IMCLock imc(hImc);
if (SUCCEEDED(imc.GetResult()))
{
hr = pv->OnSetCursor(imc, wParam, lParam);
}
}
}
if (hr != S_OK)
return DefWindowProc(hCompWnd, uMsg, wParam, lParam);
break;
}
case WM_PAINT:
case WM_TIMER:
{
TLS* ptls = TLS::GetTLS();
if (ptls == NULL)
return 0;
UIComposition* pv = (UIComposition*)GetWindowLongPtr(hCompWnd, GWLP_USERDATA);
if (pv != NULL)
{
switch (uMsg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hCompWnd, &ps);
HWND hUIWnd = pv->GetUIWnd();
if (IsWindow(hUIWnd))
{
HIMC hImc = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
IMCLock imc(hImc);
if (SUCCEEDED(imc.GetResult()))
{
pv->OnPaint(ptls, hCompWnd, hDC, ps, imc);
}
}
EndPaint(hCompWnd, &ps);
}
break;
case WM_TIMER:
pv->OnTimer(hCompWnd);
break;
}
}
}
break;
default:
return DefWindowProc(hCompWnd, uMsg, wParam, lParam);
}
return 0;
}
//+---------------------------------------------------------------------------
//
// UIComposition::ctor
// UIComposition::dtor
//
//+---------------------------------------------------------------------------
UIComposition::UIComposition(HWND hUIWnd)
{
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
m_CompWnd[i].hCompWnd = NULL;
m_CompWnd[i].fDefaultCompWnd = FALSE;
}
m_DefCompWnd.hCompWnd = NULL;
m_DefCompWnd.fDefaultCompWnd = TRUE;
m_hFontLevel1 = NULL;
m_hFontLevel2 = NULL;
m_isc = 0;
m_hUIWnd = hUIWnd;
m_lpszCompStr = NULL;
m_nCompStr = 0;
m_bTimerCOMPOSITION = FALSE;
}
UIComposition::~UIComposition()
{
DestroyCompositionWindow();
if (m_hFontLevel1)
DeleteObject(m_hFontLevel1);
if (m_hFontLevel2)
DeleteObject(m_hFontLevel2);
m_hFontLevel1 = NULL;
m_hFontLevel2 = NULL;
if (m_lpszCompStr)
{
cicMemFree(m_lpszCompStr);
m_lpszCompStr = NULL;
}
m_nCompStr = 0;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnCreate
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnCreate()
{
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnDestroy
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnDestroy()
{
return DestroyCompositionWindow();
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeSetContext
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeSetContext(
IMCLock& imc,
HWND hUIWnd,
BOOL fActivate,
DWORD isc)
{
HRESULT hr = S_OK;
if (fActivate)
{
if (SUCCEEDED(imc.GetResult()))
{
//
// #598648
//
// Powerpnt XP does not clear ISC_SHOWUICOMPOSITIONWINDOW.
// even though it is AIMM filtered window. It must be Level3.
//
BOOL fFilter = MsimtfIsWindowFiltered(imc->hWnd);
if ((isc & ISC_SHOWUICOMPOSITIONWINDOW) && fFilter)
{
isc &= ~ISC_SHOWUICOMPOSITIONWINDOW;
//
// 616323
//
// Trident can not handle the existing composition string.
//
// if hIMC already has a composition string before the focus
// goes to the trident. We need to clear the comp string.
// Trident can not start the composition string in the middle
// of composing.
//
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
if (FAILED(hr=comp.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnImeSetContext. comp==NULL"));
return hr;
}
if (comp->dwCompStrLen)
{
DWORD dwImeCompatFlags = ImmGetAppCompatFlags(NULL);
if (dwImeCompatFlags & IMECOMPAT_AIMM12_TRIDENT)
{
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(imc_ctfime.GetResult()))
{
return E_FAIL;
}
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnImeSetContext. _pCicContext==NULL"));
return E_FAIL;
}
_pCicContext->EscbCompComplete(imc);
}
}
}
}
m_isc = isc;
UpdateShowCompWndFlag(imc, NULL);
}
m_fActive = fActivate;
return hr;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeSetContextAfter
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeSetContextAfter(
IMCLock& imc)
{
if ((m_pDefCompFrameWnd && IsWindow(m_pDefCompFrameWnd->GetWnd())) ||
IsWindow(m_CompWnd[FIRST_WINDOW].hCompWnd)
)
{
HRESULT hr;
//
// Validation check of imc.
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
//
hr = imc.GetResult();
//
// we show the def / level2 comp window,
//
// - if imc is valid.
// - if composition window is on Level1 or 2.
// - if it is not level 3,
// (m_isc does not have ISC_SHOWUICOMPOSITIONWINDOW)
// - if it is active.
// - if there is a composition string.
//
IME_UIWND_STATE uiwndState;
if (SUCCEEDED(hr) &&
((uiwndState = GetLevelFromIMC(imc)) == IME_UIWND_LEVEL1 || uiwndState == IME_UIWND_LEVEL2) &&
(m_isc & ISC_SHOWUICOMPOSITIONWINDOW) &&
m_fActive)
{
DWORD dwCompLen = 0;
UpdateShowCompWndFlag(imc, &dwCompLen);
if (uiwndState == IME_UIWND_LEVEL1)
{
ShowWindow(m_pDefCompFrameWnd->GetWnd(),
m_fShowCompWnd.IsSetFlag() ? SW_SHOWNOACTIVATE : SW_HIDE);
}
else if ((uiwndState == IME_UIWND_LEVEL2) && (m_fShowCompWnd.IsResetFlag()))
{
for (int i = 0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && dwCompLen > 0; i++)
{
m_CompWnd[i].caret.HideCaret();
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
}
}
}
else
{
//
// Both Level 1 / Level 2 window hide.
//
ShowWindow(m_pDefCompFrameWnd->GetWnd(), SW_HIDE);
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
m_CompWnd[i].caret.HideCaret();
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
}
}
}
else
{
m_isc &= ~ISC_SHOWUICOMPOSITIONWINDOW;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeSelect
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeSelect(
BOOL fSelect)
{
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeStartComposition
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeStartComposition(
IMCLock& imc,
HWND hUIWnd)
{
HRESULT hr;
if (SUCCEEDED(hr = UpdateFont(imc)))
{
TEXTMETRIC tm;
HDC hDC;
HFONT hFontOrg;
hDC = GetDC(m_DefCompWnd.hCompWnd);
// get FontHeight for level1.
hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
GetTextMetrics(hDC, &tm);
m_tmFontHeightLevel1 = tm.tmHeight;
// get FontHeight for level2.
SelectObject(hDC, m_hFontLevel2);
GetTextMetrics(hDC, &tm);
m_tmFontHeightLevel2 = tm.tmHeight;
SelectObject(hDC, hFontOrg);
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
if (!imc.UseVerticalCompWindow())
{
m_caret_size.cx = CARET_WIDTH;
m_caret_size.cy = tm.tmHeight + LINE_BOLD_WIDTH;
}
else
{
m_caret_size.cx = tm.tmHeight + LINE_BOLD_WIDTH;
m_caret_size.cy = CARET_WIDTH;
}
if (SUCCEEDED(hr = CreateCompositionWindow(imc, hUIWnd)))
{
UpdateCompositionRect(imc);
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeCompositionUpdate
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeCompositionUpdate(IMCLock& imc)
{
m_isc |= ISC_SHOWUICOMPOSITIONWINDOW; // arrive WM_IME_COMPOSITION in IME UI window,
// IME should draw comp wnd.
return UpdateShowCompWndFlag(imc, NULL);
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeCompositionUpdateByTimer
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeCompositionUpdateByTimer(IMCLock& imc)
{
return UpdateCompositionRect(imc);
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeEndComposition
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeEndComposition()
{
m_isc = 0;
return DestroyCompositionWindow();
}
//+---------------------------------------------------------------------------
//
// UIComposition::CreateCompositionWindow
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::CreateCompositionWindow(
IMCLock& imc,
HWND hUIWnd)
{
HRESULT hr;
if (SUCCEEDED(hr=imc.GetResult()) &&
IsWindow(hUIWnd) &&
m_fInitUIComp.IsResetFlag())
{
//
// Create three composition windows
//
// m_CompWnd[0].hCompWnd is first composition window rectangle.
// m_CompWnd[1].hCompWnd is middle composition window rectangle.
// m_CompWnd[2].hCompWnd is last composition window rectangle.
//
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
Assert(!m_CompWnd[i].hCompWnd);
m_CompWnd[i].hCompWnd = CreateWindowExW(0,
s_szCompClassName,
NULL,
WS_POPUP | WS_DISABLED,
0, 0, 0, 0,
hUIWnd, // Parent Window Handle.
NULL,
GetInstance(),
NULL);
if (m_CompWnd[i].hCompWnd == NULL)
{
DestroyCompositionWindow();
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_CompWnd[].hCompWnd==NULL"));
return E_OUTOFMEMORY;
}
SetWindowLongPtr(m_CompWnd[i].hCompWnd, GWLP_USERDATA, (LONG_PTR)this);
switch (i)
{
case FIRST_WINDOW:
SetWindowLongPtr(m_CompWnd[FIRST_WINDOW].hCompWnd, COMPUI_WINDOW_INDEX, FIRST_WINDOW);
break;
case MIDDLE_WINDOW:
SetWindowLongPtr(m_CompWnd[MIDDLE_WINDOW].hCompWnd, COMPUI_WINDOW_INDEX, MIDDLE_WINDOW);
break;
case LAST_WINDOW:
SetWindowLongPtr(m_CompWnd[LAST_WINDOW].hCompWnd, COMPUI_WINDOW_INDEX, LAST_WINDOW);
break;
}
m_CompWnd[i].caret.CreateCaret(m_CompWnd[i].hCompWnd, m_caret_size);
}
if (FAILED(CreateCompButtonWnd(hUIWnd, (HIMC)imc)))
{
DestroyCompositionWindow();
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_pCompButtonFrameWindow==NULL"));
return E_OUTOFMEMORY;
}
if (FAILED(CreateDefFrameWnd(hUIWnd, (HIMC)imc)))
{
DestroyCompositionWindow();
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_pDefFrameWindow==NULL"));
return E_OUTOFMEMORY;
}
//
// Create default composition window
//
Assert(!m_DefCompWnd.hCompWnd);
m_DefCompWnd.hCompWnd = CreateWindowExW(WS_EX_CLIENTEDGE,
s_szCompClassName,
NULL,
WS_CHILD | WS_DISABLED,
0, 0, 0, 0,
m_pDefCompFrameWnd->GetWnd(),
NULL,
GetInstance(),
NULL);
if (m_DefCompWnd.hCompWnd == NULL)
{
DestroyCompositionWindow();
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_DefCompWnd.hCompWnd==NULL"));
return E_OUTOFMEMORY;
}
m_pDefCompFrameWnd->SetCompStrWnd(m_DefCompWnd.hCompWnd);
SetWindowLongPtr(m_DefCompWnd.hCompWnd, GWLP_USERDATA, (LONG_PTR)this);
SetWindowLongPtr(m_DefCompWnd.hCompWnd, COMPUI_WINDOW_INDEX, DEFAULT_WINDOW);
m_DefCompWnd.caret.CreateCaret(m_DefCompWnd.hCompWnd, m_caret_size);
//
// Final: set flag
//
m_fInitUIComp.SetFlag();
}
return hr;
}
//+---------------------------------------------------------------------------
//
// UIComposition::DestroyCompositionWindow
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::DestroyCompositionWindow()
{
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
m_CompWnd[i].caret.DestroyCaret();
if (IsWindow(m_CompWnd[i].hCompWnd))
{
DestroyWindow(m_CompWnd[i].hCompWnd);
m_CompWnd[i].poly_text.RemoveAll();
}
m_CompWnd[i].hCompWnd = NULL;
}
if (m_pCompButtonFrameWnd)
{
DestroyWindow(m_pCompButtonFrameWnd->GetWnd());
delete m_pCompButtonFrameWnd;
m_pCompButtonFrameWnd = NULL;
}
m_DefCompWnd.caret.DestroyCaret();
if (IsWindow(m_DefCompWnd.hCompWnd))
{
DestroyWindow(m_DefCompWnd.hCompWnd);
m_DefCompWnd.poly_text.RemoveAll();
}
if (m_pDefCompFrameWnd)
{
DestroyWindow(m_pDefCompFrameWnd->GetWnd());
delete m_pDefCompFrameWnd;
m_pDefCompFrameWnd = NULL;
}
m_DefCompWnd.hCompWnd = NULL;
m_fInitUIComp.ResetFlag();
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::HideCompositionWindow
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::HideCompositionWindow()
{
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
if (IsWindow(m_CompWnd[i].hCompWnd))
{
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
}
}
if (IsWindow(m_DefCompWnd.hCompWnd))
{
ShowWindow(m_DefCompWnd.hCompWnd, SW_HIDE);
}
if (m_pDefCompFrameWnd)
m_pDefCompFrameWnd->Show(FALSE);
if (m_pCompButtonFrameWnd)
m_pCompButtonFrameWnd->Show(FALSE);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::GetSelection
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::GetSelection(
IMCLock& imc,
LONG *pacpSelStart,
LONG *pcchSel)
{
HRESULT hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr=imc_ctfime.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. imc_ctfime==NULL"));
return hr;
}
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. _pCicContext==NULL"));
return hr;
}
*pacpSelStart = 0;
*pcchSel = 0;
Interface<ITfRange> Selection;
Interface<ITfRangeACP> SelectionACP;
hr = _pCicContext->EscbGetSelection(imc, &Selection);
if (hr == S_OK)
{
hr = Selection->QueryInterface(IID_ITfRangeACP, (void **)SelectionACP);
if (hr == S_OK)
{
hr = SelectionACP->GetExtent(pacpSelStart, pcchSel);
}
}
//
// if there is no selection, we don't have to check ReadOnly area.
//
if (*pcchSel == 0)
return hr;
//
// find the first non readonly range in the text store.
//
// pacpSelSrart is the offset of the composition string,
// so we need to subtract the range of the readonly area.
//
LONG cchRO = 0;
hr = _pCicContext->EscbReadOnlyPropMargin(imc, &SelectionACP, &cchRO);
if (hr == S_OK)
{
if (cchRO <= *pacpSelStart)
{
*pacpSelStart -= cchRO;
}
else
{
//
// our selection is overwrapped to Read Only area. Why?
//
Assert(0);
*pacpSelStart = 0;
*pcchSel = 0;
}
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::UpdateShowCompWndFlag
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::UpdateShowCompWndFlag(
IMCLock& imc,
DWORD* pdwCompStrLen)
{
HRESULT hr;
//
// Validation check of imc.
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
//
if (FAILED(hr=imc.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateShowCompWndFlag. imc==NULL"));
return hr;
}
if (! IsWindow(imc->hWnd))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateShowCompWndFlag. imc->hWNd==NULL"));
return E_FAIL;
}
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
if (FAILED(hr=comp.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateShowCompWndFlag. comp==NULL"));
return hr;
}
if ((m_isc & ISC_SHOWUICOMPOSITIONWINDOW) && comp->dwCompStrLen)
{
m_fShowCompWnd.SetFlag();
}
else
{
m_fShowCompWnd.ResetFlag();
}
if (pdwCompStrLen)
*pdwCompStrLen = comp->dwCompStrLen;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::UpdateCompositionRect
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::UpdateCompositionRect(
IMCLock& imc)
{
HRESULT hr;
//
// Validation check of imc.
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
//
if (FAILED(hr=imc.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateCompositionRect. imc==NULL"));
return hr;
}
if (! IsWindow(imc->hWnd))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateCompositionRect. imc->hWNd==NULL"));
return E_FAIL;
}
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
if (FAILED(hr=comp.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateCompositionRect. comp==NULL"));
return hr;
}
//
// Get Selection.
//
LONG acpSelStart = 0;
LONG cchSel = 0;
GetSelection(imc, &acpSelStart, &cchSel);
//
// Update show composition flag
//
DWORD dwCompLen = 0;
UpdateShowCompWndFlag(imc, &dwCompLen);
//
// Allocate temp composition string buffer
//
LPWSTR lpCompStr;
lpCompStr = GetCompStrBuffer(comp->dwCompStrLen);
if (!lpCompStr)
return E_OUTOFMEMORY;
//
// Store composition string in local buffer
//
memcpy(lpCompStr,
comp.GetOffsetPointer(comp->dwCompStrOffset),
dwCompLen * sizeof(WCHAR));
UINT fSwpShow = m_fShowCompWnd.IsSetFlag() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
if (uiwndState == IME_UIWND_LEVEL1)
{
//
// When the style is DEFAULT, show the default composition window.
//
if (IsWindow(m_DefCompWnd.hCompWnd))
{
POLYTEXTW poly;
memset(&poly, 0, sizeof(poly));
poly.n = dwCompLen;
poly.lpstr = (LPCWSTR)lpCompStr;
poly.uiFlags = ETO_OPAQUE;
SIZE size;
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
FLGetTextExtentPoint32(hDC, poly.lpstr, poly.n, &size);
poly.rcl.right = size.cx + 2 * GetSystemMetrics(SM_CXEDGE);
poly.rcl.bottom = size.cy + 2 * GetSystemMetrics(SM_CYEDGE);
BOOL fShowCaret = (comp->dwCursorPos <= poly.n ? TRUE : FALSE);
BOOL fEndCaret = (comp->dwCursorPos == poly.n ? TRUE : FALSE);
if (m_pDefCompFrameWnd)
{
m_pDefCompFrameWnd->SetCompStrRect(poly.rcl.right - poly.rcl.left + (fEndCaret ? m_caret_size.cx * 2: 0),
poly.rcl.bottom - poly.rcl.top + LINE_BOLD_WIDTH,
m_fShowCompWnd.IsSetFlag());
}
GuidMapAttribute guid_map(GuidMapAttribute::GetData(comp));
if (guid_map.Valid())
{
Assert(poly.n == guid_map->dwGuidMapAttrLen);
m_DefCompWnd.poly_text.RemoveAll();
PBYTE lpCompAttr = (PBYTE)guid_map.GetOffsetPointer(guid_map->dwGuidMapAttrOffset);
CCompClauseStore compclause;
compclause.Set(comp);
m_DefCompWnd.poly_text.SplitPolyStringAndAttr(imc, hDC, poly, lpCompAttr, &compclause);
}
else
{
m_DefCompWnd.poly_text.RemoveAll();
m_DefCompWnd.poly_text.SplitPolyStringAndAttr(imc, hDC, poly);
}
if (fShowCaret)
{
SetCaretPos(hDC, m_DefCompWnd.caret,
0, 0,
poly.lpstr, poly.n, comp->dwCursorPos,
FALSE, fEndCaret);
}
//
// Save Selection acp and cch
//
m_DefCompWnd.sel.acpStart = acpSelStart;
m_DefCompWnd.sel.cch = cchSel;
SelectObject(hDC, hFontOrg);
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
InvalidateRect(m_DefCompWnd.hCompWnd, NULL, FALSE);
}
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
if (IsWindow(m_CompWnd[i].hCompWnd))
{
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
}
}
if (m_pCompButtonFrameWnd)
{
m_pCompButtonFrameWnd->MoveShow(0, 0, FALSE);
}
}
else if (uiwndState == IME_UIWND_LEVEL2)
{
//
// When the style is not DEFAULT, show the composition window.
//
POINT pt = imc->cfCompForm.ptCurrentPos;
//
// Set the rectangle for the composition string.
//
RECT rect;
if (imc->cfCompForm.dwStyle & CFS_RECT)
rect = imc->cfCompForm.rcArea;
else
GetClientRect(imc->hWnd, &rect);
ClientToScreen(imc->hWnd, &pt);
MapWindowPoints(imc->hWnd, NULL, (LPPOINT)&rect, 2);
//
// Check the start position.
//
if (! PtInRect(&rect, pt))
return E_FAIL;
DWORD dwCursorPos = comp->dwCursorPos;
CCompClauseStore compclause;
compclause.Set(comp);
GuidMapAttribute guid_map(GuidMapAttribute::GetData(comp));
PBYTE lpCompAttr;
BOOL fCompAttr = TRUE;
if (guid_map.Valid())
{
lpCompAttr = (PBYTE)guid_map.GetOffsetPointer(guid_map->dwGuidMapAttrOffset);
Assert(dwCompLen == guid_map->dwGuidMapAttrLen);
}
else
{
TLS* ptls = TLS::GetTLS();
if (ptls)
{
CicProfile* pProfile;
if (pProfile = ptls->GetCicProfile())
{
LANGID langid;
pProfile->GetLangId(&langid);
if (PRIMARYLANGID(langid) == LANG_KOREAN)
{
fCompAttr = FALSE;
}
}
}
if (fCompAttr)
return E_FAIL;
}
{
//
// composition window
//
POINT compbtn_pos = {0,0};
BOOL fInitcompbtn_pos = FALSE;
POINT window_pos;
window_pos = pt;
int window_width;
if (!imc.UseVerticalCompWindow())
{
window_width = rect.right - pt.x;
}
else
{
window_width = rect.bottom - pt.y;
}
UINT string_length;
int i;
for (i = 0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && dwCompLen > 0; i++)
{
m_CompWnd[i].caret.HideCaret();
m_CompWnd[i].poly_text.RemoveAll();
//
// Init Selection acp and cch
//
m_CompWnd[i].sel.acpStart = 0;
m_CompWnd[i].sel.cch = 0;
SIZE size;
size.cy = 0;
if (IsWindow(m_CompWnd[i].hCompWnd))
{
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
if (i != MIDDLE_WINDOW)
{
string_length = CalcSingleTextExtentPoint(imc, hDC, lpCompStr, dwCompLen,
lpCompAttr,
fCompAttr,
&compclause,
window_width, &size,
m_CompWnd[i].poly_text, 0);
}
else
{
string_length = CalcMultiTextExtentPoint(imc, hDC, lpCompStr, dwCompLen,
lpCompAttr,
fCompAttr,
&compclause,
window_width, &size,
m_CompWnd[i].poly_text);
}
if (string_length)
{
BOOL fShowCaret = (dwCursorPos <= string_length ? TRUE : FALSE);
BOOL fEndCaret = (dwCursorPos == string_length ? TRUE : FALSE);
int pos_x = window_pos.x;
int pos_y = window_pos.y;
int cx;
int cy;
if (!imc.UseVerticalCompWindow())
{
cx = size.cx + (fEndCaret ? m_caret_size.cx: 0);
cy = size.cy;
}
else
{
pos_x -= size.cx;
cx = size.cx;
cy = size.cy + (fEndCaret ? m_caret_size.cy: 0);
}
SetWindowPos(m_CompWnd[i].hCompWnd, HWND_TOP,
pos_x, pos_y, cx, cy,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE |
fSwpShow);
if (fShowCaret)
{
UpdateCaretRect(hDC, i, dwCursorPos, imc.UseVerticalCompWindow(), fEndCaret);
dwCursorPos = ULONG_MAX;
}
else
{
dwCursorPos -= string_length;
}
//
// Save Selection acp and cch for this COMPWND
//
if (cchSel && (acpSelStart < (LONG)string_length))
{
m_CompWnd[i].sel.acpStart = acpSelStart;
LONG cchSelTemp = cchSel;
if (acpSelStart + cchSel > (LONG)string_length)
cchSelTemp = string_length - acpSelStart;
m_CompWnd[i].sel.cch = cchSelTemp;
//
// update cchSel for next COMPWND
//
cchSel -= cchSelTemp;
if (cchSel < 0)
cchSel = 0;
}
//
// set level2 comp finalizing button position.
//
compbtn_pos.x = pos_x + cx;
compbtn_pos.y = pos_y;
fInitcompbtn_pos = TRUE;
//
// update CompStr, CompAttr, CompClause for next COMPWND
//
lpCompStr += string_length;
dwCompLen -= string_length;
if (fCompAttr)
{
lpCompAttr += string_length;
compclause.Shift(string_length);
}
//
// update acpSelStart for next COMPWND
//
acpSelStart -= string_length;
if (acpSelStart < 0)
acpSelStart = 0;
}
else
{
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
m_CompWnd[i].poly_text.RemoveAll();
}
SelectObject(hDC, hFontOrg);
ReleaseDC(m_CompWnd[i].hCompWnd, hDC);
InvalidateRect(m_CompWnd[i].hCompWnd, NULL, FALSE);
}
if (!imc.UseVerticalCompWindow())
{
window_pos.x = rect.left;
window_pos.y += size.cy;
window_width = rect.right - rect.left;
rect.top += size.cy;
}
else
{
window_pos.x -= size.cx;
window_pos.y = rect.top;
window_width = rect.bottom - rect.top;
rect.left -= size.cx;
}
}
//
// hide the remaining window.
//
for (; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
if (IsWindow(m_CompWnd[i].hCompWnd))
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
m_CompWnd[i].poly_text.RemoveAll();
}
if (IsWindow(m_DefCompWnd.hCompWnd))
{
ShowWindow(m_DefCompWnd.hCompWnd, SW_HIDE);
}
if (m_pDefCompFrameWnd)
m_pDefCompFrameWnd->Show(FALSE);
if (m_pCompButtonFrameWnd)
{
m_pCompButtonFrameWnd->MoveShow(compbtn_pos.x,
compbtn_pos.y,
m_fShowCompWnd.IsSetFlag() && fInitcompbtn_pos);
}
}
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::UpdateFont
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::UpdateFont(
IMCLock& imc)
{
HRESULT hr;
//
// Validation check of imc.
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
//
if (FAILED(hr=imc.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateFont. imc==NULL"));
return hr;
}
if (m_hFontLevel1)
DeleteObject(m_hFontLevel1);
if (m_hFontLevel2)
DeleteObject(m_hFontLevel2);
LOGFONTW logfont = imc->lfFont.W;
m_hFontLevel2 = CreateFontIndirectW(&logfont);
logfont.lfEscapement = 0;
logfont.lfOrientation = 0;
if (logfont.lfFaceName[0] == L'@')
{
StringCchCopyW(logfont.lfFaceName, ARRAYSIZE(logfont.lfFaceName), &logfont.lfFaceName[1]);
}
m_hFontLevel1 = CreateFontIndirectW(&logfont);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnPaint
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnPaint(
TLS* ptls,
HWND hCompWnd,
HDC hDC,
PAINTSTRUCT& ps,
IMCLock& imc)
{
HRESULT hr = S_OK;
COMPWNDINDEX index = (COMPWNDINDEX)GetWindowLong(hCompWnd, COMPUI_WINDOW_INDEX);
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
if (FAILED(hr=comp.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPaint. comp==NULL"));
}
else
{
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
if ((uiwndState == IME_UIWND_LEVEL1) &&
(index == DEFAULT_WINDOW))
{
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
PolyTextAndAttrOut(ptls,
hDC,
FALSE,
&m_DefCompWnd);
SelectObject(hDC, hFontOrg);
}
else if ((uiwndState == IME_UIWND_LEVEL2) &&
(index != DEFAULT_WINDOW))
{
if (m_CompWnd[index].poly_text.GetPolySize())
{
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
PolyTextAndAttrOut(ptls,
hDC,
imc.UseVerticalCompWindow(),
&m_CompWnd[index]);
SelectObject(hDC, hFontOrg);
}
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnTimer
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnTimer(
HWND hCompWnd)
{
HRESULT hr = S_OK;
COMPWNDINDEX index = (COMPWNDINDEX)GetWindowLong(hCompWnd, COMPUI_WINDOW_INDEX);
if (index == DEFAULT_WINDOW)
{
return m_DefCompWnd.caret.OnTimer();
}
else
{
return m_CompWnd[index].caret.OnTimer();
}
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeNotifySetCompositionWindow
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeNotifySetCompositionWindow(
IMCLock& imc)
{
return UpdateCompositionRect(imc);
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnImeNotifySetCompositionFont
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnImeNotifySetCompositionFont(
IMCLock& imc)
{
HRESULT hr;
if (FAILED(hr = UpdateFont(imc)))
return hr;
return UpdateCompositionRect(imc);
}
//+---------------------------------------------------------------------------
//
// UIComposition::CalcSingleTextExtentPoint
//
//+---------------------------------------------------------------------------
UINT
UIComposition::CalcSingleTextExtentPoint(
IMCLock& imc,
HDC hDC,
LPCWSTR lpsz,
int string_len,
PBYTE lpAttr,
BOOL fCompAttr,
CCompClauseStore* compclause,
int window_width,
LPSIZE real_size, // OUTPUT: Total window rectangle
CPolyText& poly_text,
int row_index)
{
if (string_len == 0 || lpsz == NULL)
{
return 0;
}
SIZE delta_size;
delta_size.cx = 0;
UINT ret_len = 0;
UINT delta_len = 0;
SIZE size;
while ((delta_size.cx < window_width) && string_len)
{
++delta_len;
--string_len;
FLGetTextExtentPoint32(hDC, lpsz, delta_len, &size);
delta_size = size;
}
if (delta_size.cx < window_width)
{
ret_len = delta_len;
}
else
{
ret_len = (delta_len > 1 ? delta_len - 1 : 0);
}
if (ret_len)
{
FLGetTextExtentPoint32(hDC, lpsz, ret_len, real_size);
}
else
{
//
// if string length is 0, we should return just the height.
//
real_size->cx = 0;
real_size->cy = delta_size.cy;
}
if (!imc.UseVerticalCompWindow())
{
if (ret_len > 0)
{
real_size->cy += LINE_BOLD_WIDTH;
POLYTEXTW poly;
memset(&poly, 0, sizeof(poly));
poly.y = row_index * real_size->cy;
poly.n = ret_len;
poly.lpstr = lpsz;
poly.uiFlags = ETO_OPAQUE;
poly.rcl.top = row_index * real_size->cy;
poly.rcl.right = real_size->cx;
poly.rcl.bottom = poly.rcl.top + real_size->cy;
if (fCompAttr)
poly_text.SplitPolyStringAndAttr(imc, hDC, poly, lpAttr, compclause);
else
poly_text.SplitPolyStringAndAttr(imc, hDC, poly);
}
}
else
{
RotateSize(real_size);
if (ret_len > 0)
{
real_size->cx += LINE_BOLD_WIDTH;
//
// shift prev lines to the right.
//
poly_text.ShiftPolyText(real_size->cx, 0);
POLYTEXTW poly;
memset(&poly, 0, sizeof(poly));
poly.x = real_size->cx;
poly.n = ret_len;
poly.lpstr = lpsz;
poly.uiFlags = ETO_OPAQUE;
poly.rcl.left = 0;
poly.rcl.right = poly.rcl.left + real_size->cx;
poly.rcl.bottom = real_size->cy;
if (fCompAttr)
poly_text.SplitPolyStringAndAttr(imc, hDC, poly, lpAttr, compclause);
else
poly_text.SplitPolyStringAndAttr(imc, hDC, poly);
}
}
//
// #608684
//
// the total size of poly text could be bigger than the result of
// FLGetTextExtentPoint() with whole string. So we need to
// adjust the returning size.
//
if (ret_len)
{
int real_width = 0;
INT_PTR i;
INT_PTR nCnt = poly_text.GetPolySize();
const POLYTEXTW* ppoly = poly_text.GetPolyData();
if (!imc.UseVerticalCompWindow())
{
for (i = 0; i < nCnt; i++)
{
if (ppoly->rcl.top == (row_index * real_size->cy))
real_width += (ppoly->rcl.right - ppoly->rcl.left);
ppoly++;
}
Assert(window_width >= real_width);
real_size->cx = real_width;
}
else
{
for (i = 0; i < nCnt; i++)
{
if (ppoly->rcl.left == 0)
real_width += (ppoly->rcl.bottom - ppoly->rcl.top);
ppoly++;
}
Assert(window_width >= real_width);
real_size->cy = real_width;
}
}
return ret_len;
}
//+---------------------------------------------------------------------------
//
// UIComposition::CalcMultiTextExtentPoint
//
//+---------------------------------------------------------------------------
UINT
UIComposition::CalcMultiTextExtentPoint(
IMCLock& imc,
HDC hDC,
LPCWSTR lpsz,
int string_len,
PBYTE lpAttr,
BOOL fCompAttr,
CCompClauseStore *compclause,
int window_width,
LPSIZE real_size, // OUTPUT: Total window rectangle
CPolyText& poly_text)
{
SIZE single_size; // output single window rectangle from CalcSingleTextExtentPoint
single_size.cy = 0;
single_size.cx = 0;
UINT single_len;
UINT total_string_len = 0;
SIZE prev_size = {0, 0};
UINT prev_string_len = 0;
real_size->cx = 0;
real_size->cy = 0;
int row_index = 0;
CCompClauseStore compclauseTmp;
compclauseTmp.Copy(compclause);
if (!imc.UseVerticalCompWindow())
{
while ((single_len = CalcSingleTextExtentPoint(imc, hDC, lpsz, string_len, lpAttr, fCompAttr, &compclauseTmp, window_width, &single_size, poly_text, row_index)) > 0)
{
string_len -= single_len;
lpsz += single_len;
if (fCompAttr)
{
lpAttr += single_len;
compclauseTmp.Shift(single_len);
}
real_size->cx = max(real_size->cx, single_size.cx);
real_size->cy += single_size.cy;
prev_size = single_size;
prev_string_len = single_len;
total_string_len += single_len;
++row_index;
}
real_size->cy -= prev_size.cy;
total_string_len -= prev_string_len;
poly_text.RemoveLastLine(FALSE);
}
else
{
while ((single_len = CalcSingleTextExtentPoint(imc, hDC, lpsz, string_len, lpAttr, fCompAttr, &compclauseTmp, window_width, &single_size, poly_text, row_index)) > 0)
{
string_len -= single_len;
lpsz += single_len;
if (fCompAttr)
{
lpAttr += single_len;
compclauseTmp.Shift(single_len);
}
real_size->cy = max(real_size->cy, single_size.cy);
real_size->cx += single_size.cx;
prev_size = single_size;
prev_string_len = single_len;
total_string_len += single_len;
++row_index;
}
real_size->cx -= prev_size.cx;
total_string_len -= prev_string_len;
if (poly_text.RemoveLastLine(TRUE) == S_OK)
poly_text.ShiftPolyText(-single_size.cx, 0);
}
return total_string_len;
}
//+---------------------------------------------------------------------------
//
// UIComposition::SetCaretPos
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::SetCaretPos(
HDC hDC,
CCaret& caret,
int x,
int y,
LPCWSTR lpCompStr,
DWORD string_length,
DWORD cursor_pos,
BOOL fVert,
BOOL fEndCaret)
{
if (cursor_pos > string_length)
return S_FALSE;
SIZE size;
FLGetTextExtentPoint32(hDC, lpCompStr, cursor_pos, &size);
POINT pos;
if (!fVert)
{
pos.x = ((x + size.cx > 1) ? (x + size.cx - (fEndCaret ? 0 : 1)) : 0);
pos.y = y;
}
else
{
RotateSize(&size);
pos.x = x - size.cx - LINE_BOLD_WIDTH;
pos.y = ((y + size.cy > 1) ? (y + size.cy - (fEndCaret ? 0 : 1)) : 0);
}
caret.SetCaretPos(pos);
caret.ShowCaret();
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::UpdateCaretRect
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::UpdateCaretRect(
HDC hDC,
int index,
DWORD dwCursorPos, // dwCursorPos:: based on m_CompWnd[index].poly_text.lpstr
BOOL fVert,
BOOL fEndCaret)
{
POLYTEXTW poly;
DWORD dwCur = dwCursorPos;
BOOL fFound = FALSE;
for (int i=0; i < m_CompWnd[index].poly_text.GetPolySize(); i++)
{
poly = m_CompWnd[index].poly_text.GetPolyAt(i);
if (dwCur <= poly.n)
{
fFound = TRUE;
break;
}
dwCur -= poly.n;
}
if (! fFound)
{
return S_FALSE;
}
SetCaretPos(hDC, m_CompWnd[index].caret,
poly.x, poly.y,
poly.lpstr, poly.n,
dwCur, fVert, fEndCaret);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::PolyTextAndAttrOut
//
//+---------------------------------------------------------------------------
const DWORD s_dwDotStyles[] = {1,2};
const DWORD s_dwDashStyles[] = {3,2};
HRESULT
UIComposition::PolyTextAndAttrOut(
TLS* ptls,
HDC hDC,
BOOL fVert,
COMPWND* pcompwnd)
{
CicBridge* cic = ptls->GetCicBridge();
if (cic == NULL)
{
Internal_PolyTextOutW(hDC, pcompwnd->poly_text.GetPolyData(), (int)pcompwnd->poly_text.GetPolySize());
DebugMsg(TF_ERROR, TEXT("UIComposition::PolyTextAndAttrOut. cic==NULL"));
return S_OK;
}
if (pcompwnd->poly_text.GetAttrSize() == 0)
{
//
// Korean default composition window.
//
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
Internal_PolyTextOutW(hDC, pcompwnd->poly_text.GetPolyData(), (int)pcompwnd->poly_text.GetPolySize());
return S_OK;
}
RECT rect;
GetClientRect(pcompwnd->hCompWnd, &rect);
LONG acpStart = 0;
for (int i = 0; i < pcompwnd->poly_text.GetAttrSize(); i++)
{
POLYTEXTW poly = pcompwnd->poly_text.GetPolyAt(i);
//
// Check if this is the last in this line.
//
BOOL fLastTextInLine = FALSE;
if (i + 1 < pcompwnd->poly_text.GetAttrSize())
{
POLYTEXTW poly_next = pcompwnd->poly_text.GetPolyAt(i+1);
if (!fVert && (poly_next.x < poly.rcl.right))
fLastTextInLine = TRUE;
else if (fVert && (poly_next.y < poly.rcl.bottom))
fLastTextInLine = TRUE;
}
else
{
fLastTextInLine = TRUE;
}
TF_DISPLAYATTRIBUTE da;
BOOL fDapNotFound = FALSE;
if (FAILED(cic->GetDisplayAttributeInfo(pcompwnd->poly_text.GetAttrAt(i), &da)))
{
memset(&da, 0, sizeof(da));
da.lsStyle = TF_LS_DOT;
da.crLine.type = TF_CT_SYSCOLOR;
da.crLine.nIndex = COLOR_WINDOWTEXT;
fDapNotFound= TRUE;
}
//
// Text and Back color.
//
switch (da.crText.type)
{
case TF_CT_SYSCOLOR: SetTextColor(hDC, GetSysColor(da.crText.nIndex)); break;
case TF_CT_COLORREF: SetTextColor(hDC, da.crText.cr); break;
default: SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); break;
}
switch (da.crBk.type)
{
case TF_CT_SYSCOLOR: SetBkColor(hDC, GetSysColor(da.crBk.nIndex)); break;
case TF_CT_COLORREF: SetBkColor(hDC, da.crBk.cr); break;
default: SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); break;
}
//
// Line
//
DWORD dwPenStyle = PS_GEOMETRIC | PS_SOLID;
DWORD dwStyles = 0;
const DWORD *lpdwStyles = NULL;
switch (da.lsStyle)
{
case TF_LS_NONE:
dwPenStyle = PS_NULL;
break;
case TF_LS_SOLID:
dwPenStyle = PS_GEOMETRIC | PS_SOLID;
break;
case TF_LS_DOT:
dwPenStyle = PS_GEOMETRIC | PS_USERSTYLE;
dwStyles = 2;
lpdwStyles = s_dwDotStyles;
break;
case TF_LS_DASH:
dwPenStyle = PS_GEOMETRIC | PS_USERSTYLE;
dwStyles = 2;
lpdwStyles = s_dwDashStyles;
break;
case TF_LS_SQUIGGLE:
dwPenStyle = PS_GEOMETRIC | PS_SOLID;
break;
}
DWORD dwWidth = 1;
if (da.fBoldLine)
{
dwWidth = LINE_BOLD_WIDTH;
}
LOGBRUSH lbr;
lbr.lbStyle = BS_SOLID;
lbr.lbColor = 0;
lbr.lbHatch = 0;
switch (da.crLine.type)
{
case TF_CT_SYSCOLOR: lbr.lbColor = GetSysColor(da.crLine.nIndex); break;
case TF_CT_COLORREF: lbr.lbColor = da.crLine.cr; break;
case TF_CT_NONE: lbr.lbColor = GetTextColor(hDC); break;
}
HPEN hPen = ExtCreatePen(dwPenStyle, dwWidth, &lbr, dwStyles, lpdwStyles);
if (hPen != NULL)
{
HPEN hPenOrg = (HPEN)SelectObject(hDC, hPen);
Internal_PolyTextOutW(hDC, &poly, 1);
SIZE size;
FLGetTextExtentPoint32(hDC, poly.lpstr, poly.n, &size);
POINT start_pt;
POINT end_pt;
if (!fVert)
{
start_pt.x = poly.x;
start_pt.y = poly.y + size.cy;
//
// (size.cy / 4) is the gap between clauses.
//
end_pt.x = poly.rcl.right;
if (!fLastTextInLine)
end_pt.x -= (size.cy / 4);
end_pt.y = start_pt.y;
}
else
{
RotateSize(&size);
start_pt.x = poly.rcl.left + 1;
start_pt.y = poly.y;
end_pt.x = poly.rcl.left + 1;
//
// (size.cx / 4) is the gap between clauses.
//
end_pt.y = poly.rcl.bottom;
if (!fLastTextInLine)
end_pt.y -= (size.cx / 4);
}
MoveToEx(hDC, start_pt.x, start_pt.y, NULL);
if (da.lsStyle != TF_LS_SQUIGGLE)
{
LineTo(hDC, end_pt.x, end_pt.y);
}
else
{
CArray<POINT, POINT> squiggle_line;
MakeSquiggleLine(start_pt, end_pt, LINE_SQUIGGLE_FREQUENCY, LINE_SQUIGGLE_AMPLITUDE, fVert, squiggle_line);
Polyline(hDC, squiggle_line.GetData(), (int)squiggle_line.GetSize());
}
SelectObject(hDC, hPenOrg);
DeleteObject(hPen);
}
else
{
Assert(0);
Internal_PolyTextOutW(hDC, &poly, 1);
}
//
// Draw Selection.
//
if (fDapNotFound && pcompwnd->sel.cch &&
((acpStart + (LONG)poly.n) > pcompwnd->sel.acpStart) &&
(acpStart <= pcompwnd->sel.acpStart + pcompwnd->sel.cch))
{
LONG acpSelStartTemp;
LONG cchSelTemp;
acpSelStartTemp = pcompwnd->sel.acpStart - acpStart;
if (acpSelStartTemp < 0)
acpSelStartTemp = 0;
cchSelTemp = pcompwnd->sel.acpStart + pcompwnd->sel.cch - acpStart - acpSelStartTemp;
if (cchSelTemp > (LONG)poly.n)
cchSelTemp = poly.n;
SIZE sizeStart;
SIZE sizeEnd;
if (acpSelStartTemp)
{
FLGetTextExtentPoint32(hDC,
poly.lpstr,
acpSelStartTemp,
&sizeStart);
}
else
{
sizeStart.cx = 0;
sizeStart.cy = pcompwnd->fDefaultCompWnd ?
m_tmFontHeightLevel1 : m_tmFontHeightLevel2;
}
FLGetTextExtentPoint32(hDC,
poly.lpstr,
acpSelStartTemp + cchSelTemp,
&sizeEnd);
RECT rcInvert;
rcInvert = poly.rcl;
if (!fVert)
{
rcInvert.left = poly.rcl.left + sizeStart.cx;
rcInvert.right = poly.rcl.left + sizeEnd.cx;
}
else
{
rcInvert.top = poly.rcl.top + sizeStart.cx;
rcInvert.bottom = poly.rcl.top + sizeEnd.cx;
}
BitBlt(hDC,
rcInvert.left,
rcInvert.top,
rcInvert.right - rcInvert.left,
rcInvert.bottom - rcInvert.top,
hDC,
rcInvert.left,
rcInvert.top,
DSTINVERT);
}
if (fLastTextInLine)
{
//
// if this is the last in this line, we just draw with bk color.
//
POLYTEXTW poly_clear;
memset(&poly_clear, 0, sizeof(poly_clear));
if (!fVert)
{
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
poly_clear.uiFlags = ETO_OPAQUE;
poly_clear.rcl.top = poly.y;
poly_clear.rcl.bottom = poly.rcl.bottom;
poly_clear.rcl.left = poly.rcl.right;
poly_clear.rcl.right = rect.right;
Internal_PolyTextOutW(hDC, &poly_clear, 1);
}
else
{
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
poly_clear.uiFlags = ETO_OPAQUE;
poly_clear.rcl.top = poly.rcl.bottom;
poly_clear.rcl.bottom = rect.bottom;
poly_clear.rcl.left = poly.rcl.left;
poly_clear.rcl.right = poly.x;
Internal_PolyTextOutW(hDC, &poly_clear, 1);
}
}
acpStart += poly.n;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::MakeSquiggleLine
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::MakeSquiggleLine(
POINT start_pt,
POINT end_pt,
int frequency,
int amplitude,
BOOL fVert,
CArray<POINT, POINT>& squiggle_line)
{
int nSquiggle = 0;
int n;
if (!fVert)
{
if (end_pt.x > start_pt.x)
n = (end_pt.x - start_pt.x) / frequency;
else
n = (start_pt.x - end_pt.x) / frequency;
}
else
{
if (end_pt.y > start_pt.y)
n = (end_pt.y - start_pt.y) / frequency;
else
n = (start_pt.y - end_pt.y) / frequency;
}
nSquiggle = n * 2; // control point.
nSquiggle++; // end point.
POINT begin_pt = start_pt;
POINT pt = begin_pt;
for (int i=1; i < nSquiggle; i++)
{
if (!fVert)
{
if ((n = i % 2) != 0)
{
// control point
pt.x += frequency / 2;
pt.y = begin_pt.y - amplitude;
}
else
{
pt.x = begin_pt.x + frequency;
pt.y = begin_pt.y;
begin_pt = pt;
}
}
else
{
if ((n = i % 2) != 0)
{
// control point
pt.x = begin_pt.x + amplitude;
pt.y += frequency / 2;
}
else
{
pt.x = begin_pt.x;
pt.y = begin_pt.y + frequency;
begin_pt = pt;
}
}
squiggle_line.SetAtGrow(i-1, pt);
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnPrivateGetContextFlag
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnPrivateGetContextFlag(
IMCLock& imc,
BOOL fStartComposition,
IME_UIWND_STATE* uists)
{
//
// Check WM_IME_STARTCOMPOSITION already send ?
//
if (fStartComposition)
{
WINDOWPLACEMENT wndpl;
if (IsWindow(m_DefCompWnd.hCompWnd) && IsWindowVisible(m_DefCompWnd.hCompWnd))
{
*uists = IME_UIWND_LEVEL1;
return S_OK;
}
else
{
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
if (IsWindow(m_CompWnd[i].hCompWnd) && IsWindowVisible(m_CompWnd[i].hCompWnd))
{
*uists = IME_UIWND_LEVEL2;
return S_OK;
}
}
}
//
// If m_fShowCompWnd flag set, already arrived WM_IME_COMPOSITION in this UI Wnd.
// In this case, IME UI Wnd Level is either Level 1 or Level 2.
//
if (m_fShowCompWnd.IsSetFlag())
{
*uists = IME_UIWND_LEVEL1_OR_LEVEL2;
return S_OK;
}
if (! (m_isc & ISC_SHOWUICOMPOSITIONWINDOW))
{
*uists = IME_UIWND_LEVEL3;
return S_OK;
}
}
*uists = IME_UIWND_UNKNOWN;
return S_FALSE;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnPrivateGetCandRectFromComposition
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnPrivateGetCandRectFromComposition(
IMCLock& imc,
CandRectFromComposition* pv)
{
HRESULT hr;
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
if (FAILED(hr=comp.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetCandRectFromComposition. comp==NULL"));
return hr;
}
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
if (uiwndState == IME_UIWND_LEVEL1)
{
LPCWSTR lpstr = (LPCWSTR)comp.GetOffsetPointer(comp->dwCompStrOffset);
SIZE size;
if (lpstr && pv->dwCharPos)
{
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
FLGetTextExtentPoint32(hDC, lpstr, pv->dwCharPos, &size);
SelectObject(hDC, hFontOrg);
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
}
else
{
size.cx = 0;
size.cy = m_tmFontHeightLevel1;
}
//
// When the style is DEFAULT, this is the default composition window.
//
GetWindowRect(m_DefCompWnd.hCompWnd, pv->out_rcArea);
POINT pt;
pt.x = pt.y = 0;
pv->out_rcArea->left += pt.x + size.cx;
pv->out_rcArea->right += pt.x + size.cx;
pv->out_rcArea->top += pt.y;
pv->out_rcArea->bottom += pt.y;
}
else if (uiwndState == IME_UIWND_LEVEL2)
{
BOOL fFound = FALSE;
POLYTEXTW poly;
DWORD dwCur = pv->dwCharPos;
int i;
if (PRIMARYLANGID(pv->langid) == LANG_JAPANESE)
{
//
// In Japanese case, poly_text stored each clause string.
//
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && ! fFound;)
{
for (int j=0; j < m_CompWnd[i].poly_text.GetPolySize(); j++)
{
poly = m_CompWnd[i].poly_text.GetPolyAt(j);
if (dwCur < poly.n)
{
fFound = TRUE;
break;
}
dwCur -= poly.n;
}
if (! fFound)
{
i++;
}
}
}
else
{
//
// In other language case, poly_text stored plane text. Not clause.
//
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && ! fFound;)
{
for (int j=0; j < m_CompWnd[i].poly_text.GetPolySize(); j++)
{
poly = m_CompWnd[i].poly_text.GetPolyAt(j);
if (dwCur <= poly.n)
{
fFound = TRUE;
poly.n = dwCur;
break;
}
dwCur -= poly.n;
}
if (! fFound)
{
i++;
}
}
}
if (! fFound)
{
return S_FALSE;
}
SIZE size;
if (poly.lpstr && poly.n)
{
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
FLGetTextExtentPoint32(hDC, poly.lpstr, poly.n, &size);
SelectObject(hDC, hFontOrg);
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
}
else
{
size.cx = 0;
size.cy = m_tmFontHeightLevel2;
}
if (!imc.UseVerticalCompWindow())
{
//
// When the style is not DEFAULT, this is the composition window.
//
if (PRIMARYLANGID(pv->langid) == LANG_JAPANESE)
{
pv->out_rcArea->left = poly.x;
}
else
{
pv->out_rcArea->left = poly.x + size.cx;
}
pv->out_rcArea->right = poly.x + size.cx;
pv->out_rcArea->top = poly.y;
pv->out_rcArea->bottom = poly.y + size.cy + LINE_BOLD_WIDTH;
}
else
{
RotateSize(&size);
pv->out_rcArea->left = poly.x - size.cx - LINE_BOLD_WIDTH;
pv->out_rcArea->right = poly.x;
pv->out_rcArea->top = poly.y;
pv->out_rcArea->bottom = poly.y + size.cy;
}
//
// Convert to Screen coordinate.
//
POINT pt;
pt.x = pt.y = 0;
ClientToScreen(m_CompWnd[i].hCompWnd, &pt);
pv->out_rcArea->left += pt.x;
pv->out_rcArea->right += pt.x;
pv->out_rcArea->top += pt.y;
pv->out_rcArea->bottom += pt.y;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::GetCompStrExtent
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::OnSetCursor(IMCLock &imc, WPARAM wParam, LPARAM lParam)
{
HRESULT hr = E_FAIL;
POINT pt;
ULONG uEdge;
ULONG uQuadrant;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr=imc_ctfime.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. imc_ctfime==NULL"));
return hr;
}
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. _pCicContext==NULL"));
return hr;
}
GetCursorPos(&pt);
GetCompStrExtent(pt, &uEdge, &uQuadrant, imc);
DWORD dwBtnStatus = 0;
if (GetKeyState(VK_LBUTTON) < 0)
{
dwBtnStatus |= MK_LBUTTON;
}
if (GetKeyState(VK_MBUTTON) < 0)
{
dwBtnStatus |= MK_MBUTTON;
}
if (GetKeyState(VK_RBUTTON) < 0)
{
dwBtnStatus |= MK_RBUTTON;
}
if (_pCicContext->MsImeMouseHandler(uEdge, uQuadrant, dwBtnStatus, imc) == 1L)
hr = S_OK;
return hr;
}
//+---------------------------------------------------------------------------
//
// UIComposition::GetCompStrExtent
//
//+---------------------------------------------------------------------------
HRESULT
UIComposition::GetCompStrExtent(
POINT pt,
ULONG *puEdge,
ULONG *puQuadrant,
IMCLock& imc)
{
Assert(puEdge);
Assert(puQuadrant);
*puEdge = 0;
*puQuadrant = 0;
ULONG uCount;
HRESULT hr;
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
if (FAILED(hr=comp.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::GetCompStrExtent. comp==NULL"));
return hr;
}
if (!comp.GetOffsetPointer(comp->dwCompStrLen))
{
//
// There is no composition string.
//
return S_OK;
}
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
if (uiwndState == IME_UIWND_LEVEL1)
{
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
POINT ptCli = pt;
ScreenToClient(m_DefCompWnd.hCompWnd, &ptCli);
hr = m_DefCompWnd.poly_text.GetPolyTextExtent(ptCli,
hDC,
FALSE,
puEdge,
puQuadrant);
SelectObject(hDC, hFontOrg);
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
}
else if (uiwndState == IME_UIWND_LEVEL2)
{
BOOL fVert = imc.UseVerticalCompWindow();
int i;
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
POINT ptCli = pt;
ScreenToClient(m_CompWnd[i].hCompWnd, &ptCli);
hr = m_CompWnd[i].poly_text.GetPolyTextExtent(ptCli,
hDC,
fVert,
puEdge,
puQuadrant);
SelectObject(hDC, hFontOrg);
ReleaseDC(m_CompWnd[i].hCompWnd, hDC);
if (hr == S_OK)
break;
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// UIComposition::CreateDefFrameWnd
//
//+---------------------------------------------------------------------------
HRESULT UIComposition::CreateDefFrameWnd(HWND hwndParent, HIMC hIMC)
{
DWORD dwWndStyle = // UIWINDOW_TOPMOST |
UIWINDOW_HASTOOLTIP |
UIWINDOW_HABITATINWORKAREA |
UIWINDOW_WHISTLERLOOK |
UIWINDOW_TOOLWINDOW;
if (!m_pDefCompFrameWnd)
{
m_pDefCompFrameWnd = new CDefCompFrameWindow(hIMC, dwWndStyle);
if (!m_pDefCompFrameWnd)
return E_OUTOFMEMORY;
if (!m_pDefCompFrameWnd->Initialize())
{
delete m_pDefCompFrameWnd;
m_pDefCompFrameWnd = NULL;
return E_FAIL;
}
m_pDefCompFrameWnd->Init();
}
m_pDefCompFrameWnd->CreateWnd(hwndParent);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::CreateCompButtonWnd
//
//+---------------------------------------------------------------------------
HRESULT UIComposition::CreateCompButtonWnd(HWND hwndParent, HIMC hIMC)
{
//
// #500698
//
// no more level2 comp window in English Speech so we don't need
// finalizing button on level2.
//
TLS * ptls = TLS::GetTLS();
if (!ptls || !ptls->NonEACompositionEnabled())
return S_OK;
//
// we don't use Level2 Comp Finalizing Button for EA language.
//
if (IsEALang())
{
if (m_pCompButtonFrameWnd)
{
delete m_pCompButtonFrameWnd;
m_pCompButtonFrameWnd = NULL;
}
return S_OK;
}
DWORD dwWndStyle = // UIWINDOW_TOPMOST |
UIWINDOW_HASTOOLTIP |
UIWINDOW_HABITATINWORKAREA |
UIWINDOW_WHISTLERLOOK |
UIWINDOW_TOOLWINDOW |
UIWINDOW_WSBORDER;
if (!m_pCompButtonFrameWnd)
{
m_pCompButtonFrameWnd = new CCompButtonFrameWindow(hIMC, dwWndStyle);
if (!m_pCompButtonFrameWnd)
return E_OUTOFMEMORY;
if (!m_pCompButtonFrameWnd->Initialize())
{
delete m_pCompButtonFrameWnd;
m_pCompButtonFrameWnd = NULL;
return E_FAIL;
}
m_pCompButtonFrameWnd->Init();
}
m_pCompButtonFrameWnd->CreateWnd(hwndParent);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// UIComposition::OnPrivateGetTextExtent
//
//+---------------------------------------------------------------------------
HRESULT UIComposition::OnPrivateGetTextExtent(IMCLock& imc, TEXTEXT *ptext_ext)
{
ULONG uCount;
HRESULT hr;
if (m_bTimerCOMPOSITION == TRUE)
{
// UIWnd has already got WM_IME_COMPOSITION with new composition text, and
// set a timer for it, but the time-out value has not yet elapsed, so the new
// composition window text is not updated yet.
// But caller of GetTextExtent may assume the new text has already been in the
// composition window and try to get extent for the updated range.
//
// In this case, we need to call UpdateCompositionRect( ) to update the composition
// Rect.
UpdateCompositionRect(imc);
}
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr=imc_ctfime.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. imc_ctfime==NULL"));
return hr;
}
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. _pCicContext==NULL"));
return hr;
}
LONG cch = 0;
if (FAILED(_pCicContext->EscbReadOnlyPropMargin(imc, NULL, &cch)))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. comp==NULL"));
return hr;
}
ptext_ext->acpStart -= cch;
ptext_ext->acpEnd -= cch;
if (ptext_ext->prc)
memset(ptext_ext->prc, 0, sizeof(*ptext_ext->prc));
if (ptext_ext->pfClipped)
*ptext_ext->pfClipped = FALSE;
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
if (FAILED(hr=comp.GetResult()))
{
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. comp==NULL"));
return hr;
}
if (!comp.GetOffsetPointer(comp->dwCompStrLen))
{
//
// There is no composition string.
//
return S_OK;
}
// If the requested range is beyond the composition window,
// just return the position based on the real window.
// this is hack for CHS/CHT TIP's special design.
if (ptext_ext->acpStart > (LONG)(comp->dwCompStrLen))
ptext_ext->acpStart = (LONG)(comp->dwCompStrLen);
if (ptext_ext->acpEnd > (LONG)(comp->dwCompStrLen))
ptext_ext->acpEnd = (LONG)(comp->dwCompStrLen);
RECT rcStart = {0};
RECT rcEnd = {0};
HRESULT hrStart = S_FALSE;
HRESULT hrEnd = S_FALSE;
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
if (uiwndState == IME_UIWND_LEVEL1)
{
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
DWORD acpStart = ptext_ext->acpStart;
DWORD acpEnd = ptext_ext->acpEnd;
hrStart = m_DefCompWnd.poly_text.GetPolyTextExtentRect(acpStart, hDC, FALSE, TRUE, &rcStart);
if (hrStart == S_OK)
m_DefCompWnd._ClientToScreen(&rcStart);
hrEnd = m_DefCompWnd.poly_text.GetPolyTextExtentRect(acpEnd, hDC, FALSE, TRUE, &rcEnd);
if (hrEnd == S_OK)
m_DefCompWnd._ClientToScreen(&rcEnd);
SelectObject(hDC, hFontOrg);
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
}
else if (uiwndState == IME_UIWND_LEVEL2)
{
DWORD acpStart;
DWORD acpEnd;
BOOL fVert;
BOOL fGetLast = FALSE;
int i;
TryWithLast:
acpStart = ptext_ext->acpStart;
acpEnd = ptext_ext->acpEnd;
fVert = imc.UseVerticalCompWindow();
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
{
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
if (hrStart != S_OK)
{
hrStart = m_CompWnd[i].poly_text.GetPolyTextExtentRect(acpStart, hDC, fVert, fGetLast, &rcStart);
if (hrStart == S_OK)
m_CompWnd[i]._ClientToScreen(&rcStart);
}
if (hrEnd != S_OK)
{
hrEnd = m_CompWnd[i].poly_text.GetPolyTextExtentRect(acpEnd, hDC, fVert, fGetLast, &rcEnd);
if (hrEnd == S_OK)
m_CompWnd[i]._ClientToScreen(&rcEnd);
}
SelectObject(hDC, hFontOrg);
ReleaseDC(m_CompWnd[i].hCompWnd, hDC);
if ((hrStart == S_OK) && (hrEnd == S_OK))
break;
}
if (!fGetLast && (hrStart != S_OK))
{
fGetLast = TRUE;
goto TryWithLast;
}
}
if (hrStart == S_OK)
{
if (hrEnd == S_OK)
{
ptext_ext->prc->left = min(rcStart.left , rcEnd.left);
ptext_ext->prc->top = min(rcStart.top , rcEnd.top);
ptext_ext->prc->bottom = max(rcStart.bottom , rcEnd.bottom);
ptext_ext->prc->right = max(rcStart.right , rcEnd.right);
}
else
{
ptext_ext->prc->left = rcStart.left;
ptext_ext->prc->top = rcStart.top;
ptext_ext->prc->bottom = rcStart.bottom;
ptext_ext->prc->right = rcStart.right;
}
}
return hrStart;
}