diff options
author | Yohei Yukawa <yukawa@google.com> | 2013-05-06 14:20:11 +0900 |
---|---|---|
committer | Tor Lillqvist <tml@iki.fi> | 2013-05-13 05:14:37 +0000 |
commit | 57b5ed51d46fd5673dfe35125ceffa71d39f133d (patch) | |
tree | c6dcc9991647a7869451a15ba436cb7443f1dc06 | |
parent | c0417e82174297ace604c68fc577c831929f3573 (diff) |
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 <tml@iki.fi>
Tested-by: Tor Lillqvist <tml@iki.fi>
-rw-r--r-- | editeng/source/editeng/impedit2.cxx | 27 | ||||
-rw-r--r-- | include/vcl/cmdevt.hxx | 2 | ||||
-rw-r--r-- | include/vcl/window.hxx | 2 | ||||
-rw-r--r-- | sc/source/ui/app/inputhdl.cxx | 15 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin.cxx | 3 | ||||
-rw-r--r-- | sw/inc/crsrsh.hxx | 4 | ||||
-rw-r--r-- | sw/source/core/crsr/crsrsh.cxx | 5 | ||||
-rw-r--r-- | sw/source/ui/docvw/edtwin.cxx | 44 | ||||
-rw-r--r-- | vcl/inc/salwtype.hxx | 13 | ||||
-rw-r--r-- | vcl/inc/window.h | 3 | ||||
-rw-r--r-- | vcl/source/control/edit.cxx | 34 | ||||
-rw-r--r-- | vcl/source/window/window.cxx | 24 | ||||
-rw-r--r-- | vcl/source/window/winproc.cxx | 47 | ||||
-rw-r--r-- | vcl/win/source/window/salframe.cxx | 56 |
14 files changed, 272 insertions, 7 deletions
diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx index 8934bf8af0ae..b46b23cf72ef 100644 --- a/editeng/source/editeng/impedit2.cxx +++ b/editeng/source/editeng/impedit2.cxx @@ -537,6 +537,33 @@ void ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView ) } } } + else if ( rCEvt.GetCommand() == COMMAND_QUERYCHARPOSITION ) + { + if ( mpIMEInfos && mpIMEInfos->nLen ) + { + EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() ); + if ( !IsFormatted() ) + FormatDoc(); + + ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) ); + sal_uInt16 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), sal_True ); + const EditLine* pLine = pParaPortion->GetLines()[nLine]; + if ( pLine ) + { + Rectangle* aRects = new Rectangle[ mpIMEInfos->nLen ]; + for (sal_uInt16 i = 0; i < mpIMEInfos->nLen; ++i) + { + sal_uInt16 nInputPos = mpIMEInfos->aPos.GetIndex() + i; + if ( nInputPos > pLine->GetEnd() ) + nInputPos = pLine->GetEnd(); + Rectangle aR2 = GetEditCursor( pParaPortion, nInputPos ); + aRects[ i ] = pView->GetImpEditView()->GetWindowPos( aR2 ); + } + pView->GetWindow()->SetCompositionCharRect( aRects, mpIMEInfos->nLen ); + delete[] aRects; + } + } + } GetSelEngine().Command( rCEvt ); } diff --git a/include/vcl/cmdevt.hxx b/include/vcl/cmdevt.hxx index 03876e52e5a3..75714f2f531f 100644 --- a/include/vcl/cmdevt.hxx +++ b/include/vcl/cmdevt.hxx @@ -351,6 +351,8 @@ inline CommandSelectionChangeData::CommandSelectionChangeData( sal_uLong nStart, #define COMMAND_MEDIA ((sal_uInt16)17) #define COMMAND_SELECTIONCHANGE ((sal_uInt16)18) #define COMMAND_PREPARERECONVERSION ((sal_uInt16)19) +#define COMMAND_QUERYCHARPOSITION ((sal_uInt16)20) + class VCL_DLLPUBLIC CommandEvent { diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index 43e232dab55c..d1c783bc0e69 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -680,6 +680,8 @@ public: const Rectangle* GetCursorRect() const; long GetCursorExtTextInputWidth() const; + void SetCompositionCharRect( const Rectangle* pRect, long nCompositionLength, sal_Bool bVertical = sal_False ); + using OutputDevice::SetSettings; virtual void SetSettings( const AllSettings& rSettings ); virtual void SetSettings( const AllSettings& rSettings, sal_Bool bChild ); diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx index b3bd84a5ba26..9baa6cc36eda 100644 --- a/sc/source/ui/app/inputhdl.cxx +++ b/sc/source/ui/app/inputhdl.cxx @@ -3351,6 +3351,21 @@ bool ScInputHandler::InputCommand( const CommandEvent& rCEvt, bool bForce ) } } } + else if ( rCEvt.GetCommand() == COMMAND_QUERYCHARPOSITION ) + { + if ( eMode != SC_INPUT_NONE ) + { + UpdateActiveView(); + if (pTableView || pTopView) + { + if (pTableView) + pTableView->Command( rCEvt ); + else if (pTopView) // call only once + pTopView->Command( rCEvt ); + bUsed = true; + } + } + } else { if ( bForce || eMode != SC_INPUT_NONE ) diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index cb9c09f19788..86cddf2526c9 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -2813,7 +2813,8 @@ void ScGridWindow::Command( const CommandEvent& rCEvt ) if ( nCmd == COMMAND_STARTEXTTEXTINPUT || nCmd == COMMAND_ENDEXTTEXTINPUT || nCmd == COMMAND_EXTTEXTINPUT || - nCmd == COMMAND_CURSORPOS ) + nCmd == COMMAND_CURSORPOS || + nCmd == COMMAND_QUERYCHARPOSITION ) { sal_Bool bEditView = pViewData->HasEditView( eWhich ); if (!bEditView) diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx index 2ddb6d56e13c..58107ded4ebf 100644 --- a/sw/inc/crsrsh.hxx +++ b/sw/inc/crsrsh.hxx @@ -526,6 +526,10 @@ public: * Returns if cursor is wholly or partly within visible range. */ sal_Bool IsCrsrVisible() const { return VisArea().IsOver( GetCharRect() ); } + /* + * Returns SwRect, at which the character is located. + */ + sal_Bool GetCharRectAt(SwRect& rRect, const SwPosition* pPos); // Return current page number: // TRUE: in which cursor is located. diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 574ac81b6659..23b54f20f8f1 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -1005,6 +1005,11 @@ sal_Bool SwCrsrShell::GotoPage( sal_uInt16 nPage ) return bRet; } +sal_Bool SwCrsrShell::GetCharRectAt(SwRect& rRect, const SwPosition* pPos) +{ + SwCntntFrm* pFrm = GetCurrFrm(); + return pFrm->GetCharRect( rRect, *pPos ); +} void SwCrsrShell::GetPageNum( sal_uInt16 &rnPhyNum, sal_uInt16 &rnVirtNum, sal_Bool bAtCrsrPos, const sal_Bool bCalcFrm ) diff --git a/sw/source/ui/docvw/edtwin.cxx b/sw/source/ui/docvw/edtwin.cxx index 3ec057d993f8..ba6c20cb2fb8 100644 --- a/sw/source/ui/docvw/edtwin.cxx +++ b/sw/source/ui/docvw/edtwin.cxx @@ -5193,6 +5193,50 @@ void SwEditWin::Command( const CommandEvent& rCEvt ) } } break; + case COMMAND_QUERYCHARPOSITION: + { + SwWrtShell &rSh = m_rView.GetWrtShell(); + sal_Bool bVertical = rSh.IsInVerticalText(); + const SwPosition& rPos = *rSh.GetCrsr()->GetPoint(); + SwDocShell* pDocSh = m_rView.GetDocShell(); + SwDoc *pDoc = pDocSh->GetDoc(); + SwExtTextInput* pInput = pDoc->GetExtTextInput( rPos.nNode.GetNode(), rPos.nContent.GetIndex() ); + if ( pInput ) + { + const SwPosition& rStart = *pInput->Start(); + const SwPosition& rEnd = *pInput->End(); + int nSize = 0; + for ( SwIndex nIndex = rStart.nContent; nIndex < rEnd.nContent; ++nIndex ) + { + ++nSize; + } + Window& rWin = rSh.GetView().GetEditWin(); + if ( nSize == 0 ) + { + // When the composition does not exist, use Caret rect instead. + SwRect aCaretRect ( rSh.GetCharRect() ); + Rectangle aRect( aCaretRect.Left(), aCaretRect.Top(), aCaretRect.Right(), aCaretRect.Bottom() ); + rWin.SetCompositionCharRect( &aRect, 1, bVertical ); + } + else + { + Rectangle* aRects = new Rectangle[ nSize ]; + int nRectIndex = 0; + for ( SwIndex nIndex = rStart.nContent; nIndex < rEnd.nContent; ++nIndex ) + { + const SwPosition aPos( rStart.nNode, nIndex ); + SwRect aRect ( rSh.GetCharRect() ); + rSh.GetCharRectAt( aRect, &aPos ); + aRects[ nRectIndex ] = Rectangle( aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom() ); + ++nRectIndex; + } + rWin.SetCompositionCharRect( aRects, nSize, bVertical ); + delete[] aRects; + } + } + bCallBase = false; + } + break; #if OSL_DEBUG_LEVEL > 0 default: OSL_ENSURE( !this, "unknown command." ); diff --git a/vcl/inc/salwtype.hxx b/vcl/inc/salwtype.hxx index 62b982f8f5b6..55bc006f90e5 100644 --- a/vcl/inc/salwtype.hxx +++ b/vcl/inc/salwtype.hxx @@ -82,6 +82,7 @@ class FontSelectPattern; #define SALEVENT_STARTRECONVERSION ((sal_uInt16)45) #define SALEVENT_EXTERNALZOOM ((sal_uInt16)46) #define SALEVENT_EXTERNALSCROLL ((sal_uInt16)47) +#define SALEVENT_QUERYCHARPOSITION ((sal_uInt16)48) // MOUSELEAVE must send, when the pointer leave the client area and // the mouse is not captured @@ -213,6 +214,18 @@ struct SalSurroundingTextSelectionChangeEvent sal_uLong mnEnd; // The end index of selected range }; +// QUERYCHARPOSITION +struct SalQueryCharPositionEvent +{ + bool mbValid; // The data is valid or not. + sal_uLong mnCharPos; // The index of character in a composition. + bool mbVertical; // The text is vertical or not. + long mnCursorBoundX; // The cursor bounds corresponding to the character specified by mnCharPos - X + long mnCursorBoundY; // The cursor bounds corresponding to the character specified by mnCharPos - Y + long mnCursorBoundWidth; // The cursor bounds corresponding to the character specified by mnCharPos - Width + long mnCursorBoundHeight; // The cursor bounds corresponding to the character specified by mnCharPos - Height +}; + // ------------------ // - SalFrame-Types - // ------------------ diff --git a/vcl/inc/window.h b/vcl/inc/window.h index 725f5ad2c630..230e1b07d068 100644 --- a/vcl/inc/window.h +++ b/vcl/inc/window.h @@ -116,6 +116,9 @@ struct ImplWinData sal_uInt16* mpExtOldAttrAry; Rectangle* mpCursorRect; long mnCursorExtWidth; + sal_Bool mbVertical; + Rectangle* mpCompositionCharRects; + long mnCompositionCharRects; Rectangle* mpFocusRect; Rectangle* mpTrackRect; sal_uInt16 mnTrackFlags; 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 ) @@ -5658,6 +5662,24 @@ long Window::GetCursorExtTextInputWidth() const } // ----------------------------------------------------------------------- + +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 ) { SetSettings( rSettings, sal_False ); 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<sal_uLong>( 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 << ")" ); diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx index 05ecefdb44d1..574519c3f5a2 100644 --- a/vcl/win/source/window/salframe.cxx +++ b/vcl/win/source/window/salframe.cxx @@ -5523,6 +5523,47 @@ static LRESULT ImplHandleIMEConfirmReconvertString( HWND hWnd, LPARAM lParam ) return TRUE; } +static LRESULT ImplHandleIMEQueryCharPosition( HWND hWnd, LPARAM lParam ) { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + PIMECHARPOSITION pQueryCharPosition = (PIMECHARPOSITION) lParam; + if ( pQueryCharPosition->dwSize < sizeof(IMECHARPOSITION) ) + return FALSE; + + SalQueryCharPositionEvent aEvt; + aEvt.mbValid = false; + aEvt.mnCharPos = pQueryCharPosition->dwCharPos; + + pFrame->CallCallback( SALEVENT_QUERYCHARPOSITION, (void*)&aEvt ); + + if ( !aEvt.mbValid ) + return FALSE; + + if ( aEvt.mbVertical ) + { + // For vertical writing, the base line is left edge of the rectangle + // and the target position is top-right corner. + pQueryCharPosition->pt.x = aEvt.mnCursorBoundX + aEvt.mnCursorBoundWidth; + pQueryCharPosition->pt.y = aEvt.mnCursorBoundY; + pQueryCharPosition->cLineHeight = aEvt.mnCursorBoundWidth; + } + else + { + // For horizontal writing, the base line is the bottom edge of the rectangle. + // and the target position is top-left corner. + pQueryCharPosition->pt.x = aEvt.mnCursorBoundX; + pQueryCharPosition->pt.y = aEvt.mnCursorBoundY; + pQueryCharPosition->cLineHeight = aEvt.mnCursorBoundHeight; + } + + // Currently not supported but many IMEs usually ignore them. + pQueryCharPosition->rcDocument.left = 0; + pQueryCharPosition->rcDocument.top = 0; + pQueryCharPosition->rcDocument.right = 0; + pQueryCharPosition->rcDocument.bottom = 0; + + return TRUE; +} + #endif // WINVER >= 0x0500 // ----------------------------------------------------------------------- @@ -5945,11 +5986,16 @@ LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lP nRet = ImplHandleIMEReconvertString( hWnd, lParam ); rDef = FALSE; } - else if( (sal_uIntPtr)( wParam ) == IMR_CONFIRMRECONVERTSTRING ) - { - nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam ); - rDef = FALSE; - } + else if( (sal_uIntPtr)( wParam ) == IMR_CONFIRMRECONVERTSTRING ) + { + nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam ); + rDef = FALSE; + } + else if ( (sal_uIntPtr)( wParam ) == IMR_QUERYCHARPOSITION ) + { + nRet = ImplHandleIMEQueryCharPosition( hWnd, lParam ); + rDef = FALSE; + } break; #endif // WINVER >= 0x0500 } |