From b5c61b525cca0d0dbec58273a5209cdc45b742e6 Mon Sep 17 00:00:00 2001 From: Thomas Lange Date: Wed, 25 Nov 2009 16:49:20 +0000 Subject: #i51258# thesaurus for right click context menu --- vcl/source/window/seleng.cxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/source/window/seleng.cxx b/vcl/source/window/seleng.cxx index 136d8ad968b7..3b24b34855c8 100644 --- a/vcl/source/window/seleng.cxx +++ b/vcl/source/window/seleng.cxx @@ -203,7 +203,11 @@ void SelectionEngine::CursorPosChanging( BOOL bShift, BOOL bMod1 ) BOOL SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt ) { nFlags &= (~SELENG_CMDEVT); - if ( !pFunctionSet || !pWin || rMEvt.GetClicks() > 1 || rMEvt.IsRight() ) + if ( !pFunctionSet || !pWin ) + return FALSE; + const bool bRightClickCursorPositioning = + rMEvt.IsRight() && rMEvt.GetClicks() == 1 && !IsInSelection(); + if ( (rMEvt.GetClicks() > 1 || rMEvt.IsRight()) && !bRightClickCursorPositioning ) return FALSE; USHORT nModifier = rMEvt.GetModifier() | nLockedMods; -- cgit From 08e0e53c74d3d5019a7c510e39e8adf57145ca70 Mon Sep 17 00:00:00 2001 From: "Frank Schoenheit [fs]" Date: Thu, 29 Apr 2010 10:05:04 +0200 Subject: fs33a: #i111238# add support for images to AWT's ListBoxControl/Model --- vcl/inc/vcl/lstbox.hxx | 1 + vcl/source/control/lstbox.cxx | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'vcl') diff --git a/vcl/inc/vcl/lstbox.hxx b/vcl/inc/vcl/lstbox.hxx index 98cd05d999dd..3659e5aee485 100644 --- a/vcl/inc/vcl/lstbox.hxx +++ b/vcl/inc/vcl/lstbox.hxx @@ -130,6 +130,7 @@ public: virtual USHORT GetEntryPos( const XubString& rStr ) const; virtual USHORT GetEntryPos( const void* pData ) const; + Image GetEntryImage( USHORT nPos ) const; virtual XubString GetEntry( USHORT nPos ) const; virtual USHORT GetEntryCount() const; diff --git a/vcl/source/control/lstbox.cxx b/vcl/source/control/lstbox.cxx index 70b67c0a3d57..dde34d52806c 100644 --- a/vcl/source/control/lstbox.cxx +++ b/vcl/source/control/lstbox.cxx @@ -1081,6 +1081,15 @@ void ListBox::RemoveEntry( USHORT nPos ) // ----------------------------------------------------------------------- +Image ListBox::GetEntryImage( USHORT nPos ) const +{ + if ( mpImplLB->GetEntryList()->HasEntryImage( nPos ) ) + return mpImplLB->GetEntryList()->GetEntryImage( nPos ); + return Image(); +} + +// ----------------------------------------------------------------------- + USHORT ListBox::GetEntryPos( const XubString& rStr ) const { USHORT nPos = mpImplLB->GetEntryList()->FindEntry( rStr ); -- cgit From aae2c038fad7eaeda79b1d77840cbbecb99f268b Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Thu, 25 Mar 2010 18:16:13 +0100 Subject: vcl111: #i92094# use current event for GetPointerState --- vcl/aqua/source/window/salframe.cxx | 95 ++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 27 deletions(-) (limited to 'vcl') diff --git a/vcl/aqua/source/window/salframe.cxx b/vcl/aqua/source/window/salframe.cxx index 71c84ee0c2f1..413b5bcd5490 100644 --- a/vcl/aqua/source/window/salframe.cxx +++ b/vcl/aqua/source/window/salframe.cxx @@ -1352,40 +1352,81 @@ void AquaSalFrame::GetWorkArea( Rectangle& rRect ) SalPointerState AquaSalFrame::GetPointerState() { SalPointerState state; + state.mnState = 0; // get position NSPoint aPt = [mpWindow mouseLocationOutsideOfEventStream]; CocoaToVCL( aPt, false ); state.maPos = Point(static_cast(aPt.x), static_cast(aPt.y)); - // FIXME: replace Carbon by Cocoa - // Cocoa does not have an equivalent for GetCurrentEventButtonState - // and GetCurrentEventKeyModifiers. - // we could try to get away with tracking all events for modifierKeys - // and all mouse events for button state in VCL_NSApllication::sendEvent, - // but it is unclear whether this will get us the same result. - // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now + NSEvent* pCur = [NSApp currentEvent]; + bool bMouseEvent = false; + if( pCur ) + { + bMouseEvent = true; + switch( [pCur type] ) + { + case NSLeftMouseDown: state.mnState |= MOUSE_LEFT; break; + case NSLeftMouseUp: break; + case NSRightMouseDown: state.mnState |= MOUSE_RIGHT; break; + case NSRightMouseUp: break; + case NSOtherMouseDown: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break; + case NSOtherMouseUp: break; + case NSMouseMoved: break; + case NSLeftMouseDragged: state.mnState |= MOUSE_LEFT; break; + case NSRightMouseDragged: state.mnState |= MOUSE_RIGHT; break; + case NSOtherMouseDragged: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break; + break; + default: + bMouseEvent = false; + break; + } + } + if( bMouseEvent ) + { + unsigned int nMask = (unsigned int)[pCur modifierFlags]; + if( (nMask & NSShiftKeyMask) != 0 ) + state.mnState |= KEY_SHIFT; + if( (nMask & NSControlKeyMask) != 0 ) + state.mnState |= KEY_MOD3; + if( (nMask & NSAlternateKeyMask) != 0 ) + state.mnState |= KEY_MOD2; + if( (nMask & NSCommandKeyMask) != 0 ) + state.mnState |= KEY_MOD1; + + } + else + { + // FIXME: replace Carbon by Cocoa + // Cocoa does not have an equivalent for GetCurrentEventButtonState + // and GetCurrentEventKeyModifiers. + // we could try to get away with tracking all events for modifierKeys + // and all mouse events for button state in VCL_NSApllication::sendEvent, + // but it is unclear whether this will get us the same result. + // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now + + // fill in button state + UInt32 nState = GetCurrentEventButtonState(); + state.mnState = 0; + if( nState & 1 ) + state.mnState |= MOUSE_LEFT; // primary button + if( nState & 2 ) + state.mnState |= MOUSE_RIGHT; // secondary button + if( nState & 4 ) + state.mnState |= MOUSE_MIDDLE; // tertiary button + + // fill in modifier state + nState = GetCurrentEventKeyModifiers(); + if( nState & shiftKey ) + state.mnState |= KEY_SHIFT; + if( nState & controlKey ) + state.mnState |= KEY_MOD3; + if( nState & optionKey ) + state.mnState |= KEY_MOD2; + if( nState & cmdKey ) + state.mnState |= KEY_MOD1; + } - // fill in button state - UInt32 nState = GetCurrentEventButtonState(); - state.mnState = 0; - if( nState & 1 ) - state.mnState |= MOUSE_LEFT; // primary button - if( nState & 2 ) - state.mnState |= MOUSE_RIGHT; // secondary button - if( nState & 4 ) - state.mnState |= MOUSE_MIDDLE; // tertiary button - - // fill in modifier state - nState = GetCurrentEventKeyModifiers(); - if( nState & shiftKey ) - state.mnState |= KEY_SHIFT; - if( nState & controlKey ) - state.mnState |= KEY_MOD3; - if( nState & optionKey ) - state.mnState |= KEY_MOD2; - if( nState & cmdKey ) - state.mnState |= KEY_MOD1; return state; } -- cgit From 903bfc6a7230cf30262c52c6cf6b649dbac8f996 Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Wed, 31 Mar 2010 14:10:23 +0200 Subject: vcl111: #102694# more hacking for metacity and tool windows --- vcl/unx/gtk/window/gtkframe.cxx | 31 +++++++++++++++++-------------- vcl/unx/inc/plugins/gtk/gtkframe.hxx | 1 + 2 files changed, 18 insertions(+), 14 deletions(-) (limited to 'vcl') diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx index ba42cfc5ae82..bc4bc420a2eb 100644 --- a/vcl/unx/gtk/window/gtkframe.cxx +++ b/vcl/unx/gtk/window/gtkframe.cxx @@ -566,6 +566,7 @@ void GtkSalFrame::InitCommon() m_nExtStyle = 0; m_pRegion = NULL; m_ePointerStyle = 0xffff; + m_bSetFocusOnMap = false; gtk_widget_set_app_paintable( m_pWindow, TRUE ); gtk_widget_set_double_buffered( m_pWindow, FALSE ); @@ -803,11 +804,6 @@ void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle ) ( ! (nStyle & SAL_FRAME_STYLE_FLOAT) || (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) ); - /* #i100116# metacity has a peculiar behavior regarding WM_HINT accept focus and _NET_WM_USER_TIME - at some point that may be fixed in metacity and we will have to revisit this - */ - bool bMetaCityToolWindowHack = getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") && - (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ); if( bDecoHandling ) { bool bNoDecor = ! (nStyle & (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE ) ); @@ -823,8 +819,6 @@ void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle ) { eType = GDK_WINDOW_TYPE_HINT_UTILITY; gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true ); - if( bMetaCityToolWindowHack ) - lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true ); } else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) { @@ -874,7 +868,7 @@ void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle ) if( bDecoHandling ) { gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) ? TRUE : FALSE ); - if( ( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) ) || bMetaCityToolWindowHack ) + if( ( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) ) ) lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, false ); } @@ -1357,9 +1351,9 @@ void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate ) // // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused. // awesome. + bool bMetaCity = getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity"); if( nUserTime == 0 && - ( - getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") || + ( bMetaCity || ( getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz") && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) @@ -1371,9 +1365,11 @@ void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate ) nUserTime= getDisplay()->GetLastUserEventTime( true ); //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window); } - lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime ); + if( bMetaCity && ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) ) + m_bSetFocusOnMap = true; + gtk_widget_show( m_pWindow ); if( isFloatGrabWindow() ) @@ -2834,6 +2830,8 @@ gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame ) GTK_YIELD_GRAB(); + bool bSetFocus = pThis->m_bSetFocusOnMap; + pThis->m_bSetFocusOnMap = false; if( ImplGetSVData()->mbIsTestTool ) { /* #i76541# testtool needs the focus to be in a new document @@ -2843,9 +2841,14 @@ gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame ) * so this is done when running in testtool only */ if( ! pThis->m_pParent && (pThis->m_nStyle & SAL_FRAME_STYLE_MOVEABLE) != 0 ) - XSetInputFocus( pThis->getDisplay()->GetDisplay(), - GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window), - RevertToParent, CurrentTime ); + bSetFocus = true; + } + + if( bSetFocus ) + { + XSetInputFocus( pThis->getDisplay()->GetDisplay(), + GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window), + RevertToParent, CurrentTime ); } pThis->CallCallback( SALEVENT_RESIZE, NULL ); diff --git a/vcl/unx/inc/plugins/gtk/gtkframe.hxx b/vcl/unx/inc/plugins/gtk/gtkframe.hxx index 0a91d99fd839..88a26b401eed 100644 --- a/vcl/unx/inc/plugins/gtk/gtkframe.hxx +++ b/vcl/unx/inc/plugins/gtk/gtkframe.hxx @@ -185,6 +185,7 @@ class GtkSalFrame : public SalFrame bool m_bDefaultSize; bool m_bSendModChangeOnRelease; bool m_bWindowIsGtkPlug; + bool m_bSetFocusOnMap; String m_aTitle; IMHandler* m_pIMHandler; -- cgit From a14e90df9620b4e4259d20197660f2dac67628d7 Mon Sep 17 00:00:00 2001 From: sj Date: Fri, 9 Apr 2010 18:04:50 +0200 Subject: impress190: #110673# applied patch (removed some Boundchecker warnings) --- vcl/source/gdi/pngread.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/source/gdi/pngread.cxx b/vcl/source/gdi/pngread.cxx index b7eb8e5f50bf..11971db34378 100644 --- a/vcl/source/gdi/pngread.cxx +++ b/vcl/source/gdi/pngread.cxx @@ -703,7 +703,7 @@ void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth ) nBitDepth = 8; sal_uInt16 nPaletteEntryCount = 1 << nBitDepth; - sal_uInt32 nAdd = 256 / (nPaletteEntryCount - 1); + sal_uInt32 nAdd = nBitDepth ? 256 / (nPaletteEntryCount - 1) : 0; // no bitdepth==2 available // but bitdepth==4 with two unused bits is close enough -- cgit From 20231f17aebf160bb96b81ed31d4c2ed5c83785c Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Mon, 12 Apr 2010 14:55:57 +0200 Subject: #i110806# fix stlport debug assertion (thanks dtardon) --- vcl/source/gdi/sallayout.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vcl') diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index 344867ebb0b0..cacaa1849b65 100755 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -1800,8 +1800,8 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs ) int nRunStart, nRunEnd; while (rArgs.GetNextRun(&nRunStart, &nRunEnd, &bRtl)) { - if (bRtl) std::fill(vRtl.begin() + nRunStart - rArgs.mnMinCharPos, - vRtl.begin() + nRunEnd - rArgs.mnMinCharPos, true); + if (bRtl) std::fill(vRtl.begin() + (nRunStart - rArgs.mnMinCharPos), + vRtl.begin() + (nRunEnd - rArgs.mnMinCharPos), true); } rArgs.ResetPos(); -- cgit From 8b570a04e1bd1f5e2f49f13c4c377dbeb2ca6928 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Wed, 14 Apr 2010 09:28:17 +0200 Subject: #i107915# fix vertical writing for non-BMP CJK chars --- vcl/source/gdi/sallayout.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'vcl') diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index 008a64f615f2..3e4ca9fc3df6 100755 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -133,18 +133,19 @@ int GetVerticalFlags( sal_UCS4 nChar ) /* #i52932# remember: nChar == 0x2010 || nChar == 0x2015 nChar == 0x2016 || nChar == 0x2026 - are GF_NONE also, but already handled in the first if + are GF_NONE also, but already handled in the outer if condition */ if((nChar >= 0x3008 && nChar <= 0x301C && nChar != 0x3012) || (nChar == 0xFF3B || nChar == 0xFF3D) || (nChar >= 0xFF5B && nChar <= 0xFF9F) // halfwidth forms - || (nChar == 0xFFE3) - || (nChar >= 0x02F800 && nChar <= 0x02FFFF) ) + || (nChar == 0xFFE3) ) return GF_NONE; // not rotated else if( nChar == 0x30fc ) return GF_ROTR; // right return GF_ROTL; // left } + else if( (nChar >= 0x02F800 && nChar <= 0x02FFFF) ) // non-BMP CJK ideographs + return GF_NONE; // not rotated return GF_NONE; } -- cgit From 2f030c991f7de0b09dc4dd6210f2b99511b69509 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Wed, 14 Apr 2010 14:45:43 +0200 Subject: #i110240# fix emulation of hflex/hflex1 type2ops for type1 subset --- vcl/source/fontsubset/cff.cxx | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'vcl') diff --git a/vcl/source/fontsubset/cff.cxx b/vcl/source/fontsubset/cff.cxx index 9884e7016fee..d3cbd7e7bfbf 100644 --- a/vcl/source/fontsubset/cff.cxx +++ b/vcl/source/fontsubset/cff.cxx @@ -468,7 +468,7 @@ public: // TODO: is public really needed? private: // typeop exceution context int mnStackIdx; - ValType mnValStack[ NMAXSTACK]; + ValType mnValStack[ NMAXSTACK+4]; ValType mnTransVals[ NMAXTRANS]; int mnHintSize; @@ -1241,16 +1241,33 @@ void CffSubsetterContext::convertOneTypeEsc( void) break; } case TYPE2OP::HFLEX1: { - assert( mnStackIdx == 9 ); - writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, -6 ); - writeCurveTo( mnStackIdx, -4, -6, -3, -2, -1, -8 ); + assert( mnStackIdx == 9); +#if 0 // emulate hflex1 as straight line + const ValType* pX = &mnValStack[ mnStackIdx]; + const ValType fDX = pX[-9] + pX[-7] + pX[-5] + pX[-4] + pX[-3] + pX[-1]; + writeType1Val( fDX); + writeTypeOp( TYPE1OP::HLINETO); +#else // emulate hflex1 as two curves + writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, 0); + writeCurveTo( mnStackIdx, -4, 0, -3, -2, -1, 0); + // TODO: emulate hflex1 using othersubr call +#endif mnStackIdx -= 9; } break; case TYPE2OP::HFLEX: { - assert( mnStackIdx == 7 ); - writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, -5 ); - writeCurveTo( mnStackIdx, -3, -5, -2, 0, -1, 0 ); + assert( mnStackIdx == 7); + ValType* pX = &mnValStack[ mnStackIdx]; +#if 0 // emulate hflex as straight line + const ValType fDX = pX[-7] + pX[-6] + pX[-4] + pX[-3] + pX[-2] + pX[-1]; + writeType1Val( fDX); + writeTypeOp( TYPE1OP::HLINETO); +#else // emulate hflex as two curves + pX[+1] = -pX[-5]; // temp: +dy5==-dy2 + writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, 0); + writeCurveTo( mnStackIdx, -3, 0, -2, +1, -1, 0); + // TODO: emulate hflex using othersubr call +#endif mnStackIdx -= 7; } break; -- cgit From a075cefbec52ef6b02cd631e8a5b1319aadd3e03 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Fri, 16 Apr 2010 14:11:19 +0200 Subject: #i108743# fix psp\'s getGlyphWidths() for non-type1 fonts --- vcl/unx/source/fontmanager/fontmanager.cxx | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'vcl') diff --git a/vcl/unx/source/fontmanager/fontmanager.cxx b/vcl/unx/source/fontmanager/fontmanager.cxx index 93e3eef53ab3..606a57071d64 100644 --- a/vcl/unx/source/fontmanager/fontmanager.cxx +++ b/vcl/unx/source/fontmanager/fontmanager.cxx @@ -40,6 +40,7 @@ #include "vcl/fontcache.hxx" #include "vcl/fontcache.hxx" #include "vcl/fontsubset.hxx" +#include "vcl/impfont.hxx" #include "vcl/strhelper.hxx" #include "vcl/ppdparser.hxx" #include "vcl/svdata.hxx" @@ -3795,6 +3796,35 @@ void PrintFontManager::getGlyphWidths( fontID nFont, free( pMetrics ); rUnicodeEnc.clear(); } + + // fill the unicode map + // TODO: isn't this map already available elsewhere in the fontmanager? + const sal_uInt8* pCmapData = NULL; + int nCmapSize = 0; + if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) ) + { + CmapResult aCmapResult; + if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) ) + { + const ImplFontCharMap aCharMap( aCmapResult ); + for( sal_uInt32 cOld = 0;;) + { + // get next unicode covered by font + const sal_uInt32 c = aCharMap.GetNextChar( cOld ); + if( c == cOld ) + break; + cOld = c; +#if (sizeof(sal_Unicode) <= 2) // TODO: remove when sal_Unicode covers all of unicode + if( c > 0xFFFF ) + break; +#endif + // get the matching glyph index + const sal_uInt32 nGlyphId = aCharMap.GetGlyphIndex( c ); + // update the requested map + rUnicodeEnc[ (sal_Unicode)c ] = nGlyphId; + } + } + } } CloseTTFont( pTTFont ); } -- cgit From fac60d2f0b6938e768a0c662f34a5f67028eaa93 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 20 Apr 2010 15:42:54 +0200 Subject: #i107360# moved trapezoid tesselation into basegfx --- vcl/unx/inc/salgdi.h | 13 +- vcl/unx/source/gdi/salgdi.cxx | 778 +++++------------------------------------- 2 files changed, 88 insertions(+), 703 deletions(-) (limited to 'vcl') diff --git a/vcl/unx/inc/salgdi.h b/vcl/unx/inc/salgdi.h index da69f04b6f8f..6ccea2c4a00c 100644 --- a/vcl/unx/inc/salgdi.h +++ b/vcl/unx/inc/salgdi.h @@ -57,6 +57,10 @@ class ImplLayoutArgs; class X11FontLayout; class ServerFontLayout; +namespace basegfx { + class B2DTrapezoid; +} + // -=-= SalGraphicsData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= class CairoFontsCache @@ -289,8 +293,11 @@ public: virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ); - virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency ); - virtual bool drawPolyLine( const ::basegfx::B2DPolygon& rPolygon, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin); + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ); + virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin ); + virtual bool drawFilledTrapezoids( const ::basegfx::B2DTrapezoid*, int nTrapCount, double fTransparency ); + +#if 1 // TODO: remove these obselete methods virtual sal_Bool drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ); @@ -301,6 +308,8 @@ public: const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ); +#endif + virtual void copyArea( long nDestX, long nDestY, long nSrcX, diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx index 7637d3b2bd02..32aeed2dbc95 100644 --- a/vcl/unx/source/gdi/salgdi.cxx +++ b/vcl/unx/source/gdi/salgdi.cxx @@ -50,8 +50,9 @@ #include "basegfx/polygon/b2dpolygonclipper.hxx" #include "basegfx/polygon/b2dlinegeometry.hxx" #include "basegfx/matrix/b2dhommatrix.hxx" -#include +#include "basegfx/matrix/b2dhommatrixtools.hxx" #include "basegfx/polygon/b2dpolypolygoncutter.hxx" +#include "basegfx/polygon/b2dtrapezoid.hxx" #include #include @@ -1087,115 +1088,6 @@ SystemGraphicsData X11SalGraphics::GetGraphicsData() const // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -// B2DPolygon support methods - -namespace { // anonymous namespace to prevent export -// the methods and structures here are used by the -// B2DPolyPolygon->RenderTrapezoid conversion algorithm - -// compare two line segments -// assumption: both segments point downward -// assumption: they must have at least some y-overlap -// assumption: rA.p1.y <= rB.p1.y -bool IsLeftOf( const XLineFixed& rA, const XLineFixed& rB ) -{ - bool bAbove = (rA.p1.y <= rB.p1.y); - const XLineFixed& rU = bAbove ? rA : rB; - const XLineFixed& rL = bAbove ? rB : rA; - - const XFixed aXDiff = rU.p2.x - rU.p1.x; - const XFixed aYDiff = rU.p2.y - rU.p1.y; - - // compare upper point of lower segment with line through upper segment - if( (rU.p1.y != rL.p1.y) || (rU.p1.x != rL.p1.x) ) - { - const sal_Int64 n1 = (sal_Int64)aXDiff * (rL.p1.y - rU.p1.y); - const sal_Int64 n2 = (sal_Int64)aYDiff * (rL.p1.x - rU.p1.x); - if( n1 != n2 ) - return ((n1 < n2) == bAbove); - } - - // compare lower point of lower segment with line through upper segment - if( (rU.p2.y != rL.p2.y) || (rU.p2.x != rL.p2.x) ) - { - const sal_Int64 n3 = (sal_Int64)aXDiff * (rL.p2.y - rU.p1.y); - const sal_Int64 n4 = (sal_Int64)aYDiff * (rL.p2.x - rU.p1.x); - if( n3 != n4 ) - return ((n3 < n4) == bAbove); - } - - // both segments overlap - return false; -} - -struct HalfTrapezoid -{ - // assumptions: - // maLine.p1.y <= mnY < maLine.p2.y - XLineFixed maLine; - XFixed mnY; - - XFixed getXMin() const { return std::min( maLine.p1.x, maLine.p2.x); } - XFixed getXMax() const { return std::max( maLine.p1.x, maLine.p2.x); } -}; - -class HalfTrapCompare -{ -public: - bool operator()( const HalfTrapezoid& rA, const HalfTrapezoid& rB ) const - { - bool bIsTopLeft = false; - if( rA.mnY != rB.mnY ) // sort top-first if possible - bIsTopLeft = (rA.mnY < rB.mnY); - else // else sort left-first - bIsTopLeft = IsLeftOf( rA.maLine, rB.maLine ); - // adjust to priority_queue sorting convention - return !bIsTopLeft; - } -}; - -typedef std::vector< HalfTrapezoid > HTVector; -typedef std::priority_queue< HalfTrapezoid, HTVector, HalfTrapCompare > HTQueueBase; -// we need a priority queue with a reserve() to prevent countless reallocations -class HTQueue -: public HTQueueBase -{ -public: - void reserve( size_t n ) { c.reserve( n ); } - void swapvec( HTVector& v ) { c.swap( v ); } -}; - -typedef std::vector TrapezoidVector; - -class TrapezoidXCompare -{ - const TrapezoidVector& mrVector; -public: - TrapezoidXCompare( const TrapezoidVector& rVector ) - : mrVector( rVector ) {} - bool operator()( int nA, int nB ) const - { return IsLeftOf( mrVector[nA].left, mrVector[nB].left ); } -}; - -typedef std::multiset< int, TrapezoidXCompare > ActiveTrapSet; - -class TrapezoidYCompare -{ - const TrapezoidVector& mrVector; -public: - TrapezoidYCompare( const TrapezoidVector& rVector ) - : mrVector( rVector ) {} - bool operator()( int nA, int nB ) const - { return (mrVector[nA].bottom < mrVector[nB].bottom); } -}; - -typedef std::multiset< int, TrapezoidYCompare > VerticalTrapSet; - -#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND -void splitIntersectingSegments( HTVector&); -#endif // DISABLE_SOLVECROSSOVER_WORKAROUND -} // end of anonymous namespace - // draw a poly-polygon bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency) { @@ -1219,329 +1111,66 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly if( pRenderEnv ) return FALSE; - // check xrender support for trapezoids - XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); - if( !rRenderPeer.AreTrapezoidsSupported() ) - return FALSE; - Picture aDstPic = GetXRenderPicture(); - // check xrender support for this drawable - if( !aDstPic ) - return FALSE; + // snap to raster if requested + basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly; + const bool bSnapToRaster = !getAntiAliasB2DDraw(); + if( bSnapToRaster ) + aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly ); // don't bother with polygons outside of visible area const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() ); - const basegfx::B2DRange aPolyRange = basegfx::tools::getRange( rOrigPolyPoly ); - const bool bNeedViewClip = aPolyRange.isInside( aViewRange ); - if( !aPolyRange.overlaps( aViewRange ) ) + aPolyPoly = basegfx::tools::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false ); + if( !aPolyPoly.count() ) return true; - // convert the polypolygon to trapezoids - - // prepare the polypolygon for the algorithm below: - // - clip it against the view range - // - make sure it contains no self-intersections - // while we are at it guess the number of involved polygon points - int nHTQueueReserve = 0; - basegfx::B2DPolyPolygon aGoodPolyPoly; - for( int nOrigPolyIdx = 0; nOrigPolyIdx < nOrigPolyCount; ++nOrigPolyIdx ) - { - const ::basegfx::B2DPolygon aOuterPolygon = rOrigPolyPoly.getB2DPolygon( nOrigPolyIdx ); - - // render-trapezoids should be inside the view => clip polygon against view range - basegfx::B2DPolyPolygon aClippedPolygon( aOuterPolygon ); - if( bNeedViewClip ) - { - aClippedPolygon = basegfx::tools::clipPolygonOnRange( aOuterPolygon, aViewRange, true, false ); - DBG_ASSERT( aClippedPolygon.count(), "polygon confirmed to overlap with view should not get here" ); - } - const int nClippedPolyCount = aClippedPolygon.count(); - if( !nClippedPolyCount ) - continue; - -#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND - for( int nClippedPolyIdx = 0; nClippedPolyIdx < nClippedPolyCount; ++nClippedPolyIdx ) - { - const ::basegfx::B2DPolygon aSolvedPolygon = aClippedPolygon.getB2DPolygon( nClippedPolyIdx ); - const int nPointCount = aSolvedPolygon.count(); - aGoodPolyPoly.append( aSolvedPolygon ); - nHTQueueReserve += aSolvedPolygon.areControlPointsUsed() ? 8 * nPointCount : nPointCount; - } -#else // DISABLE_SOLVECROSSOVER_WORKAROUND - // #i103259# polypoly.solveCrossover() fails to remove self-intersections - // but polygon.solveCrossover() works. Use it to build the intersection-free polypolygon - // TODO: if the self-intersection prevention is too expensive make the trap-algorithm tolerate intersections - for( int nClippedPolyIdx = 0; nClippedPolyIdx < nClippedPolyCount; ++nClippedPolyIdx ) - { - ::basegfx::B2DPolygon aUnsolvedPolygon = aClippedPolygon.getB2DPolygon( nClippedPolyIdx ); - basegfx::B2DPolyPolygon aSolvedPolyPoly( basegfx::tools::solveCrossovers( aUnsolvedPolygon) ); - const int nSolvedPolyCount = aSolvedPolyPoly.count(); - for( int nSolvedPolyIdx = 0; nSolvedPolyIdx < nSolvedPolyCount; ++nSolvedPolyIdx ) - { - // build the intersection-free polypolygon one by one - const ::basegfx::B2DPolygon aSolvedPolygon = aSolvedPolyPoly.getB2DPolygon( nSolvedPolyIdx ); - aGoodPolyPoly.append( aSolvedPolygon ); - // and while we are at it use the conviently available point count to guess the number of needed half-traps - const int nPointCount = aSolvedPolygon.count(); - nHTQueueReserve += aSolvedPolygon.areControlPointsUsed() ? 8 * nPointCount : nPointCount; - } - } -#endif // DISABLE_SOLVECROSSOVER_WORKAROUND - } - // #i100922# try to prevent priority-queue reallocations by reservering enough - nHTQueueReserve = ((4*nHTQueueReserve) | 0x1FFF) + 1; - HTVector aHTVector; - aHTVector.reserve( nHTQueueReserve ); - - // first convert the B2DPolyPolygon to HalfTrapezoids - const int nGoodPolyCount = aGoodPolyPoly.count(); - for( int nGoodPolyIdx = 0; nGoodPolyIdx < nGoodPolyCount; ++nGoodPolyIdx ) - { - ::basegfx::B2DPolygon aInnerPolygon = aGoodPolyPoly.getB2DPolygon( nGoodPolyIdx ); - - // render-trapezoids have linear edges => get rid of bezier segments - if( aInnerPolygon.areControlPointsUsed() ) - aInnerPolygon = ::basegfx::tools::adaptiveSubdivideByDistance( aInnerPolygon, 0.125 ); - - const int nPointCount = aInnerPolygon.count(); - if( nPointCount >= 3 ) - { - // convert polygon point pairs to HalfTrapezoids - // connect the polygon point with the first one if needed - XPointFixed aOldXPF = { 0, 0 }; - XPointFixed aNewXPF; - for( int nPointIdx = 0; nPointIdx <= nPointCount; ++nPointIdx, aOldXPF = aNewXPF ) - { - // auto-close the polygon if needed - const int k = (nPointIdx < nPointCount) ? nPointIdx : 0; - const ::basegfx::B2DPoint& aPoint = aInnerPolygon.getB2DPoint( k ); - - // convert the B2DPoint into XRENDER units - if(getAntiAliasB2DDraw()) - { - aNewXPF.x = XDoubleToFixed( aPoint.getX() ); - aNewXPF.y = XDoubleToFixed( aPoint.getY() ); - } - else - { - aNewXPF.x = XDoubleToFixed( basegfx::fround( aPoint.getX() ) ); - aNewXPF.y = XDoubleToFixed( basegfx::fround( aPoint.getY() ) ); - } - - // check if enough data is available for a new HalfTrapezoid - if( nPointIdx == 0 ) - continue; - - // construct HalfTrapezoid as topdown segment - HalfTrapezoid aHT; - if( aNewXPF.y < aOldXPF.y ) - { - aHT.maLine.p1 = aNewXPF; - aHT.maLine.p2 = aOldXPF; - } - else - { - aHT.maLine.p2 = aNewXPF; - aHT.maLine.p1 = aOldXPF; - } - - aHT.mnY = aHT.maLine.p1.y; + // tesselate the polypolygon into trapezoids + basegfx::B2DTrapezoidVector aB2DTrapVector; + basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aPolyPoly ); + const int nTrapCount = aB2DTrapVector.size(); + const bool bDrawn = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency ); + return bDrawn; +} -#if 0 // ignore clipped HalfTrapezoids - if( aHT.mnY < 0 ) - aHT.mnY = 0; - else if( aHT.mnY > 10000 ) - continue; -#endif +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - // queue up the HalfTrapezoid - aHTVector.push_back( aHT ); - } - } - } +bool X11SalGraphics::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency ) +{ + if( nTrapCount <= 0 ) + return true; - if( aHTVector.empty() ) - return TRUE; + Picture aDstPic = GetXRenderPicture(); + // check xrender support for this drawable + if( !aDstPic ) + return false; -#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND - // find intersecting halftraps and split them up - // TODO: remove when solveCrossOvers gets fast enough so its use can be enabled above - // FAQ: why should segment intersection be handled before adaptiveSubdivide()? - // Answer: because it is conceptually much faster - // Example: consider two intersecting circles with a diameter of 1000 pixels - // before subdivision: eight bezier segments - // after subdivision: more than a thousand line segments - // since even the best generic intersection finders have a complexity of O((n+k)*log(n+k)) - // it shows that testing while the segment count is still low is a much better approach. - splitIntersectingSegments( aHTVector); -#endif // DISABLE_SOLVECROSSOVER_WORKAROUND - - // build queue from vector of intersection-free segments - // TODO: is replacing the priority-queue by a sorted vector worth it? - std::make_heap( aHTVector.begin(), aHTVector.end(), HalfTrapCompare()); - HTQueue aHTQueue; - aHTQueue.swapvec( aHTVector); - - // then convert the HalfTrapezoids into full Trapezoids - TrapezoidVector aTrapVector; - aTrapVector.reserve( aHTQueue.size() * 2 ); // just a guess - - TrapezoidXCompare aTrapXCompare( aTrapVector ); - ActiveTrapSet aActiveTraps( aTrapXCompare ); - - TrapezoidYCompare aTrapYCompare( aTrapVector ); - VerticalTrapSet aVerticalTraps( aTrapYCompare ); - - while( !aHTQueue.empty() ) + // convert the B2DTrapezoids into XRender-Trapezoids + typedef std::vector TrapezoidVector; + TrapezoidVector aTrapVector( nTrapCount ); + const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps; + for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i ) { - XTrapezoid aTrapezoid; - - // convert a HalfTrapezoid pair - // get the left side of the trapezoid - const HalfTrapezoid& rLeft = aHTQueue.top(); - aTrapezoid.top = rLeft.mnY; - aTrapezoid.left = rLeft.maLine; - aHTQueue.pop(); - - // ignore left segment that would result in an empty trapezoid - if( aTrapezoid.left.p2.y <= aTrapezoid.top ) - continue; - - // get the right side of the trapezoid - aTrapezoid.right.p2.y = aTrapezoid.bottom; - while( !aHTQueue.empty() ) { - const HalfTrapezoid& rRight = aHTQueue.top(); - aTrapezoid.right = rRight.maLine; - aHTQueue.pop(); - // ignore right segment that would result in an empty trapezoid - if( aTrapezoid.right.p2.y > aTrapezoid.top ) - break; - } - - // the topmost endpoint determines the trapezoid bottom - aTrapezoid.bottom = aTrapezoid.left.p2.y; - if( aTrapezoid.bottom > aTrapezoid.right.p2.y ) - aTrapezoid.bottom = aTrapezoid.right.p2.y; - - // keep the full Trapezoid candidate - aTrapVector.push_back( aTrapezoid ); - - // unless it splits another trapezoid that is still active - bool bSplit = false; - ActiveTrapSet::iterator aActiveTrapsIt = aActiveTraps.begin(); - while(aActiveTrapsIt != aActiveTraps.end()) - { - XTrapezoid& rLeftTrap = aTrapVector[ *aActiveTrapsIt ]; - - // skip until first overlap candidate - // TODO: use stl::*er_bound() instead - if( IsLeftOf( aTrapezoid.left, rLeftTrap.left) ) - { - ++aActiveTrapsIt; - continue; - } - - // in the ActiveTrapSet there are still trapezoids where - // a vertical overlap with new trapezoids is no longer possible - // they could have been removed in the verticaltraps loop below - // but this would be expensive and is not needed as we can - // simply ignore them until we stumble upon them here. - if( rLeftTrap.bottom <= aTrapezoid.top ) - { - ActiveTrapSet::iterator it = aActiveTrapsIt; - if( aActiveTrapsIt != aActiveTraps.begin() ) - { - --aActiveTrapsIt; - aActiveTraps.erase( it ); - ++aActiveTrapsIt; - } - else - { - aActiveTraps.erase( it ); - aActiveTrapsIt = aActiveTraps.begin(); - } - continue; - } - - // check if there is horizontal overlap - // aTrapezoid.left==rLeftTrap.right is allowed though - if( !IsLeftOf( aTrapezoid.left, rLeftTrap.right ) ) - { - ++aActiveTrapsIt; - continue; - } - - // prepare to split the old trapezoid and keep its upper part - // find the old trapezoids entry in the VerticalTrapSet and remove it - typedef std::pair VTSPair; - VTSPair aVTSPair = aVerticalTraps.equal_range( *aActiveTrapsIt ); - VerticalTrapSet::iterator aVTSit = aVTSPair.first; - for(; aVTSit != aVTSPair.second; ++aVTSit ) - { - if( *aVTSit != *aActiveTrapsIt ) - continue; - aVerticalTraps.erase( aVTSit ); - break; - } - // then update the old trapezoid's bottom - rLeftTrap.bottom = aTrapezoid.top; - // enter the updated old trapzoid in VerticalTrapSet - aVerticalTraps.insert( aVerticalTraps.begin(), *aActiveTrapsIt ); - // the old trapezoid is no longer active - aActiveTraps.erase( aActiveTrapsIt ); - - // the trapezoid causing the split has become obsolete - // so its both sides have to be re-queued - HalfTrapezoid aHT; - aHT.mnY = aTrapezoid.top; - aHT.maLine = aTrapezoid.left; - aHTQueue.push( aHT ); - aHT.maLine = aTrapezoid.right; - aHTQueue.push( aHT ); - - bSplit = true; - break; - } - - // keep or forget the resulting full Trapezoid - if( bSplit ) - aTrapVector.pop_back(); - else - { - aActiveTraps.insert( aTrapVector.size()-1 ); - aVerticalTraps.insert( aTrapVector.size()-1 ); - } - - // mark trapezoids that can no longer be split as inactive - // and recycle their sides which were not fully resolved - static const XFixed nMaxTop = +0x7FFFFFFF; - const XFixed nNewTop = aHTQueue.empty() ? nMaxTop : aHTQueue.top().mnY; - while( !aVerticalTraps.empty() ) - { - // check the next trapezoid to be retired - const XTrapezoid& rOldTrap = aTrapVector[ *aVerticalTraps.begin() ]; - if( nNewTop < rOldTrap.bottom ) - break; - // this trapezoid can no longer be split - aVerticalTraps.erase( aVerticalTraps.begin() ); - - // recycle its sides that were not fully resolved - HalfTrapezoid aHT; - aHT.mnY = rOldTrap.bottom; - - if( rOldTrap.left.p2.y > aHT.mnY ) - { - aHT.maLine = rOldTrap.left; - aHTQueue.push( aHT ); - } - if( rOldTrap.right.p2.y > aHT.mnY ) - { - aHT.maLine = rOldTrap.right; - aHTQueue.push( aHT ); - } - } + XTrapezoid& rTrap = aTrapVector[ i ] ; + + // set y-coordinates + const double fY1 = pB2DTrap->getTopY(); + rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 ); + const double fY2 = pB2DTrap->getBottomY(); + rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 ); + + // set x-coordinates + const double fXL1 = pB2DTrap->getTopXLeft(); + rTrap.left.p1.x = XDoubleToFixed( fXL1 ); + const double fXR1 = pB2DTrap->getTopXRight(); + rTrap.right.p1.x = XDoubleToFixed( fXR1 ); + const double fXL2 = pB2DTrap->getBottomXLeft(); + rTrap.left.p2.x = XDoubleToFixed( fXL2 ); + const double fXR2 = pB2DTrap->getBottomXRight(); + rTrap.right.p2.x = XDoubleToFixed( fXR2 ); } - // create xrender Picture for polygon foreground + // get xrender Picture for polygon foreground + // TODO: cache it like the target picture which uses GetXRenderPicture() + XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ 32 ]; if( !rEntry.m_aPicture ) { @@ -1569,15 +1198,17 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly rRenderPeer.CompositeTrapezoids( PictOpOver, rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() ); - return TRUE; + return true; } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin) { + const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2); + // #i101491# - if(rPolygon.count() > 1000) + if( !bIsHairline && (rPolygon.count() > 1000) ) { // the used basegfx::tools::createAreaGeometry is simply too // expensive with very big polygons; fallback to caller (who @@ -1587,9 +1218,28 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : // the same way. return false; } - const XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); - if( !rRenderPeer.AreTrapezoidsSupported() ) - return false; + + // temporarily adjust brush color to pen color + // since the line is drawn as an area-polygon + const SalColor aKeepBrushColor = nBrushColor_; + nBrushColor_ = nPenColor_; + + // shortcut for hairline drawing to improve performance + if( bIsHairline ) + { + // hairlines can benefit from a simplified tesselation + // e.g. for hairlines the linejoin style can be ignored + basegfx::B2DTrapezoidVector aB2DTrapVector; + basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, rPolygon, rLineWidth.getX() ); + + // draw tesselation result + const int nTrapCount = aB2DTrapVector.size(); + const bool bDrawOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, 0.0 ); + + // restore the original brush GC + nBrushColor_ = aKeepBrushColor; + return bDrawOk; + } // get the area polygon for the line polygon basegfx::B2DPolygon aPolygon = rPolygon; @@ -1600,18 +1250,6 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY())); } - // special handling for hairlines to improve the drawing performance - // TODO: revisit after basegfx performance related changes - const bool bIsHairline = (rLineWidth.getX() < 1.2) && (rLineWidth.getY() < 1.2); - if( bIsHairline ) - { - // for hairlines the linejoin style becomes irrelevant - eLineJoin = basegfx::B2DLINEJOIN_NONE; - // createAreaGeometry is still too expensive when beziers are involved - if( aPolygon.areControlPointsUsed() ) - aPolygon = ::basegfx::tools::adaptiveSubdivideByDistance( aPolygon, 0.125 ); - } - // create the area-polygon for the line const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, 0.5*rLineWidth.getX(), eLineJoin) ); @@ -1622,11 +1260,6 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX())); } - // temporarily adjust brush color to pen color - // since the line is drawn as an area-polygon - const SalColor aKeepBrushColor = nBrushColor_; - nBrushColor_ = nPenColor_; - // draw each area polypolygon component individually // to emulate the polypolygon winding rule "non-zero" bool bDrawOk = true; @@ -1634,7 +1267,7 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) { const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) ); - bDrawOk = drawPolyPolygon( aOnePoly, 0.0); + bDrawOk = drawPolyPolygon( aOnePoly, 0.0 ); if( !bDrawOk ) break; } @@ -1645,260 +1278,3 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND -// TODO: move the intersection solver into basegfx -// and then support bezier-intersection finding too - -namespace { // anonymous namespace to prevent export - -typedef HalfTrapezoid LineSeg; -typedef HTVector LSVector; - -inline bool operator==( const LineSeg& r1, const LineSeg& r2) -{ - if( r1.maLine.p2.y != r2.maLine.p2.y) return false; - if( r1.maLine.p2.x != r2.maLine.p2.x) return false; - if( r1.maLine.p1.y != r2.maLine.p1.y) return false; - if( r1.maLine.p1.x != r2.maLine.p1.x) return false; - return true; -} - -struct LSYMinCmp -{ - bool operator()( const LineSeg& r1, const LineSeg& r2) const - { return r2.maLine.p1.y < r1.maLine.p1.y; } -}; - -struct LSYMaxCmp -{ - bool operator()( const LineSeg& r1, const LineSeg& r2) const - { return r2.maLine.p2.y < r1.maLine.p2.y; } -}; - -struct LSXMinCmp -{ - bool operator()( const LineSeg& r1, const LineSeg& r2) const - { return( r1.getXMin() < r2.getXMin()); } -}; - -struct CutPoint -{ - XFixed mnSegmentId; - float mfCutParam; - XPointFixed maPoint; -}; - -struct CutPointCmp -{ - bool operator()( const CutPoint& r1, const CutPoint& r2) const - { - if( r1.mnSegmentId != r2.mnSegmentId) - return (r1.mnSegmentId < r2.mnSegmentId); - return (r1.mfCutParam < r2.mfCutParam); - } -}; - -bool findIntersection( const LineSeg& rLS1, const LineSeg& rLS2, CutPoint aCutPoints[2]) -{ - // segments intersect at r1.p1 + s*(r1.p2-r1.p1) == r2.p1 + t*(r2.p2-r2.p1) - // when both segment-parameters are ((0 - // (r1.p1x - r2.p1x) == s * (r1.p1x - r1.p2x) + t * (r2.p2x - r2.p1x) - // (r1.p1y - r2.p1y) == s * (r1.p1y - r1.p2y) + t * (r2.p2y - r2.p1y) - // check if lines are identical or parallel => not intersecting - const XLineFixed& r1 = rLS1.maLine; - const XLineFixed& r2 = rLS2.maLine; - const double fDet = (double)(r1.p1.x - r1.p2.x) * (r2.p2.y - r2.p1.y) - - (double)(r2.p2.x - r2.p1.x) * (r1.p1.y - r1.p2.y); - static const double fEps = 1e-8; - if( fabs(fDet) < fEps) - return false; - // check if intersecting with first segment - const double fS1 = (double)(r2.p2.y - r2.p1.y) * (r1.p1.x - r2.p1.x); - const double fS2 = (double)(r2.p2.x - r2.p1.x) * (r2.p1.y - r1.p1.y); - const double fS = (fS1 + fS2) / fDet; - if( (fS <= +fEps) || (fS >= 1-fEps)) - return false; - // check if intersecting with second segment - const double fT1 = (double)(r1.p2.y - r1.p1.y) * (r1.p1.x - r2.p1.x); - const double fT2 = (double)(r1.p2.x - r1.p1.x) * (r2.p1.y - r1.p1.y); - const double fT = (fT1 + fT2) / fDet; - if( (fT <= +fEps) || (fT >= 1-fEps)) - return false; - // force the intersection point to be exactly identical on both segments - aCutPoints[0].maPoint.x = (XFixed)(r1.p1.x + fS * (r1.p2.x - r1.p1.x)); - aCutPoints[0].maPoint.y = (XFixed)(r1.p1.y + fS * (r1.p2.y - r1.p1.y)); - aCutPoints[1].maPoint.x = aCutPoints[0].maPoint.x; - aCutPoints[1].maPoint.y = aCutPoints[0].maPoint.y; - aCutPoints[0].mnSegmentId = rLS1.mnY; - aCutPoints[0].mfCutParam = (float)fS; - aCutPoints[1].mnSegmentId = rLS2.mnY; - aCutPoints[1].mfCutParam = (float)fT; - return true; -} - -typedef std::priority_queue< LineSeg, LSVector, LSYMinCmp> LSYMinQueueBase; -typedef std::priority_queue< LineSeg, LSVector, LSYMaxCmp> LSYMaxQueueBase; -typedef std::multiset< LineSeg, LSXMinCmp> LSXMinSet; -typedef std::set< CutPoint, CutPointCmp> CutPointSet; - -class LSYMinQueue : public LSYMinQueueBase -{ -public: - void reserve( size_t n) { c.reserve(n);} - void swapvec( LSVector& v) { c.swap(v);} -}; - -class LSYMaxQueue : public LSYMaxQueueBase -{ -public: - void reserve( size_t n) { c.reserve(n);} -}; - -void addAndCutSegment( LSVector& rLSVector, const LineSeg& rLS, CutPointSet& rCutPointSet) -{ - // short circuit when no segment was cut - if( rCutPointSet.empty()) { - rLSVector.push_back( rLS); - return; - } - - // find the first cut point for this segment - LineSeg aCS = rLS; - CutPoint aMinCutPoint; - aMinCutPoint.mnSegmentId = rLS.mnY; - aMinCutPoint.mfCutParam = 0.0; - CutPointSet::iterator itFirst = rCutPointSet.lower_bound( aMinCutPoint); - CutPointSet::iterator it = itFirst; - // iterate through all cut points of this segment - for(; it != rCutPointSet.end(); ++it) { - const CutPoint rCutPoint = (*it); - if( rCutPoint.mnSegmentId != rLS.mnY) - break; - // cut segment at the cutpoint - aCS.maLine.p2 = rCutPoint.maPoint; - rLSVector.push_back( aCS); - // prepare for next segment cut - aCS.maLine.p1 = aCS.maLine.p2; - } - // remove cutparams that will no longer be needed - // TODO: is it worth it or should we just keep the cutparams? - rCutPointSet.erase( itFirst, it); - - // add segment part remaining after last cut - aCS.maLine.p2 = rLS.maLine.p2; - rLSVector.push_back( aCS); -} - -void splitIntersectingSegments( LSVector& rLSVector) -{ - // get a unique id for each lineseg, temporarily abuse the mnY member - LSVector::iterator aLSit = rLSVector.begin(); - for( int i = 0; aLSit != rLSVector.end(); ++aLSit) { - LineSeg& rLS = *aLSit; - rLS.mnY = i++; - } - // get an y-sorted queue from the input vector - LSYMinQueue aYMinQueue; - std::make_heap( rLSVector.begin(), rLSVector.end(), LSYMinCmp()); - aYMinQueue.swapvec( rLSVector); - - // prepare the result vector - // try to avoid reallocations by guessing a reasonable result size - rLSVector.reserve( aYMinQueue.size() * 3/2 ); - - // find all intersections - CutPointSet aCutPointSet; - LSXMinSet aXMinSet; - LSYMaxQueue aYMaxQueue; - aYMaxQueue.reserve( aYMinQueue.size()); - // sweep-down and check all segment-pairs that overlap - while( !aYMinQueue.empty()) { - // get next input-segment - const LineSeg& rLS = aYMinQueue.top(); - // retire obsoleted segments - const XFixed fYCur = rLS.maLine.p1.y; - while( !aYMaxQueue.empty()) { - // check next segment to be retired - const LineSeg& rOS = aYMaxQueue.top(); - if( fYCur < rOS.maLine.p2.y) - break; - // emit resolved segment into result - addAndCutSegment( rLSVector, rOS, aCutPointSet); - // find segment to be retired in xmin-compare-set - LSXMinSet::iterator itR = aXMinSet.lower_bound( rOS); - while( !(*itR == rOS)) ++itR; - // retire segment from xmin-compare-set - aXMinSet.erase( itR); - // this segment is pining for the fjords - aYMaxQueue.pop(); - } - - // iterate over all segments that might overlap - // skip over the leftmost segments that cannot overlap - const XFixed fXMax = rLS.getXMax(); - LSXMinSet::const_iterator itC = aXMinSet.begin(); - for(; itC != aXMinSet.end(); ++itC) - if( (*itC).getXMin() <= fXMax) - break; - // TODO: if the linear search becomes too expensive - // then use an XMaxQueue based approach to replace it - const XFixed fXMin = rLS.getXMin(); - for(; itC != aXMinSet.end(); ++itC) { - const LineSeg& rOS = *itC; - if( fXMin >= rOS.getXMax()) - continue; - if( fXMax < rOS.getXMin()) - break; - CutPoint aCutPoints[2]; - if( !findIntersection( rLS, rOS, aCutPoints)) - continue; - // remember cut parameters - // TODO: std::set seems to use individual allocations - // which results in perf-problems for many entries - // => pre-allocate nodes by using a non-default allocator - aCutPointSet.insert( aCutPoints[0]); - aCutPointSet.insert( aCutPoints[1]); - } - // add segment to xmin-compare-set - // TODO: do we have a good insertion hint? - aXMinSet.insert( /*itC,*/ rLS); - // register segment for retirement - aYMaxQueue.push( rLS); - aYMinQueue.pop(); - } - - // retire the remaining segments - aXMinSet.clear(); - while( !aYMaxQueue.empty()) { - // emit segments and cut them up if needed - const LineSeg& rLS = aYMaxQueue.top(); - addAndCutSegment( rLSVector, rLS, aCutPointSet); - aYMaxQueue.pop(); - } - - // get the segments ready to be consumed by the drawPolygon() caller - aLSit = rLSVector.begin(); - LSVector::iterator aLSit2 = aLSit; - for(; aLSit != rLSVector.end(); ++aLSit) { - LineSeg& rLS = *aLSit; - // restore the segment top member - rLS.mnY = rLS.maLine.p1.y; - // remove horizontal segments for now - // TODO: until the trapezoid converter is adjusted to handle them - if( rLS.maLine.p1.y == rLS.maLine.p2.y ) - continue; - *(aLSit2++) = rLS; - } - if(aLSit2 != aLSit) - rLSVector.resize( aLSit2 - rLSVector.begin() ); -} - -} // end anonymous namespace - -#endif // DISABLE_SOLVECROSSOVER_WORKAROUND - -// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -- cgit From 17c8132ca3e52eada54e861e59f0a805c50fff6e Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 20 Apr 2010 15:53:33 +0200 Subject: #i108743# destructor of ImplFontCharMap becomes public --- vcl/inc/vcl/impfont.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vcl') diff --git a/vcl/inc/vcl/impfont.hxx b/vcl/inc/vcl/impfont.hxx index 6ce9f21500b5..a1104bbf4a86 100644 --- a/vcl/inc/vcl/impfont.hxx +++ b/vcl/inc/vcl/impfont.hxx @@ -177,7 +177,8 @@ class CmapResult; class VCL_DLLPUBLIC ImplFontCharMap { public: - explicit ImplFontCharMap( const CmapResult& ); + explicit ImplFontCharMap( const CmapResult& ); + virtual ~ImplFontCharMap(); static ImplFontCharMap* GetDefaultMap( bool bSymbols=false); @@ -201,7 +202,6 @@ public: int GetGlyphIndex( sal_uInt32 ) const; private: - /*virtual*/ ~ImplFontCharMap(); int ImplFindRangeIndex( sal_uInt32 ) const; // prevent assignment and copy construction -- cgit From 7d1514688c7baafb3b998cde97eabf83ea3ab908 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 20 Apr 2010 16:01:40 +0200 Subject: remove compile warning --- vcl/unx/source/fontmanager/fontmanager.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vcl') diff --git a/vcl/unx/source/fontmanager/fontmanager.cxx b/vcl/unx/source/fontmanager/fontmanager.cxx index 606a57071d64..21183dc567ec 100644 --- a/vcl/unx/source/fontmanager/fontmanager.cxx +++ b/vcl/unx/source/fontmanager/fontmanager.cxx @@ -3814,8 +3814,8 @@ void PrintFontManager::getGlyphWidths( fontID nFont, if( c == cOld ) break; cOld = c; -#if (sizeof(sal_Unicode) <= 2) // TODO: remove when sal_Unicode covers all of unicode - if( c > 0xFFFF ) +#if 1 // TODO: remove when sal_Unicode covers all of unicode + if( c > (sal_Unicode)~0 ) break; #endif // get the matching glyph index -- cgit From 33b27bb6627da60efcd78919c287a521f06c7e2b Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Thu, 22 Apr 2010 17:01:19 +0200 Subject: vcl111: #i108490# condition for error message was to broad --- vcl/source/gdi/pdfwriter_impl.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 6a24775219d9..add53cdfaabf 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -9749,7 +9749,7 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) aLine.append( " ]\n" ); } } - else if( m_bIsPDF_A1 ) + else if( m_bIsPDF_A1 && (bWriteMask || aTransparentColor != Color( COL_TRANSPARENT )) ) m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA ); aLine.append( ">>\n" -- cgit From fbce9358c049499cf0fc142e259493034fc6355c Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Thu, 22 Apr 2010 19:41:52 +0200 Subject: vcl111: #i59974# improve single key commit hack --- vcl/unx/gtk/window/gtkframe.cxx | 17 +++++++++++++---- vcl/unx/inc/plugins/gtk/gtkframe.hxx | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'vcl') diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx index ad694cf5bbc1..8029fb3cd05c 100644 --- a/vcl/unx/gtk/window/gtkframe.cxx +++ b/vcl/unx/gtk/window/gtkframe.cxx @@ -3209,7 +3209,8 @@ GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame ) : m_pFrame(pFrame), m_nPrevKeyPresses( 0 ), m_pIMContext( NULL ), - m_bFocused( true ) + m_bFocused( true ), + m_bPreeditJustChanged( false ) { m_aInputEvent.mpTextAttr = NULL; createIMContext(); @@ -3384,6 +3385,8 @@ bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent ) if( aDel.isDeleted() ) return true; + m_bPreeditJustChanged = false; + if( bResult ) return true; else @@ -3413,6 +3416,8 @@ bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent ) if( aDel.isDeleted() ) return true; + m_bPreeditJustChanged = false; + std::list::iterator iter = m_aPrevKeyPresses.begin(); std::list::iterator iter_end = m_aPrevKeyPresses.end(); while (iter != iter_end) @@ -3476,8 +3481,6 @@ void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* p { GTK_YIELD_GRAB(); - bool bWasPreedit = (pThis->m_aInputEvent.mpTextAttr != 0); - pThis->m_aInputEvent.mnTime = 0; pThis->m_aInputEvent.mpTextAttr = 0; pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 ); @@ -3501,6 +3504,9 @@ void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* p * or because there never was a preedit. */ bool bSingleCommit = false; + bool bWasPreedit = + (pThis->m_aInputEvent.mpTextAttr != 0) || + pThis->m_bPreeditJustChanged; if( ! bWasPreedit && pThis->m_aInputEvent.maText.Len() == 1 && ! pThis->m_aPrevKeyPresses.empty() @@ -3515,7 +3521,6 @@ void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* p bSingleCommit = true; } } - if( ! bSingleCommit ) { pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent); @@ -3563,6 +3568,8 @@ void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_ } } + pThis->m_bPreeditJustChanged = true; + bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL; pThis->m_aInputEvent.mnTime = 0; pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 ); @@ -3646,6 +3653,8 @@ void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_hand GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler; GTK_YIELD_GRAB(); + pThis->m_bPreeditJustChanged = true; + vcl::DeletionListener aDel( pThis->m_pFrame ); pThis->doCallEndExtTextInput(); if( ! aDel.isDeleted() ) diff --git a/vcl/unx/inc/plugins/gtk/gtkframe.hxx b/vcl/unx/inc/plugins/gtk/gtkframe.hxx index 88a26b401eed..18dd476fc2c4 100644 --- a/vcl/unx/inc/plugins/gtk/gtkframe.hxx +++ b/vcl/unx/inc/plugins/gtk/gtkframe.hxx @@ -130,6 +130,7 @@ class GtkSalFrame : public SalFrame int m_nPrevKeyPresses; // avoid using size() GtkIMContext* m_pIMContext; bool m_bFocused; + bool m_bPreeditJustChanged; SalExtTextInputEvent m_aInputEvent; std::vector< USHORT > m_aInputFlags; -- cgit From 96176d231f3737ef4eb96f2e08a5cfd958a12dcb Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Mon, 26 Apr 2010 11:14:03 +0200 Subject: vcl111: #i111106# simplify XIOErrorHandler (thanks cmc) --- vcl/unx/gtk/app/gtkdata.cxx | 3 --- vcl/unx/inc/saldisp.hxx | 1 + vcl/unx/kde/kdedata.cxx | 3 --- vcl/unx/kde4/KDEXLib.cxx | 5 +---- vcl/unx/source/app/saldata.cxx | 6 +++--- 5 files changed, 5 insertions(+), 13 deletions(-) (limited to 'vcl') diff --git a/vcl/unx/gtk/app/gtkdata.cxx b/vcl/unx/gtk/app/gtkdata.cxx index d1e5c5954352..586bedca1066 100644 --- a/vcl/unx/gtk/app/gtkdata.cxx +++ b/vcl/unx/gtk/app/gtkdata.cxx @@ -636,9 +636,6 @@ void GtkXLib::Init() Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp ); - XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); - XSetErrorHandler ( (XErrorHandler)X11SalData::XErrorHdl ); - m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp ); gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay ); diff --git a/vcl/unx/inc/saldisp.hxx b/vcl/unx/inc/saldisp.hxx index e54d6e828911..3734cbec6ef7 100644 --- a/vcl/unx/inc/saldisp.hxx +++ b/vcl/unx/inc/saldisp.hxx @@ -231,6 +231,7 @@ protected: XErrorHandler m_aHandler; }; std::vector< XErrorStackEntry > m_aXErrorHandlerStack; + XIOErrorHandler m_aOrigXIOErrorHandler; public: SalXLib(); virtual ~SalXLib(); diff --git a/vcl/unx/kde/kdedata.cxx b/vcl/unx/kde/kdedata.cxx index 5e2801e47fc6..34b0ff652cde 100644 --- a/vcl/unx/kde/kdedata.cxx +++ b/vcl/unx/kde/kdedata.cxx @@ -182,9 +182,6 @@ void KDEXLib::Init() SalDisplay *pSalDisplay = new SalKDEDisplay( pDisp ); - XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); - XSetErrorHandler ( (XErrorHandler)X11SalData::XErrorHdl ); - pInputMethod->CreateMethod( pDisp ); pInputMethod->AddConnectionWatch( pDisp, (void*)this ); pSalDisplay->SetInputMethod( pInputMethod ); diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx index 2e5b86b79f9c..6a2793b8abe3 100644 --- a/vcl/unx/kde4/KDEXLib.cxx +++ b/vcl/unx/kde4/KDEXLib.cxx @@ -148,9 +148,6 @@ void KDEXLib::Init() ((VCLKDEApplication*)m_pApplication)->disp = pSalDisplay; - XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); - XSetErrorHandler ( (XErrorHandler)X11SalData::XErrorHdl ); - pInputMethod->CreateMethod( pDisp ); pInputMethod->AddConnectionWatch( pDisp, (void*)this ); pSalDisplay->SetInputMethod( pInputMethod ); @@ -175,4 +172,4 @@ void KDEXLib::doStartup() fprintf( stderr, "called KStartupInfo::appStarted()\n" ); #endif } -} \ No newline at end of file +} diff --git a/vcl/unx/source/app/saldata.cxx b/vcl/unx/source/app/saldata.cxx index 4155887a9875..c337dc14a6f8 100644 --- a/vcl/unx/source/app/saldata.cxx +++ b/vcl/unx/source/app/saldata.cxx @@ -352,8 +352,9 @@ SalXLib::SalXLib() nFDs_ = m_pTimeoutFDS[0] + 1; } - PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) ); m_bHaveSystemChildFrames = false; + m_aOrigXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); + PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) ); } SalXLib::~SalXLib() @@ -363,6 +364,7 @@ SalXLib::~SalXLib() close (m_pTimeoutFDS[1]); PopXErrorLevel(); + XSetIOErrorHandler (m_aOrigXIOErrorHandler); } void SalXLib::PushXErrorLevel( bool bIgnore ) @@ -458,8 +460,6 @@ void SalXLib::Init() exit(0); } - XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); - SalDisplay *pSalDisplay = new SalX11Display( pDisp ); pInputMethod->CreateMethod( pDisp ); -- cgit From 5369c4232ac93e99fad3e52604538dba7a5d68f2 Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Mon, 26 Apr 2010 16:36:17 +0200 Subject: vcl111: #i103999# fix problem with moblin theme (thanks tml) --- vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx index de4d55b0230a..cb36b4613707 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -3475,7 +3475,7 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings ) aStyleSet.SetMenuColor( aBackColor ); aStyleSet.SetMenuTextColor( aTextColor ); - aTextColor = getColor( pMenubarStyle->text[GTK_STATE_NORMAL] ); + aTextColor = getColor( pMenubarStyle->fg[GTK_STATE_NORMAL] ); aStyleSet.SetMenuBarTextColor( aTextColor ); #if OSL_DEBUG_LEVEL > 1 -- cgit From 7fa4812d0283a9a4b9f06fc1e6c8dcc80bc62257 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 27 Apr 2010 12:20:11 +0200 Subject: vcl: use language in glyph fallback lookup through fontconfig --- vcl/source/gdi/outdev3.cxx | 1 + vcl/unx/source/gdi/salgdi3.cxx | 2 +- vcl/util/makefile.mk | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx index e13ae6cbe64a..438f81bdc6c1 100644 --- a/vcl/source/gdi/outdev3.cxx +++ b/vcl/source/gdi/outdev3.cxx @@ -579,6 +579,7 @@ Font OutputDevice::GetDefaultFont( USHORT nType, LanguageType eLang, { aFont.SetHeight( nDefaultHeight ); aFont.SetWeight( WEIGHT_NORMAL ); + aFont.SetLanguage( eLang ); if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW ) aFont.SetCharSet( gsl_getSystemTextEncoding() ); diff --git a/vcl/unx/source/gdi/salgdi3.cxx b/vcl/unx/source/gdi/salgdi3.cxx index 7cf2009a3e07..760fb81cf1aa 100644 --- a/vcl/unx/source/gdi/salgdi3.cxx +++ b/vcl/unx/source/gdi/salgdi3.cxx @@ -2025,7 +2025,7 @@ static ImplFontSelectData GetFcSubstitute(const ImplFontSelectData &rFontSelData { ImplFontSelectData aRet(rFontSelData); - const rtl::OString aLangAttrib; //TODO: = MsLangId::convertLanguageToIsoByteString( rFontSelData.meLanguage ); + const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString( rFontSelData.meLanguage ); psp::italic::type eItalic = psp::italic::Unknown; if( rFontSelData.GetSlant() != ITALIC_DONTKNOW ) diff --git a/vcl/util/makefile.mk b/vcl/util/makefile.mk index d501765c8491..eb54531c375c 100644 --- a/vcl/util/makefile.mk +++ b/vcl/util/makefile.mk @@ -299,6 +299,7 @@ SHL2DEPN=$(SHL1IMPLIBN) $(SHL1TARGETN) SHL2STDLIBS=\ $(VCLLIB)\ $(I18NPAPERLIB) \ + $(I18NISOLANGLIB) \ $(TOOLSLIB) \ $(VOSLIB) \ $(BASEGFXLIB) \ -- cgit From de48ac823452730d09eed48cbfee70c2b3880055 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 27 Apr 2010 13:55:52 +0200 Subject: #161963# use modulo-2 arithmetic for access into indirect glyphid array --- vcl/source/gdi/metric.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/source/gdi/metric.cxx b/vcl/source/gdi/metric.cxx index e5f54df41c9e..097cc3a6b901 100644 --- a/vcl/source/gdi/metric.cxx +++ b/vcl/source/gdi/metric.cxx @@ -401,7 +401,7 @@ int ImplFontCharMap::GetGlyphIndex( sal_uInt32 cChar ) const nGlyphIndex += nStartIndex; } else { // the glyphid array has the glyph index - nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex]; + nGlyphIndex = mpGlyphIds[ (nGlyphIndex - nStartIndex) & 0xFFFF ]; } return nGlyphIndex; -- cgit From 6d884e817f8e8d6d42fa4ccdfc56a5832ce90369 Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Tue, 27 Apr 2010 15:40:24 +0200 Subject: vcl111: #i105472# add style to omit pointer evasion of help window --- vcl/inc/vcl/help.hxx | 1 + vcl/source/app/help.cxx | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) (limited to 'vcl') diff --git a/vcl/inc/vcl/help.hxx b/vcl/inc/vcl/help.hxx index 4bca986812ed..30308aa8a723 100644 --- a/vcl/inc/vcl/help.hxx +++ b/vcl/inc/vcl/help.hxx @@ -48,6 +48,7 @@ class Window; #define QUICKHELP_BOTTOM ((USHORT)0x0020) #define QUICKHELP_NOAUTOPOS (QUICKHELP_LEFT | QUICKHELP_CENTER | QUICKHELP_RIGHT | QUICKHELP_TOP | QUICKHELP_VCENTER | QUICKHELP_BOTTOM) #define QUICKHELP_CTRLTEXT ((USHORT)0x0040) +#define QUICKHELP_NOEVADEPOINTER ((USHORT)0x4000) #define QUICKHELP_BIDI_RTL ((USHORT)0x8000) // By changes you must also change: rsc/vclrsc.hxx diff --git a/vcl/source/app/help.cxx b/vcl/source/app/help.cxx index b4ab10887fcd..ac1da931ba06 100644 --- a/vcl/source/app/help.cxx +++ b/vcl/source/app/help.cxx @@ -759,18 +759,26 @@ void ImplSetHelpWindowPos( Window* pHelpWin, USHORT nHelpWinStyle, USHORT nStyle else if ( ( aPos.Y() + aSz.Height() ) > aScreenRect.Bottom() ) aPos.Y() = aScreenRect.Bottom() - aSz.Height(); - // the popup must not appear under the mouse - // otherwise it would directly be closed due to a focus change... - Rectangle aHelpRect( aPos, aSz ); - if( aHelpRect.IsInside( mPos ) ) + if( ! (nStyle & QUICKHELP_NOEVADEPOINTER) ) { - Point delta(2,2); - Point pSize( aSz.Width(), aSz.Height() ); - Point pTest( mPos - pSize - delta ); - if( pTest.X() > aScreenRect.Left() && pTest.Y() > aScreenRect.Top() ) - aPos = pTest; - else - aPos = mPos + delta; + /* the remark below should be obsolete by now as the helpwindow should + not be focusable, leaving it as a hint. However it is sensible in most + conditions to evade the mouse pointer so the content window is fully visible. + + // the popup must not appear under the mouse + // otherwise it would directly be closed due to a focus change... + */ + Rectangle aHelpRect( aPos, aSz ); + if( aHelpRect.IsInside( mPos ) ) + { + Point delta(2,2); + Point pSize( aSz.Width(), aSz.Height() ); + Point pTest( mPos - pSize - delta ); + if( pTest.X() > aScreenRect.Left() && pTest.Y() > aScreenRect.Top() ) + aPos = pTest; + else + aPos = mPos + delta; + } } Window* pWindow = pHelpWin->GetParent()->ImplGetFrameWindow(); -- cgit From 2b7db7fb4e176d01bda38a58d1c0488a6ec9236e Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Wed, 28 Apr 2010 12:03:40 +0200 Subject: #i161963# fix indirect glyphid array access for aliased symbol codepoints --- vcl/source/gdi/metric.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'vcl') diff --git a/vcl/source/gdi/metric.cxx b/vcl/source/gdi/metric.cxx index 097cc3a6b901..325146b6be8a 100644 --- a/vcl/source/gdi/metric.cxx +++ b/vcl/source/gdi/metric.cxx @@ -386,8 +386,9 @@ int ImplFontCharMap::GetGlyphIndex( sal_uInt32 cChar ) const const bool bSymbolic = (mpRangeCodes[0]>=0xF000) & (mpRangeCodes[1]<=0xF0FF); if( !bSymbolic ) return 0; - // check for symbol aliasing (U+F0xx -> U+00xx) - nRange = ImplFindRangeIndex( cChar | 0xF000 ); + // check for symbol aliasing (U+00xx <-> U+F0xx) + cChar |= 0xF000; + nRange = ImplFindRangeIndex( cChar ); } // check that we are inside a range if( (nRange & 1) != 0 ) @@ -401,7 +402,7 @@ int ImplFontCharMap::GetGlyphIndex( sal_uInt32 cChar ) const nGlyphIndex += nStartIndex; } else { // the glyphid array has the glyph index - nGlyphIndex = mpGlyphIds[ (nGlyphIndex - nStartIndex) & 0xFFFF ]; + nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex ]; } return nGlyphIndex; -- cgit From 491858eb7551eaf5e9063ebbcc3a301395d2fb0a Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Fri, 30 Apr 2010 16:49:16 +0200 Subject: vcl111: #i103999# fix menu text color --- vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx index cb36b4613707..4f8372c263d4 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -3471,7 +3471,7 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings ) aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] ); aStyleSet.SetMenuBarColor( aBackColor ); aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] ); - aTextColor = getColor( pMenuTextStyle->text[GTK_STATE_NORMAL] ); + aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] ); aStyleSet.SetMenuColor( aBackColor ); aStyleSet.SetMenuTextColor( aTextColor ); -- cgit From 03efbb4e37d70ea1bd8f2616ce6c6e5a84e61378 Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Mon, 3 May 2010 15:00:51 +0200 Subject: vcl111: #i106125# do not limit the system scrollbarsize anymore --- vcl/win/source/window/salframe.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vcl') diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx index a6567464ac5e..7314fd2b6164 100755 --- a/vcl/win/source/window/salframe.cxx +++ b/vcl/win/source/window/salframe.cxx @@ -2891,8 +2891,8 @@ void WinSalFrame::UpdateSettings( AllSettings& rSettings ) BOOL bCompBorder = (aStyleSettings.GetOptions() & (STYLE_OPTION_MACSTYLE | STYLE_OPTION_UNIXSTYLE)) == 0; // TODO: once those options vanish: just set bCompBorder to TRUE // to have the system colors read - aStyleSettings.SetScrollBarSize( Min( GetSystemMetrics( SM_CXVSCROLL ), 20 ) ); // #99956# do not allow huge scrollbars, most of the UI is not scaled anymore - aStyleSettings.SetSpinSize( Min( GetSystemMetrics( SM_CXVSCROLL ), 20 ) ); + aStyleSettings.SetScrollBarSize( GetSystemMetrics( SM_CXVSCROLL ) ); + aStyleSettings.SetSpinSize( GetSystemMetrics( SM_CXVSCROLL ) ); aStyleSettings.SetCursorBlinkTime( GetCaretBlinkTime() ); if ( bCompBorder ) { -- cgit From f645ed3b6bd82298df06c912ea2fadba0eea96eb Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 4 May 2010 15:38:17 +0200 Subject: #i95867# avoid GDI-internal integer overflow for extremely anisotropic text --- vcl/win/source/gdi/salgdi3.cxx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'vcl') diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx index ebe470d3eb7e..abdfb2dac5bb 100644 --- a/vcl/win/source/gdi/salgdi3.cxx +++ b/vcl/win/source/gdi/salgdi3.cxx @@ -1272,15 +1272,24 @@ HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFont && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) ) lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 ); - // limit font requests to MAXFONTHEIGHT + // #i47675# limit font requests to MAXFONTHEIGHT // TODO: share MAXFONTHEIGHT font instance - if( -aLogFont.lfHeight <= MAXFONTHEIGHT ) + if( (-aLogFont.lfHeight <= MAXFONTHEIGHT) + && (+aLogFont.lfWidth <= MAXFONTHEIGHT) ) + { o_rFontScale = 1.0; - else + } + else if( -aLogFont.lfHeight >= +aLogFont.lfWidth ) { o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT; aLogFont.lfHeight = -MAXFONTHEIGHT; - aLogFont.lfWidth = static_cast( aLogFont.lfWidth / o_rFontScale ); + aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale ); + } + else // #i95867# also limit font widths + { + o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT; + aLogFont.lfWidth = +MAXFONTHEIGHT; + aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale ); } hNewFont = ::CreateFontIndirectW( &aLogFont ); -- cgit From c999e914a371d37ec37aab2db3c2d5f8a62ee192 Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Tue, 4 May 2010 18:15:36 +0200 Subject: vcl111: #i42282# do not position dialogs outside the screen just because the screen existed in the last session --- vcl/inc/vcl/syswin.hxx | 2 ++ vcl/source/window/syswin.cxx | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) (limited to 'vcl') diff --git a/vcl/inc/vcl/syswin.hxx b/vcl/inc/vcl/syswin.hxx index b0e74df9a767..b3a7d9b8775e 100644 --- a/vcl/inc/vcl/syswin.hxx +++ b/vcl/inc/vcl/syswin.hxx @@ -179,6 +179,8 @@ private: SystemWindow (const SystemWindow &); SystemWindow & operator= (const SystemWindow &); + SAL_DLLPRIVATE void ImplMoveToScreen( long& io_rX, long& io_rY, long i_nWidth, long i_nHeight, Window* i_pConfigureWin ); + protected: // Single argument ctors shall be explicit. explicit SystemWindow( WindowType nType ); diff --git a/vcl/source/window/syswin.cxx b/vcl/source/window/syswin.cxx index 056b55dc3b61..f3624ef56f59 100644 --- a/vcl/source/window/syswin.cxx +++ b/vcl/source/window/syswin.cxx @@ -659,6 +659,63 @@ static void ImplWindowStateToStr( const WindowStateData& rData, ByteString& rStr // ----------------------------------------------------------------------- +void SystemWindow::ImplMoveToScreen( long& io_rX, long& io_rY, long i_nWidth, long i_nHeight, Window* i_pConfigureWin ) +{ + Rectangle aScreenRect; + if( Application::IsMultiDisplay() ) + { + aScreenRect = Application::GetScreenPosSizePixel( GetScreenNumber() ); + } + else + { + aScreenRect = Application::GetScreenPosSizePixel( 0 ); + for( unsigned int i = 1; i < Application::GetScreenCount(); i++ ) + aScreenRect.Union( Application::GetScreenPosSizePixel( i ) ); + } + // unfortunately most of the time width and height are not really known + if( i_nWidth < 1 ) + i_nWidth = 50; + if( i_nHeight < 1 ) + i_nHeight = 50; + + // check left border + bool bMove = false; + if( io_rX + i_nWidth < aScreenRect.Left() ) + { + bMove = true; + io_rX = aScreenRect.Left(); + } + // check right border + if( io_rX > aScreenRect.Right() - i_nWidth ) + { + bMove = true; + io_rX = aScreenRect.Right() - i_nWidth; + } + // check top border + if( io_rY + i_nHeight < aScreenRect.Top() ) + { + bMove = true; + io_rY = aScreenRect.Top(); + } + // check bottom border + if( io_rY > aScreenRect.Bottom() - i_nHeight ) + { + bMove = true; + io_rY = aScreenRect.Bottom() - i_nHeight; + } + Window* pParent = i_pConfigureWin->GetParent(); + if( bMove && pParent ) + { + // calculate absolute screen pos here, since that is what is contained in WindowState + Point aParentAbsPos( pParent->OutputToAbsoluteScreenPixel( Point(0,0) ) ); + Size aParentSizePixel( pParent->GetOutputSizePixel() ); + Point aPos( (aParentSizePixel.Width() - i_nWidth) / 2, + (aParentSizePixel.Height() - i_nHeight) / 2 ); + io_rX = aParentAbsPos.X() + aPos.X(); + io_rY = aParentAbsPos.Y() + aPos.Y(); + } +} + void SystemWindow::SetWindowStateData( const WindowStateData& rData ) { ULONG nValidMask = rData.GetMask(); @@ -701,6 +758,10 @@ void SystemWindow::SetWindowStateData( const WindowStateData& rData ) //nState &= ~(WINDOWSTATE_STATE_MINIMIZED); aState.mnState = nState & SAL_FRAMESTATE_SYSTEMMASK; + // normalize window positions onto screen + ImplMoveToScreen( aState.mnX, aState.mnY, aState.mnWidth, aState.mnHeight, pWindow ); + ImplMoveToScreen( aState.mnMaximizedX, aState.mnMaximizedY, aState.mnMaximizedWidth, aState.mnMaximizedHeight, pWindow ); + // #96568# avoid having multiple frames at the same screen location // do the check only if not maximized if( !((rData.GetMask() & WINDOWSTATE_MASK_STATE) && (nState & WINDOWSTATE_STATE_MAXIMIZED)) ) -- cgit From 69e661370538571d578552757bde5998c9d52fdf Mon Sep 17 00:00:00 2001 From: "Frank Schoenheit [fs]" Date: Wed, 5 May 2010 12:29:29 +0200 Subject: os141: do not crash on NULL Windows passed to ::Execute --- vcl/source/window/menu.cxx | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'vcl') diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx index ddfb1125d0d7..cebe1d1f596c 100644 --- a/vcl/source/window/menu.cxx +++ b/vcl/source/window/menu.cxx @@ -32,6 +32,7 @@ #include "vcl/salinst.hxx" #include "tools/list.hxx" #include "tools/debug.hxx" +#include "tools/diagnose_ex.h" #include "vcl/svdata.hxx" #include "vcl/svapp.hxx" #include "vcl/mnemonic.hxx" @@ -3464,6 +3465,9 @@ USHORT PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos ) USHORT PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, USHORT nFlags ) { + ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 ); + + ULONG nPopupModeFlags = 0; if ( nFlags & POPUPMENU_EXECUTE_DOWN ) nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN; -- cgit From 770b45622ec89c3fe430f379a05737841e979bdd Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Thu, 6 May 2010 09:01:43 +0200 Subject: #i11054# #i111272# fix graphite line breaking and expanded/condensed text (thanks kstribley) --- vcl/inc/vcl/graphite_cache.hxx | 19 +-- vcl/inc/vcl/graphite_layout.hxx | 9 ++ vcl/source/glyphs/graphite_layout.cxx | 227 ++++++++++++++++++++++++++-------- 3 files changed, 194 insertions(+), 61 deletions(-) (limited to 'vcl') diff --git a/vcl/inc/vcl/graphite_cache.hxx b/vcl/inc/vcl/graphite_cache.hxx index eba5109c7446..5472b32dd62f 100644 --- a/vcl/inc/vcl/graphite_cache.hxx +++ b/vcl/inc/vcl/graphite_cache.hxx @@ -127,7 +127,7 @@ public: } m_segMap.clear(); }; - GrSegRecord * getSegment(ImplLayoutArgs & layoutArgs, bool bIsRtl) + GrSegRecord * getSegment(ImplLayoutArgs & layoutArgs, bool bIsRtl, int segCharLimit) { GrSegRecord * found = NULL; // try to find a segment starting at correct place, if not, try to find a @@ -152,8 +152,6 @@ public: if (found->m_seg->startCharacter() <= layoutArgs.mnMinCharPos && found->m_seg->stopCharacter() >= layoutArgs.mnEndCharPos) { - const size_t seg_char_limit = min(layoutArgs.mnLength, layoutArgs.mnEndCharPos - + GraphiteLayout::EXTRA_CONTEXT_LENGTH); DBG_ASSERT(found && found->m_seg, "null entry in GraphiteSegmentCache"); // restore original start character, in case it has changed found->m_seg->setTextSourceOffset(found->m_startChar); @@ -161,7 +159,7 @@ public: // interest // We could use substr and ==, but substr does a copy, // so its probably faster to do it like this - for (size_t i = layoutArgs.mnMinCharPos; i < seg_char_limit; i++) + for (int i = layoutArgs.mnMinCharPos; i < segCharLimit; i++) { //if (!found->m_rope->match(rtl::OUString(layoutArgs.mpStr[i], layoutArgs.mnLength), i - found->m_seg->startCharacter())) if (found->m_rope->getStr()[i-found->m_seg->startCharacter()] != layoutArgs.mpStr[i]) @@ -171,6 +169,15 @@ public: { return NULL; } + if (found->m_seg->stopCharacter() > layoutArgs.mnEndCharPos && + static_cast(found->char2BaseGlyph().size()) > layoutArgs.mnEndCharPos) + { + // check that the requested end character isn't mid cluster + if (found->char2BaseGlyph()[layoutArgs.mnEndCharPos-layoutArgs.mnMinCharPos] == -1) + { + return NULL; + } + } // if (found->m_lockCount != 0) // OutputDebugString("Multple users of SegRecord!"); found->m_lockCount++; @@ -183,10 +190,8 @@ public: // this is expecially needed when editing a large paragraph // each edit changes the pointers, but if we don't reuse any segments it gets very // slow. - const size_t seg_char_limit = min(layoutArgs.mnLength, layoutArgs.mnEndCharPos - + GraphiteLayout::EXTRA_CONTEXT_LENGTH); rtl::OUString * rope = new rtl::OUString(layoutArgs.mpStr + layoutArgs.mnMinCharPos, - seg_char_limit - layoutArgs.mnMinCharPos); + segCharLimit - layoutArgs.mnMinCharPos); if (!rope) return NULL; size_t nHash = (*(rope)).hashCode(); GrRMEntry range = m_ropeMap.equal_range(nHash); diff --git a/vcl/inc/vcl/graphite_layout.hxx b/vcl/inc/vcl/graphite_layout.hxx index 1fbb11211ca0..520f4620cd90 100644 --- a/vcl/inc/vcl/graphite_layout.hxx +++ b/vcl/inc/vcl/graphite_layout.hxx @@ -75,6 +75,14 @@ namespace grutils { class GrFeatureParser; } class VCL_DLLPUBLIC GraphiteLayout : public SalLayout { public: + // Mask to allow Word break status to be stored within mvChar2BaseGlyph + enum { + WORD_BREAK_BEFORE = 0x40000000, + HYPHEN_BREAK_BEFORE = 0x80000000, + BREAK_MASK = 0xC0000000, + GLYPH_INDEX_MASK = 0x3FFFFFFF + } LineBreakMask; + class Glyphs : public std::vector { public: @@ -159,6 +167,7 @@ private: std::pair glyph_to_chars(const GlyphItem &) const; std::pair caret_positions(size_t) const; + void expandOrCondense(ImplLayoutArgs &rArgs); }; diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx index 6e75d1fde868..a0aa20a73fde 100644 --- a/vcl/source/glyphs/graphite_layout.cxx +++ b/vcl/source/glyphs/graphite_layout.cxx @@ -353,6 +353,46 @@ std::pair GraphiteLayout::Glyphs::appendCluster(gr::Segment & rSeg, assert(size() < rGlyph2Char.size()); rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] = size(); rGlyph2Char[size()] = nFirstCharInCluster; + + // can we break before this cluster? + // Glyphs may have either a positive or negative breakWeight refering to + // the position after or before the glyph respectively + int nPrevBreakWeight = 0; + if (nFirstGlyphInCluster > 0) + { + nPrevBreakWeight = (iGlyphs.first + (nFirstGlyphInCluster - 1))->breakweight(); + } + int nBreakWeight = aFirstGlyph.breakweight(); + if (nBreakWeight < 0) + { + // negative means it applies to the position before the glyph's character + nBreakWeight *= -1; + if (nPrevBreakWeight > 0 && nPrevBreakWeight < nBreakWeight) + { + // prevBreakWeight wins + nBreakWeight = nPrevBreakWeight; + } + } + else + { + nBreakWeight = 0; + // positive means break after + if (nPrevBreakWeight > 0) + nBreakWeight = nPrevBreakWeight; + } + if (nBreakWeight > gr::klbNoBreak/*0*/ && + // nBreakWeight <= gr::klbHyphenBreak) // uses Graphite hyphenation + nBreakWeight <= gr::klbLetterBreak) // Needed for issue 111272 + { + if (nBreakWeight < gr::klbHyphenBreak) + rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE; + else + rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= HYPHEN_BREAK_BEFORE; + } + // always allow a break before a space even if graphite doesn't + if (rArgs.mpStr[nFirstCharInCluster] == 0x20) + rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE; + bool bBaseGlyph = true; for (int j = nFirstGlyphInCluster; j != nNextGlyph; j += nDelta) @@ -409,7 +449,7 @@ std::pair GraphiteLayout::Glyphs::appendCluster(gr::Segment & rSeg, } } #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"Cluster g[%d-%d) c[%d-%d)%x x%ld y%f\n", nFirstGlyphInCluster, nNextGlyph, nFirstCharInCluster, nNextChar, rArgs.mpStr[nFirstCharInCluster], nXPos, aFirstGlyph.yOffset()); + fprintf(grLog(),"Cluster g[%d-%d) c[%d-%d)%x x%ld y%f bw%d\n", nFirstGlyphInCluster, nNextGlyph, nFirstCharInCluster, nNextChar, rArgs.mpStr[nFirstCharInCluster], nXPos, aFirstGlyph.yOffset(), nBreakWeight); #endif return aBounds; } @@ -641,6 +681,19 @@ gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl)) maLayout.setRightToLeft(bRtl); + // Context is often needed beyond the specified end, however, we don't + // want it if there has been a direction change, since it is hard + // to tell between reordering within one direction and multi-directional + // text. Extra context, can also cause problems with ligatures stradling + // a hyphenation point, so disable if CTL is disabled. + const int nSegCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH); + int limit = rArgs.mnEndCharPos; + if ((nSegCharLimit > limit) && !(SAL_LAYOUT_COMPLEX_DISABLED & rArgs.mnFlags)) + { + limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos, + nSegCharLimit - rArgs.mnEndCharPos, bRtl); + } + #ifdef GRCACHE GrFontHasher hasher(mrFont); sal_Int32 aFontHash = hasher.hashCode(mpFeatures); @@ -648,7 +701,7 @@ gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) (GraphiteCacheHandler::instance).getCache(aFontHash); if (pCache) { - *pSegRecord = pCache->getSegment(rArgs, bRtl); + *pSegRecord = pCache->getSegment(rArgs, bRtl, nSegCharLimit); if (*pSegRecord) { pSegment = (*pSegRecord)->getSegment(); @@ -667,18 +720,6 @@ gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) } #endif - // Context is often needed beyond the specified end, however, we don't - // want it if there has been a direction change, since it is hard - // to tell between reordering within one direction and multi-directional - // text. - const int segCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH); - int limit = rArgs.mnEndCharPos; - if (segCharLimit > limit) - { - limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos, - segCharLimit - rArgs.mnEndCharPos, bRtl); - } - // Create a new TextSource object for the engine. mpTextSrc = new TextSourceAdaptor(rArgs, limit); if (mpFeatures) mpTextSrc->setFeatures(mpFeatures); @@ -795,27 +836,35 @@ bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment) int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) const { - // Adjust maxmnWidth so FindNextBreakPoint returns a sensible answer. - maxmnWidth -= (mnEndCharPos-mnMinCharPos-1)*char_extra; // extra character spacing. - maxmnWidth /= factor; // scaling factor. +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(),"Gr::GetTextBreak c[%d-%d) maxWidth %ld char extra %ld factor %d\n", + mnMinCharPos, mnEndCharPos, maxmnWidth, char_extra, factor); +#endif - // Ask the segment for the nearest whole letter break for the width. - //float width; - float targetWidth = maxmnWidth/mfScaling; // return quickly if this segment is narrower than the target width - // (sometimes graphite doesn't seem to realise this!) - if (targetWidth > mnWidth) + if (maxmnWidth > mnWidth * factor + char_extra * (mnEndCharPos - mnMinCharPos - 1)) return STRING_LEN; - //int nBreak = mpSegment->findNextBreakPoint(mnMinCharPos, - // gr::klbWordBreak, gr::klbLetterBreak, targetWidth, &width); - // LineFillSegment seems to give better results that findNextBreakPoint - // though it may be slower - gr::LayoutEnvironment aLE; - gr::LineFillSegment lineSeg(const_cast(&mrFont), mpTextSrc, &aLE, - mnMinCharPos, mpTextSrc->getContextLength(), - targetWidth); - int nBreak = lineSeg.stopCharacter(); + long nWidth = mvCharDxs[0] * factor; + int nLastBreak = -1; + for (size_t i = 1; i < mvCharDxs.size(); i++) + { + nWidth += char_extra; + if (nWidth > maxmnWidth) break; + if (mvChar2BaseGlyph[i] != -1) + { + if (mvChar2BaseGlyph[i] & (WORD_BREAK_BEFORE | HYPHEN_BREAK_BEFORE)) + nLastBreak = static_cast(i); + } + nWidth += (mvCharDxs[i] - mvCharDxs[i-1]) * factor; + } + int nBreak = mnMinCharPos; + if (nLastBreak > -1) + nBreak += nLastBreak; + +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(), "Gr::GetTextBreak break after %d\n", nBreak - mnMinCharPos); +#endif if (nBreak > mnEndCharPos) nBreak = STRING_LEN; else if (nBreak < mnMinCharPos) nBreak = mnMinCharPos; @@ -833,9 +882,10 @@ long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const { for (size_t i = 0; i < mvCharDxs.size(); i++) { - assert((mvChar2BaseGlyph[i] >= -1) && (mvChar2BaseGlyph[i] < (signed)mvGlyphs.size())); + assert((mvChar2BaseGlyph[i] >= -1) && + ((mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK) < (signed)mvGlyphs.size())); if (mvChar2BaseGlyph[i] != -1 && - mvGlyphs[mvChar2BaseGlyph[i]].mnGlyphIndex == GF_DROPPED) + mvGlyphs[mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK].mnGlyphIndex == GF_DROPPED) { // when used in MultiSalLayout::GetTextBreak dropped glyphs // must have zero width @@ -865,7 +915,6 @@ long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const void GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); - if(rArgs.mpDXArray) { std::vector vDeltaWidths(mvGlyphs.size(), 0); @@ -894,8 +943,75 @@ void GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs) } } } + else if (rArgs.mnLayoutWidth > 0) + { +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(), "AdjustLayout width %ld=>%ld\n", mnWidth, rArgs.mnLayoutWidth); +#endif + expandOrCondense(rArgs); + } } +void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs) +{ + int nDeltaWidth = rArgs.mnLayoutWidth - mnWidth; + if (nDeltaWidth > 0) // expand, just expand between clusters + { + int nClusterCount = 0; + for (size_t j = 0; j < mvGlyphs.size(); j++) + { + if (mvGlyphs[j].IsClusterStart()) + { + ++nClusterCount; + } + } + if (nClusterCount > 1) + { + float fExtraPerCluster = static_cast(nDeltaWidth) / static_cast(nClusterCount - 1); + int nCluster = 0; + int nOffset = 0; + for (size_t i = 0; i < mvGlyphs.size(); i++) + { + if (mvGlyphs[i].IsClusterStart()) + { + nOffset = fExtraPerCluster * nCluster; + size_t nCharIndex = mvGlyph2Char[i]; + mvCharDxs[nCharIndex] += nOffset; + // adjust char dxs for rest of characters in cluster + while (++nCharIndex < mvGlyph2Char.size()) + { + int nChar2Base = (mvChar2BaseGlyph[nCharIndex] == -1)? -1 : mvChar2BaseGlyph[nCharIndex] & GLYPH_INDEX_MASK; + if (nChar2Base == -1 || nChar2Base == static_cast(i)) + mvCharDxs[nCharIndex] += nOffset; + } + ++nCluster; + } + mvGlyphs[i].maLinearPos.X() += nOffset; + } + } + } + else // condense - apply a factor to all glyph positions + { + if (mvGlyphs.size() == 0) return; + Glyphs::iterator iLastGlyph = mvGlyphs.begin() + (mvGlyphs.size() - 1); + // position last glyph using original width + float fXFactor = static_cast(rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth) / static_cast(iLastGlyph->maLinearPos.X()); +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(), "Condense by factor %f\n", fXFactor); +#endif + iLastGlyph->maLinearPos.X() = rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth; + Glyphs::iterator iGlyph = mvGlyphs.begin(); + while (iGlyph != iLastGlyph) + { + iGlyph->maLinearPos.X() = static_cast(iGlyph->maLinearPos.X()) * fXFactor; + ++iGlyph; + } + for (size_t i = 0; i < mvCharDxs.size(); i++) + { + mvCharDxs[i] = fXFactor * static_cast(mvCharDxs[i]); + } + } +} void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector & rDeltaWidth) { @@ -917,37 +1033,39 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector & rDelt int nPrevClusterLastChar = -1; for (size_t i = 0; i < nChars; i++) { - if (mvChar2BaseGlyph[i] > -1 && mvChar2BaseGlyph[i] != nPrevClusterGlyph) + int nChar2Base = (mvChar2BaseGlyph[i] == -1)? -1 : mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK; + if ((nChar2Base > -1) && (nChar2Base != nPrevClusterGlyph)) { - assert((mvChar2BaseGlyph[i] > -1) && (mvChar2BaseGlyph[i] < (signed)mvGlyphs.size())); - GlyphItem & gi = mvGlyphs[mvChar2BaseGlyph[i]]; + assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size())); + GlyphItem & gi = mvGlyphs[nChar2Base]; if (!gi.IsClusterStart()) continue; // find last glyph of this cluster size_t j = i + 1; int nLastChar = i; - int nLastGlyph = mvChar2BaseGlyph[i]; + int nLastGlyph = nChar2Base; for (; j < nChars; j++) { - assert((mvChar2BaseGlyph[j] >= -1) && (mvChar2BaseGlyph[j] < (signed)mvGlyphs.size())); - if (mvChar2BaseGlyph[j] != -1 && mvGlyphs[mvChar2BaseGlyph[j]].IsClusterStart()) + int nChar2BaseJ = (mvChar2BaseGlyph[j] == -1)? -1 : mvChar2BaseGlyph[j] & GLYPH_INDEX_MASK; + assert((nChar2BaseJ >= -1) && (nChar2BaseJ < (signed)mvGlyphs.size())); + if (nChar2BaseJ != -1 && mvGlyphs[nChar2BaseJ].IsClusterStart()) { - nLastGlyph = mvChar2BaseGlyph[j] + ((bRtl)? 1 : -1); + nLastGlyph = nChar2BaseJ + ((bRtl)? 1 : -1); nLastChar = j - 1; break; } } if (nLastGlyph < 0) { - nLastGlyph = mvChar2BaseGlyph[i]; + nLastGlyph = nChar2Base; } // Its harder to find the last glyph rtl, since the first of // cluster is still on the left so we need to search towards // the previous cluster to the right if (bRtl) { - nLastGlyph = mvChar2BaseGlyph[i]; + nLastGlyph = nChar2Base; while (nLastGlyph + 1 < (signed)mvGlyphs.size() && !mvGlyphs[nLastGlyph+1].IsClusterStart()) { @@ -983,7 +1101,7 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector & rDelt // update glyph positions if (bRtl) { - for (int n = mvChar2BaseGlyph[i]; n <= nLastGlyph; n++) + for (int n = nChar2Base; n <= nLastGlyph; n++) { assert((n > - 1) && (n < (signed)mvGlyphs.size())); mvGlyphs[n].maLinearPos.X() += -nDGlyphOrigin + nXOffset; @@ -991,17 +1109,17 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector & rDelt } else { - for (int n = mvChar2BaseGlyph[i]; n <= nLastGlyph; n++) + for (int n = nChar2Base; n <= nLastGlyph; n++) { assert((n > - 1) && (n < (signed)mvGlyphs.size())); mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + nXOffset; } } - rDeltaWidth[mvChar2BaseGlyph[i]] = nDWidth; + rDeltaWidth[nChar2Base] = nDWidth; #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"c%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld\t", (int)i, mvChar2BaseGlyph[i], nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[mvChar2BaseGlyph[i]].maLinearPos.X()); + fprintf(grLog(),"c%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld\t", (int)i, nChar2Base, nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[nChar2Base].maLinearPos.X()); #endif - nPrevClusterGlyph = mvChar2BaseGlyph[i]; + nPrevClusterGlyph = nChar2Base; nPrevClusterLastChar = nLastChar; i = nLastChar; } @@ -1043,7 +1161,7 @@ void GraphiteLayout::kashidaJustify(std::vector& rDeltaWidths, sal_GlyphId continue; } // calculate gap, ignore if too small - int nGapWidth = rDeltaWidths[nOrigGlyphIndex];; + int nGapWidth = rDeltaWidths[nOrigGlyphIndex]; // worst case is one kashida even for mini-gaps if( 3 * nGapWidth < nKashidaWidth ) { @@ -1104,13 +1222,14 @@ void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray { if (mvChar2BaseGlyph[nCharSlot] != -1) { - assert((mvChar2BaseGlyph[nCharSlot] > -1) && (mvChar2BaseGlyph[nCharSlot] < (signed)mvGlyphs.size())); - GlyphItem gi = mvGlyphs[mvChar2BaseGlyph[nCharSlot]]; + int nChar2Base = mvChar2BaseGlyph[nCharSlot] & GLYPH_INDEX_MASK; + assert((mvChar2BaseGlyph[nCharSlot] > -1) && (nChar2Base < (signed)mvGlyphs.size())); + GlyphItem gi = mvGlyphs[nChar2Base]; if (gi.mnGlyphIndex == GF_DROPPED) { continue; } - int nCluster = mvChar2BaseGlyph[nCharSlot]; + int nCluster = nChar2Base; long origClusterWidth = gi.mnNewWidth; long nMin = gi.maLinearPos.X(); long nMax = gi.maLinearPos.X() + gi.mnNewWidth; @@ -1135,7 +1254,7 @@ void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray pCaretXArray[i] = nMin; pCaretXArray[i+1] = nMax; } - prevBase = mvChar2BaseGlyph[nCharSlot]; + prevBase = nChar2Base; prevClusterWidth = origClusterWidth; } else if (prevBase > -1) @@ -1268,7 +1387,7 @@ int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out, #ifdef GRLAYOUT_DEBUG fprintf(grLog(),"GetNextGlyphs g%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", glyph_slot - 1, - mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance, + GLYPH_INDEX_MASK&mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance, aPosOut.X(), aPosOut.Y()); #endif -- cgit From ec097e0b381b6b9d126d77c47ba89f6da70687a3 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Fri, 7 May 2010 09:30:53 +0200 Subject: #100000# fix compile warning and assertion --- vcl/source/glyphs/graphite_layout.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vcl') diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx index a0aa20a73fde..ff2fd8f306b1 100644 --- a/vcl/source/glyphs/graphite_layout.cxx +++ b/vcl/source/glyphs/graphite_layout.cxx @@ -882,8 +882,8 @@ long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const { for (size_t i = 0; i < mvCharDxs.size(); i++) { - assert((mvChar2BaseGlyph[i] >= -1) && - ((mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK) < (signed)mvGlyphs.size())); + assert( (mvChar2BaseGlyph[i] == -1) || + ((signed)(mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK) < (signed)mvGlyphs.size())); if (mvChar2BaseGlyph[i] != -1 && mvGlyphs[mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK].mnGlyphIndex == GF_DROPPED) { -- cgit From 8a7501fdc4dce26a4be91eef144b6bae48e55845 Mon Sep 17 00:00:00 2001 From: Armin Le Grand Date: Mon, 10 May 2010 15:15:32 +0200 Subject: #i110768# use better subdivision for fat beziers when printing --- vcl/source/gdi/outdev.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'vcl') diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx index 62be0130e068..bb5e4e3ba36d 100644 --- a/vcl/source/gdi/outdev.cxx +++ b/vcl/source/gdi/outdev.cxx @@ -2383,6 +2383,16 @@ void OutputDevice::impPaintLineGeometryWithEvtlExpand( { const double fHalfLineWidth((rInfo.GetWidth() * 0.5) + 0.5); + if(aLinePolyPolygon.areControlPointsUsed()) + { + // #i110768# When area geometry has to be created, do not + // use the fallback bezier decomposition inside createAreaGeometry, + // but one that is at least as good as ImplSubdivideBezier was. + // There, Polygon::AdaptiveSubdivide was used with default parameter + // 1.0 as quality index. + aLinePolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(aLinePolyPolygon, 1.0); + } + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) { aFillPolyPolygon.append(basegfx::tools::createAreaGeometry( -- cgit From 4986d0508799b5e743cb6ccc9af6d84824d2e198 Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Mon, 17 May 2010 12:40:01 +0200 Subject: vcl111: #i111464# fix frame width (thanks kendy !) --- vcl/unx/kde4/KDESalGraphics.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vcl') diff --git a/vcl/unx/kde4/KDESalGraphics.cxx b/vcl/unx/kde4/KDESalGraphics.cxx index 25dd50ce3958..a34bf861b83d 100644 --- a/vcl/unx/kde4/KDESalGraphics.cxx +++ b/vcl/unx/kde4/KDESalGraphics.cxx @@ -744,7 +744,7 @@ BOOL KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part, { if( part == PART_BORDER ) { - int size = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + int size = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); USHORT nStyle = val.getNumericVal(); if( nStyle & FRAME_DRAW_NODRAW ) { -- cgit From 5d74e58fe163e423f29b075502e726a0e012a038 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 18 May 2010 09:43:20 +0200 Subject: #i107915# all TIP/SIP unicodes get the same vertical flags --- vcl/source/gdi/sallayout.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'vcl') diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index 3e4ca9fc3df6..5e187944c706 100755 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -144,10 +144,10 @@ int GetVerticalFlags( sal_UCS4 nChar ) return GF_ROTR; // right return GF_ROTL; // left } - else if( (nChar >= 0x02F800 && nChar <= 0x02FFFF) ) // non-BMP CJK ideographs - return GF_NONE; // not rotated + else if( (nChar >= 0x20000) && (nChar <= 0x3FFFF) ) // all SIP/TIP ideographs + return GF_ROTL; // left - return GF_NONE; + return GF_NONE; // not rotated as default } // ----------------------------------------------------------------------- -- cgit From df3eba513b2f936e07ac173a61b4599695b1e0e3 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Tue, 18 May 2010 11:10:00 +0200 Subject: #i111021# #i11575#desc5#b adjust B2D tesselator result to raster --- vcl/unx/source/gdi/salgdi.cxx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'vcl') diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx index 32aeed2dbc95..15e391256344 100644 --- a/vcl/unx/source/gdi/salgdi.cxx +++ b/vcl/unx/source/gdi/salgdi.cxx @@ -1224,13 +1224,18 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : const SalColor aKeepBrushColor = nBrushColor_; nBrushColor_ = nPenColor_; + // #i11575#desc5#b adjust B2D tesselation result to raster positions + basegfx::B2DPolygon aPolygon = rPolygon; + const double fHalfWidth = 0.5 * rLineWidth.getX(); + aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(+fHalfWidth,+fHalfWidth) ); + // shortcut for hairline drawing to improve performance if( bIsHairline ) { // hairlines can benefit from a simplified tesselation // e.g. for hairlines the linejoin style can be ignored basegfx::B2DTrapezoidVector aB2DTrapVector; - basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, rPolygon, rLineWidth.getX() ); + basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() ); // draw tesselation result const int nTrapCount = aB2DTrapVector.size(); @@ -1242,16 +1247,15 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : } // get the area polygon for the line polygon - basegfx::B2DPolygon aPolygon = rPolygon; if( (rLineWidth.getX() != rLineWidth.getY()) && !basegfx::fTools::equalZero( rLineWidth.getY() ) ) { // prepare for createAreaGeometry() with anisotropic linewidth - aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY())); + aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY())); } // create the area-polygon for the line - const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, 0.5*rLineWidth.getX(), eLineJoin) ); + const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin) ); if( (rLineWidth.getX() != rLineWidth.getY()) && !basegfx::fTools::equalZero( rLineWidth.getX() ) ) @@ -1278,3 +1282,4 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + -- cgit From 52a825459618ea98cfa6978ab7eeeace2c2f3a61 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Wed, 19 May 2010 15:47:51 +0200 Subject: #i110214# fix b2dpoly drawing on aqua --- vcl/aqua/source/gdi/salgdi.cxx | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'vcl') diff --git a/vcl/aqua/source/gdi/salgdi.cxx b/vcl/aqua/source/gdi/salgdi.cxx index a54a7fad7ac5..9c2641256cd9 100644 --- a/vcl/aqua/source/gdi/salgdi.cxx +++ b/vcl/aqua/source/gdi/salgdi.cxx @@ -473,7 +473,6 @@ static void AddPolygonToPath( CGMutablePathRef xPath, const CGAffineTransform* pTransform = NULL; const bool bHasCurves = rPolygon.areControlPointsUsed(); - bool bPendingCurve = false; for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ ) { int nClosedIdx = nPointIdx; @@ -488,7 +487,7 @@ static void AddPolygonToPath( CGMutablePathRef xPath, ::basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx ); - if(bPixelSnap) + if( bPixelSnap) { // snap device coordinates to full pixels aPoint.setX( basegfx::fround( aPoint.getX() ) ); @@ -498,9 +497,19 @@ static void AddPolygonToPath( CGMutablePathRef xPath, if( bLineDraw ) aPoint += aHalfPointOfs; - if( !nPointIdx ) // first point + if( nClosedIdx != 0 ) { // first point => just move there CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); - else if( !bPendingCurve ) // line segment + continue; + } + + bool bPendingCurve = false; + if( bHasCurves ) + { + bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx ); + bPendingCurve |= rPolygon.isPrevControlPointUsed( nPointIdx ); + } + + if( !bPendingCurve ) // line segment CGPathAddLineToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); else // cubic bezier segment { @@ -514,9 +523,6 @@ static void AddPolygonToPath( CGMutablePathRef xPath, CGPathAddCurveToPoint( xPath, pTransform, aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() ); } - - if( bHasCurves ) - bPendingCurve = rPolygon.isNextControlPointUsed( nClosedIdx ); } if( bClosePath ) -- cgit From e2c090708e089258087396d46acacf513f70e809 Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Wed, 19 May 2010 16:33:51 +0200 Subject: #i110214# fix typo in b2dpoly drawing on aqua --- vcl/aqua/source/gdi/salgdi.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vcl') diff --git a/vcl/aqua/source/gdi/salgdi.cxx b/vcl/aqua/source/gdi/salgdi.cxx index 9c2641256cd9..9c4ae4a40165 100644 --- a/vcl/aqua/source/gdi/salgdi.cxx +++ b/vcl/aqua/source/gdi/salgdi.cxx @@ -497,7 +497,7 @@ static void AddPolygonToPath( CGMutablePathRef xPath, if( bLineDraw ) aPoint += aHalfPointOfs; - if( nClosedIdx != 0 ) { // first point => just move there + if( !nPointIdx ) { // first point => just move there CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); continue; } @@ -506,7 +506,7 @@ static void AddPolygonToPath( CGMutablePathRef xPath, if( bHasCurves ) { bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx ); - bPendingCurve |= rPolygon.isPrevControlPointUsed( nPointIdx ); + bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx ); } if( !bPendingCurve ) // line segment -- cgit From ffe5faef611a17abf300a049f5158dd6662c46de Mon Sep 17 00:00:00 2001 From: "Frank Schoenheit [fs]" Date: Thu, 20 May 2010 12:38:21 +0200 Subject: unoawt: MultiSelectionSimpleMode property for list boxes, allowing 'browser-like' multi selection (where a single click onto an entry only toggles this entry) --- vcl/source/control/lstbox.cxx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'vcl') diff --git a/vcl/source/control/lstbox.cxx b/vcl/source/control/lstbox.cxx index dde34d52806c..6c7df5b106bf 100644 --- a/vcl/source/control/lstbox.cxx +++ b/vcl/source/control/lstbox.cxx @@ -885,6 +885,8 @@ void ListBox::StateChanged( StateChangedType nType ) { SetStyle( ImplInitStyle( GetStyle() ) ); mpImplLB->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT ) ? TRUE : FALSE ); + BOOL bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) ? TRUE : FALSE; + mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode ); } else if( nType == STATE_CHANGE_MIRRORING ) { -- cgit From 1f8a320a9caec6354f3a2f6bbc38ba8f85e7f16c Mon Sep 17 00:00:00 2001 From: "Philipp Lohmann [pl]" Date: Fri, 21 May 2010 14:06:12 +0200 Subject: vcl111: #i102694# metacity and compiz need the same workaround --- vcl/unx/gtk/window/gtkframe.cxx | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'vcl') diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx index c0eae3d2f0d0..11d567c85098 100644 --- a/vcl/unx/gtk/window/gtkframe.cxx +++ b/vcl/unx/gtk/window/gtkframe.cxx @@ -1353,15 +1353,11 @@ void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate ) // // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused. // awesome. - bool bMetaCity = getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity"); - if( nUserTime == 0 && - ( bMetaCity || - ( - getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz") && - (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) - ) - ) - ) + bool bHack = + getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") || + getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz") + ; + if( nUserTime == 0 && bHack ) { /* #i99360# ugly workaround an X11 library bug */ nUserTime= getDisplay()->GetLastUserEventTime( true ); @@ -1369,7 +1365,7 @@ void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate ) } lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime ); - if( bMetaCity && ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) ) + if( bHack && ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) ) m_bSetFocusOnMap = true; gtk_widget_show( m_pWindow ); -- cgit