diff --git a/vcl/aqua/source/window/salmenu.cxx b/vcl/aqua/source/window/salmenu.cxx index 8128f9171ce1..9b4499cc1233 100644 --- a/vcl/aqua/source/window/salmenu.cxx +++ b/vcl/aqua/source/window/salmenu.cxx @@ -346,7 +346,6 @@ bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rR // set offsets for positioning const float offset = 9.0; - const float lineHeight = 17.0; // get the pointers AquaSalFrame * pParentAquaSalFrame = (AquaSalFrame *) pWin->ImplGetWindowImpl()->mpRealParent->ImplGetFrame(); @@ -360,21 +359,19 @@ bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rR NSMenu* pCopyMenu = [mpMenu copy]; // filter disabled elements - sal_Int32 drawnItems = removeUnusedItemsRunner( pCopyMenu ); + removeUnusedItemsRunner( pCopyMenu ); // create frame rect NSRect displayPopupFrame = NSMakeRect( rRect.nLeft+(offset-1), rRect.nTop+(offset+1), popupFrame.size.width, 0 ); pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false); - // adjust frame rect when necessary + // do the same strange semantics as vcl popup windows to arrive at a frame geometry + // in mirrored UI case; best done by actually executing the same code USHORT nArrangeIndex; - Point position = pWin->ImplCalcPos( pWin, rRect, nFlags, nArrangeIndex ); - if( position.Y() < rRect.nTop ) { - displayPopupFrame.origin.y += ( lineHeight*drawnItems ); - } - if( position.X() < rRect.nLeft ) { - displayPopupFrame.origin.x -= popupFrame.size.width; - } + pWin->SetPosPixel( pWin->ImplCalcPos( pWin, rRect, nFlags, nArrangeIndex ) ); + displayPopupFrame.origin.x = pWin->ImplGetFrame()->maGeometry.nX - pParentAquaSalFrame->maGeometry.nX + offset; + displayPopupFrame.origin.y = pWin->ImplGetFrame()->maGeometry.nY - pParentAquaSalFrame->maGeometry.nY + offset; + pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false); // open popup menu NSPopUpButtonCell * pPopUpButtonCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]; diff --git a/vcl/inc/vcl/sallayout.hxx b/vcl/inc/vcl/sallayout.hxx index fe7cee130a3a..3141381041c8 100755 --- a/vcl/inc/vcl/sallayout.hxx +++ b/vcl/inc/vcl/sallayout.hxx @@ -145,6 +145,7 @@ protected: }; // helper functions often used with ImplLayoutArgs +bool IsDiacritic( sal_UCS4 ); int GetVerticalFlags( sal_UCS4 ); sal_UCS4 GetVerticalChar( sal_UCS4 ); // #i80090# GetMirroredChar also needed outside vcl, moved to svapp.hxx @@ -329,11 +330,11 @@ public: mnGlyphIndex(nGlyphIndex), maLinearPos(rLinearPos) {} - enum{ FALLBACK_MASK=0xFF, IS_IN_CLUSTER=0x100, IS_RTL_GLYPH=0x200 }; + enum{ FALLBACK_MASK=0xFF, IS_IN_CLUSTER=0x100, IS_RTL_GLYPH=0x200, IS_DIACRITIC=0x400 }; - bool IsClusterStart() const { return !(mnFlags & IS_IN_CLUSTER); } - bool IsRTLGlyph() const { return ((mnFlags & IS_RTL_GLYPH) != 0); } - bool IsDiacritic() const { return (mnOrigWidth <= 0); } // TODO: better heuristic + bool IsClusterStart() const { return ((mnFlags & IS_IN_CLUSTER) == 0); } + bool IsRTLGlyph() const { return ((mnFlags & IS_RTL_GLYPH) != 0); } + bool IsDiacritic() const { return ((mnFlags & IS_DIACRITIC) != 0); } }; // --------------- diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index 22db6cff9eb2..0358b25ca153 100755 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -65,6 +65,43 @@ // ======================================================================= +// TODO: ask the glyph directly, for now we need this method because of #i99367# +// true if a codepoint doesn't influence the logical text width +bool IsDiacritic( sal_UCS4 nChar ) +{ + // shortcut abvious non-diacritics + if( nChar < 0x0300 ) + return false; + if( nChar >= 0x2100 ) + return false; + + struct DiaRange { sal_UCS4 mnMin, mnEnd;}; + static const DiaRange aRanges[] = { + {0x0300, 0x0370}, + {0x0590, 0x05C0}, {0x05C1, 0x05C3}, {0x05C3, 0x05C6}, {0x05C7, 0x05C8}, + {0x0610, 0x061B}, {0x064B, 0x0660}, {0x0670, 0x0671}, {0x06D6, 0x06DC}, {0x06DF, 0x06EE}, + {0x0730, 0x074D}, {0x07A6, 0x07B1}, {0x07EB, 0x07F4}, +#if 0 // all known fonts have zero-width diacritics already, so no need to query it + {0x0900, 0x0904}, {0x093C, 0x093D}, {0x0941, 0x0948}, {0x094D, 0x0950}, {0x0951, 0x0958}, + {0x0980, 0x0985}, {0x09BC, 0x09BD}, {0x09C1, 0x09C7}, {0x09CD, 0x09CE}, {0x09E2, 0x09E6}, + {0x0A00, 0x0A05}, {0x0A3C, 0x0A59}, //... +#endif + {0x1DC0, 0x1E00}, + {0x205F, 0x2070}, {0x20D0, 0x2100} + }; + + // TODO: almost anything is faster than an O(n) search + static const int nCount = sizeof(aRanges) / sizeof(*aRanges); + const DiaRange* pRange = &aRanges[0]; + for( int i = nCount; --i >= 0; ++pRange ) + if( (pRange->mnMin <= nChar) && (nChar < pRange->mnEnd) ) + return true; + + return false; +} + +// ======================================================================= + int GetVerticalFlags( sal_UCS4 nChar ) { if( (nChar >= 0x1100 && nChar <= 0x11f9) // Hangul Jamo @@ -1077,7 +1114,7 @@ void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs ) return; // determine cluster boundaries and x base offset - int nCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos; + const int nCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos; int* pLogCluster = (int*)alloca( nCharCount * sizeof(int) ); int i, n; long nBasePointX = -1; @@ -1096,6 +1133,20 @@ void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs ) if( nBasePointX < 0 ) nBasePointX = pG->maLinearPos.X(); } + // retarget unresolved pLogCluster[n] to a glyph inside the cluster + // TODO: better do it while the deleted-glyph markers are still there + for( n = 0; n < nCharCount; ++n ) + if( (i = pLogCluster[0]) >= 0 ) + break; + if( n >= nCharCount ) + return; + for( n = 0; n < nCharCount; ++n ) + { + if( pLogCluster[ n ] < 0 ) + pLogCluster[ n ] = i; + else + i = pLogCluster[ n ]; + } // calculate adjusted cluster widths sal_Int32* pNewGlyphWidths = (sal_Int32*)alloca( mnGlyphCount * sizeof(long) ); @@ -1106,15 +1157,11 @@ void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs ) for( int nCharPos = i = -1; rArgs.GetNextPos( &nCharPos, &bRTL ); ) { n = nCharPos - rArgs.mnMinCharPos; - if( pLogCluster[ n ] >= 0 ) - i = pLogCluster[ n ]; - if( i >= 0 ) - { - long nDelta = rArgs.mpDXArray[ n ] ; - if( n > 0 ) - nDelta -= rArgs.mpDXArray[ n-1 ]; - pNewGlyphWidths[ i ] += nDelta * mnUnitsPerPixel; - } + i = pLogCluster[ n ]; + long nDelta = rArgs.mpDXArray[ n ] ; + if( n > 0 ) + nDelta -= rArgs.mpDXArray[ n-1 ]; + pNewGlyphWidths[ i ] += nDelta * mnUnitsPerPixel; } // move cluster positions using the adjusted widths @@ -1133,10 +1180,11 @@ void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs ) { if( pClusterG->IsClusterStart() ) break; - nOldClusterWidth += pClusterG->mnNewWidth; + if( !pClusterG->IsDiacritic() ) // #i99367# ignore diacritics + nOldClusterWidth += pClusterG->mnNewWidth; nNewClusterWidth += pNewGlyphWidths[j]; } - int nDiff = nNewClusterWidth - nOldClusterWidth; + const int nDiff = nNewClusterWidth - nOldClusterWidth; // adjust cluster glyph widths and positions nDelta = nBasePointX + (nNewPos - pG->maLinearPos.X()); @@ -1179,13 +1227,13 @@ void GenericSalLayout::Justify( long nNewWidth ) { if( !pG->IsDiacritic() ) ++nStretchable; - if( nMaxGlyphWidth < pG->mnOrigWidth) - nMaxGlyphWidth = pG->mnOrigWidth; + if( nMaxGlyphWidth < pG->mnOrigWidth ) + nMaxGlyphWidth = pG->mnOrigWidth; } // move rightmost glyph to requested position nOldWidth -= pGRight->mnOrigWidth; - if( nOldWidth <= 0) + if( nOldWidth <= 0 ) return; if( nNewWidth < nMaxGlyphWidth) nNewWidth = nMaxGlyphWidth; diff --git a/vcl/source/glyphs/gcach_ftyp.hxx b/vcl/source/glyphs/gcach_ftyp.hxx index a853e7008aa5..660f772d43ed 100644 --- a/vcl/source/glyphs/gcach_ftyp.hxx +++ b/vcl/source/glyphs/gcach_ftyp.hxx @@ -181,7 +181,7 @@ public: virtual int GetFontFaceNum() const { return mpFontInfo->GetFaceNum(); } virtual bool TestFont() const; virtual void* GetFtFace() const; - virtual int GetLoadFlags() const { return mnLoadFlags; } + virtual int GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); } virtual bool NeedsArtificialBold() const { return mbArtBold; } virtual bool NeedsArtificialItalic() const { return mbArtItalic; } diff --git a/vcl/source/glyphs/gcach_layout.cxx b/vcl/source/glyphs/gcach_layout.cxx index 1e2f83f5f128..6bbf78f819b0 100755 --- a/vcl/source/glyphs/gcach_layout.cxx +++ b/vcl/source/glyphs/gcach_layout.cxx @@ -519,7 +519,9 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr continue; } + // apply vertical flags, etc. + bool bDiacritic = false; if( nCharPos >= 0 ) { sal_UCS4 aChar = rArgs.mpStr[ nCharPos ]; @@ -535,12 +537,22 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr } #endif nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar ); + + // #i99367# HACK: try to detect all diacritics + if( aChar>=0x0300 && aChar<0x2100 ) + bDiacritic = IsDiacritic( aChar ); } // get glyph position and its metrics aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) ); const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex ); int nGlyphWidth = rGM.GetCharWidth(); + if( nGlyphWidth <= 0 ) + bDiacritic |= true; + // #i99367# force all diacritics to zero width + // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth + else if( bDiacritic ) + nGlyphWidth = 0; // heuristic to detect glyph clusters bool bInCluster = true; @@ -556,7 +568,7 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr nClusterMinPos = nCharPos; // extend cluster else if( nCharPos <= nClusterMaxPos ) /*NOTHING*/; // inside cluster - else if( nGlyphWidth <= 0 ) + else if( bDiacritic ) nClusterMaxPos = nCharPos; // add diacritic to cluster else { nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster @@ -570,7 +582,7 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr nClusterMaxPos = nCharPos; // extend cluster else if( nCharPos >= nClusterMinPos ) /*NOTHING*/; // inside cluster - else if( nGlyphWidth <= 0 ) + else if( bDiacritic ) { nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*] if( bClusterStart ) { @@ -590,6 +602,8 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; if( bRightToLeft ) nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; + if( bDiacritic ) + nGlyphFlags |= GlyphItem::IS_DIACRITIC; // add resulting glyph item to layout const GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth ); diff --git a/vcl/source/window/dlgctrl.cxx b/vcl/source/window/dlgctrl.cxx index 642c378a8eee..1e9a3350c88e 100644 --- a/vcl/source/window/dlgctrl.cxx +++ b/vcl/source/window/dlgctrl.cxx @@ -370,7 +370,7 @@ static Window* ImplFindAccelWindow( Window* pParent, USHORT& rIndex, xub_Unicode pWindow = ImplGetNextWindow( pParent, i, i, TRUE ); else pWindow = ImplGetChildWindow( pParent, nFormStart, i, TRUE ); - while ( bSearch ) + while( bSearch && pWindow ) { const XubString aStr = pWindow->GetText(); USHORT nPos = aStr.Search( '~' ); @@ -415,7 +415,11 @@ static Window* ImplFindAccelWindow( Window* pParent, USHORT& rIndex, xub_Unicode break; if ( i < nFormEnd ) + { pWindow = ImplGetNextWindow( pParent, i, i, bCheckEnable ); + if( ! pWindow ) + pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable ); + } else pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable ); } diff --git a/vcl/source/window/floatwin.cxx b/vcl/source/window/floatwin.cxx index 59dfc2a04eae..7bcb90bbb8fc 100644 --- a/vcl/source/window/floatwin.cxx +++ b/vcl/source/window/floatwin.cxx @@ -424,6 +424,11 @@ Point FloatingWindow::ImplCalcPos( Window* pWindow, { if( devRectRTL.Right()-aSize.Width()+1 < aScreenRect.Left() ) aPos.X() -= aScreenRect.Left() - devRectRTL.Right() + aSize.Width() - 1; + else if( aPos.X() + aSize.Width() > aScreenRect.Right() ) + { + aPos.X() -= aSize.Width()-2; // popup to left instead + aPos.Y() -= 2; + } } else if ( aPos.X()+aSize.Width() > aScreenRect.Right() ) { diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx index 0f5e6fb6a8db..1318f4fa8415 100644 --- a/vcl/source/window/menu.cxx +++ b/vcl/source/window/menu.cxx @@ -31,42 +31,36 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#ifndef _SV_SVSYS_HXX -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef _SV_SVIDS_HRC -#include -#endif -#include -#include -#include -#include -#include -#include -#ifndef _SV_RC_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "svsys.h" +#include "vcl/salinst.hxx" +#include "tools/list.hxx" +#include "tools/debug.hxx" +#include "vcl/svdata.hxx" +#include "vcl/svapp.hxx" +#include "vcl/mnemonic.hxx" +#include "vcl/image.hxx" +#include "vcl/event.hxx" +#include "vcl/help.hxx" +#include "vcl/svids.hrc" +#include "vcl/floatwin.hxx" +#include "vcl/wrkwin.hxx" +#include "vcl/timer.hxx" +#include "vcl/sound.hxx" +#include "vcl/decoview.hxx" +#include "vcl/bitmap.hxx" +#include "tools/rc.h" +#include "vcl/menu.hxx" +#include "vcl/button.hxx" +#include "vcl/gradient.hxx" +#include "vcl/i18nhelp.hxx" +#include "vcl/taskpanelist.hxx" +#include "vcl/window.h" +#include "vcl/controllayout.hxx" +#include "vcl/toolbox.hxx" +#include "tools/stream.hxx" +#include "vcl/salmenu.hxx" +#include "vcl/salframe.hxx" +#include "vcl/dockingarea.hxx" #include @@ -3572,7 +3566,7 @@ USHORT PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, ULONG nPopupM pWin->SetFocusId( nFocusId ); pWin->SetOutputSizePixel( aSz ); - // #102158# menues must never grab the focus, otherwise + // #102158# menus must never grab the focus, otherwise // they will be closed immediately // from now on focus grabbing is only prohibited automatically if // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some @@ -3581,15 +3575,7 @@ USHORT PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, ULONG nPopupM if ( GetItemCount() ) { SalMenu* pMenu = ImplGetSalMenu(); - Rectangle aNativeRect( aRect ); - if( pW->IsRTLEnabled() && Application::GetSettings().GetLayoutRTL() ) - { - Point aPt( aRect.TopLeft() ); - aPt.X() += aSz.Width(); - pW->ImplMirrorFramePos( aPt ); - aNativeRect = Rectangle( aPt, aNativeRect.GetSize() ); - } - if( pMenu && pMenu->ShowNativePopupMenu( pWin, aNativeRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) ) + if( pMenu && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) ) { pWin->StopExecute(0); pWin->doShutdown(); diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index caa43c3bef1e..ec16b65cf41f 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -3015,25 +3015,9 @@ void Window::ImplScroll( const Rectangle& rRect, Window* pWindow = mpWindowImpl->mpFirstChild; while ( pWindow ) { - pWindow->mpWindowImpl->mnX += nHorzScroll; - pWindow->mpWindowImpl->maPos.X() += nHorzScroll; - pWindow->mpWindowImpl->mnY += nVertScroll; - pWindow->mpWindowImpl->maPos.Y() += nVertScroll; - if ( pWindow->ImplUpdatePos() ) - pWindow->ImplUpdateSysObjPos(); - if ( pWindow->IsReallyVisible() ) - pWindow->ImplSetClipFlag(); - if ( pWindow->mpWindowImpl->mpClientWindow ) - pWindow->mpWindowImpl->mpClientWindow->mpWindowImpl->maPos = pWindow->mpWindowImpl->maPos; - - if ( pWindow->IsVisible() ) - { - pWindow->ImplCallMove(); - } - else - { - pWindow->mpWindowImpl->mbCallMove = TRUE; - } + Point aPos = pWindow->GetPosPixel(); + aPos += Point( nHorzScroll, nVertScroll ); + pWindow->SetPosPixel( aPos ); pWindow = pWindow->mpWindowImpl->mpNext; } @@ -3261,7 +3245,6 @@ void Window::ImplPosSizeWindow( long nX, long nY, if ( nFlags & WINDOW_POSSIZE_X ) { long nOrgX = nX; - //if ( nX != mnX ) // --- RTL --- (compare the screen coordinates) Point aPtDev( Point( nX+mnOutOffX, 0 ) ); if( ImplHasMirroredGraphics() ) @@ -3276,6 +3259,17 @@ void Window::ImplPosSizeWindow( long nX, long nY, // --- RTL --- (re-mirror at parent window) nX = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - nX; } + /* #i99166# An LTR window in RTL UI that gets sized only would be + expected to not moved its upper left point + */ + if( bnXRecycled ) + { + if( ImplIsAntiparallel() ) + { + aPtDev.X() = mpWindowImpl->mnAbsScreenX; + nOrgX = mpWindowImpl->maPos.X(); + } + } } else if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() ) {