From 57b5ed51d46fd5673dfe35125ceffa71d39f133d Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Mon, 6 May 2013 14:20:11 +0900 Subject: Support IMR_QUERYCHARPOSITION in Writer and Calc. IMR_QUERYCHARPOSITION is one of optional but fundamental request message sent from IMEs to application. This message is used for retrieving the positional information for each character in a composition text especially when the composition text is drawn by the application. This information is critical for IMEs to align suggestion window with the composition text. Change-Id: I53a344a78688060004cc8bcbbf1127f22a468e20 Reviewed-on: https://gerrit.libreoffice.org/3849 Reviewed-by: Tor Lillqvist Tested-by: Tor Lillqvist --- vcl/source/control/edit.cxx | 34 +++++++++++++++++++++++++++++++ vcl/source/window/window.cxx | 24 +++++++++++++++++++++- vcl/source/window/winproc.cxx | 47 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) (limited to 'vcl/source') diff --git a/vcl/source/control/edit.cxx b/vcl/source/control/edit.cxx index 41722998160a..10b25dc94c6c 100644 --- a/vcl/source/control/edit.cxx +++ b/vcl/source/control/edit.cxx @@ -2313,6 +2313,40 @@ void Edit::Command( const CommandEvent& rCEvt ) Selection aSelection( pData->GetStart(), pData->GetEnd() ); SetSelection(aSelection); } + else if ( rCEvt.GetCommand() == COMMAND_QUERYCHARPOSITION ) + { + if (mpIMEInfos && mpIMEInfos->nLen > 0) + { + OUString aText = ImplGetText(); + sal_Int32 nDXBuffer[256]; + sal_Int32* pDXBuffer = NULL; + sal_Int32* pDX = nDXBuffer; + + if( !aText.isEmpty() ) + { + if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) ) + { + pDXBuffer = new sal_Int32[2*(aText.getLength()+1)]; + pDX = pDXBuffer; + } + + GetCaretPositions( aText, pDX, 0, aText.getLength() ); + } + long nTH = GetTextHeight(); + Point aPos( mnXOffset, ImplGetTextYPosition() ); + + Rectangle* aRects = new Rectangle[ mpIMEInfos->nLen ]; + for ( int nIndex = 0; nIndex < mpIMEInfos->nLen; ++nIndex ) + { + Rectangle aRect( aPos, Size( 10, nTH ) ); + aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset(); + aRects[ nIndex ] = aRect; + } + SetCompositionCharRect( aRects, mpIMEInfos->nLen ); + delete[] aRects; + delete[] pDXBuffer; + } + } else Control::Command( rCEvt ); } diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index fc692d21405e..dfb22398ed4b 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -1372,8 +1372,10 @@ ImplWinData* Window::ImplGetWinData() const ((Window*)this)->mpWindowImpl->mpWinData = new ImplWinData; mpWindowImpl->mpWinData->mpExtOldText = NULL; mpWindowImpl->mpWinData->mpExtOldAttrAry = NULL; - mpWindowImpl->mpWinData->mpCursorRect = 0; + mpWindowImpl->mpWinData->mpCursorRect = NULL; mpWindowImpl->mpWinData->mnCursorExtWidth = 0; + mpWindowImpl->mpWinData->mpCompositionCharRects = NULL; + mpWindowImpl->mpWinData->mnCompositionCharRects = 0; mpWindowImpl->mpWinData->mpFocusRect = NULL; mpWindowImpl->mpWinData->mpTrackRect = NULL; mpWindowImpl->mpWinData->mnTrackFlags = 0; @@ -4644,6 +4646,8 @@ Window::~Window() delete mpWindowImpl->mpWinData->mpExtOldAttrAry; if ( mpWindowImpl->mpWinData->mpCursorRect ) delete mpWindowImpl->mpWinData->mpCursorRect; + if ( mpWindowImpl->mpWinData->mpCompositionCharRects) + delete[] mpWindowImpl->mpWinData->mpCompositionCharRects; if ( mpWindowImpl->mpWinData->mpFocusRect ) delete mpWindowImpl->mpWinData->mpFocusRect; if ( mpWindowImpl->mpWinData->mpTrackRect ) @@ -5657,6 +5661,24 @@ long Window::GetCursorExtTextInputWidth() const return pWinData->mnCursorExtWidth; } +// ----------------------------------------------------------------------- + +void Window::SetCompositionCharRect( const Rectangle* pRect, long nCompositionLength, sal_Bool bVertical ) { + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplWinData* pWinData = ImplGetWinData(); + delete[] pWinData->mpCompositionCharRects; + pWinData->mbVertical = bVertical; + pWinData->mpCompositionCharRects = NULL; + pWinData->mnCompositionCharRects = nCompositionLength; + if ( pRect && (nCompositionLength > 0) ) + { + pWinData->mpCompositionCharRects = new Rectangle[nCompositionLength]; + for (long i = 0; i < nCompositionLength; ++i) + pWinData->mpCompositionCharRects[i] = pRect[i]; + } +} + // ----------------------------------------------------------------------- void Window::SetSettings( const AllSettings& rSettings ) { diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx index 2a296ca8309d..73e5a7a6e800 100644 --- a/vcl/source/window/winproc.cxx +++ b/vcl/source/window/winproc.cxx @@ -2348,6 +2348,50 @@ static void ImplHandleStartReconversion( Window *pWindow ) // ----------------------------------------------------------------------- +static void ImplHandleSalQueryCharPosition( Window *pWindow, + SalQueryCharPositionEvent *pEvt ) +{ + pEvt->mbValid = false; + pEvt->mbVertical = false; + pEvt->mnCursorBoundX = 0; + pEvt->mnCursorBoundY = 0; + pEvt->mnCursorBoundWidth = 0; + pEvt->mnCursorBoundHeight = 0; + + ImplSVData* pSVData = ImplGetSVData(); + Window* pChild = pSVData->maWinData.mpExtTextInputWin; + + if ( !pChild ) + pChild = ImplGetKeyInputWindow( pWindow ); + else + { + // Test, if the Window is related to the frame + if ( !pWindow->ImplIsWindowOrChild( pChild ) ) + pChild = ImplGetKeyInputWindow( pWindow ); + } + + if( pChild ) + { + ImplCallCommand( pChild, COMMAND_QUERYCHARPOSITION ); + + ImplWinData* pWinData = pChild->ImplGetWinData(); + if ( pWinData->mpCompositionCharRects && pEvt->mnCharPos < static_cast( pWinData->mnCompositionCharRects ) ) + { + const Rectangle& aRect = pWinData->mpCompositionCharRects[ pEvt->mnCharPos ]; + Rectangle aDeviceRect = pChild->ImplLogicToDevicePixel( aRect ); + Point aAbsScreenPos = pChild->OutputToAbsoluteScreenPixel( pChild->ScreenToOutputPixel(aDeviceRect.TopLeft()) ); + pEvt->mnCursorBoundX = aAbsScreenPos.X(); + pEvt->mnCursorBoundY = aAbsScreenPos.Y(); + pEvt->mnCursorBoundWidth = aDeviceRect.GetWidth(); + pEvt->mnCursorBoundHeight = aDeviceRect.GetHeight(); + pEvt->mbVertical = (pWinData->mbVertical != sal_False); + pEvt->mbValid = true; + } + } +} + +// ----------------------------------------------------------------------- + long ImplWindowFrameProc( Window* pWindow, SalFrame* /*pFrame*/, sal_uInt16 nEvent, const void* pEvent ) { @@ -2659,6 +2703,9 @@ long ImplWindowFrameProc( Window* pWindow, SalFrame* /*pFrame*/, } } break; + case SALEVENT_QUERYCHARPOSITION: + ImplHandleSalQueryCharPosition( pWindow, (SalQueryCharPositionEvent*)pEvent ); + break; #ifdef DBG_UTIL default: SAL_WARN( "vcl.layout", "ImplWindowFrameProc(): unknown event (" << nEvent << ")" ); -- cgit