summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYohei Yukawa <yukawa@google.com>2013-05-06 14:20:11 +0900
committerTor Lillqvist <tml@iki.fi>2013-05-13 05:14:37 +0000
commit57b5ed51d46fd5673dfe35125ceffa71d39f133d (patch)
treec6dcc9991647a7869451a15ba436cb7443f1dc06
parentc0417e82174297ace604c68fc577c831929f3573 (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.cxx27
-rw-r--r--include/vcl/cmdevt.hxx2
-rw-r--r--include/vcl/window.hxx2
-rw-r--r--sc/source/ui/app/inputhdl.cxx15
-rw-r--r--sc/source/ui/view/gridwin.cxx3
-rw-r--r--sw/inc/crsrsh.hxx4
-rw-r--r--sw/source/core/crsr/crsrsh.cxx5
-rw-r--r--sw/source/ui/docvw/edtwin.cxx44
-rw-r--r--vcl/inc/salwtype.hxx13
-rw-r--r--vcl/inc/window.h3
-rw-r--r--vcl/source/control/edit.cxx34
-rw-r--r--vcl/source/window/window.cxx24
-rw-r--r--vcl/source/window/winproc.cxx47
-rw-r--r--vcl/win/source/window/salframe.cxx56
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
}