summaryrefslogtreecommitdiff
path: root/vcl/win/source/gdi
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/win/source/gdi')
-rw-r--r--vcl/win/source/gdi/MAKEFILE.MK4
-rw-r--r--vcl/win/source/gdi/salgdi3.cxx127
-rw-r--r--vcl/win/source/gdi/salgdi_gdiplus.cxx162
-rwxr-xr-xvcl/win/source/gdi/winlayout.cxx307
4 files changed, 470 insertions, 130 deletions
diff --git a/vcl/win/source/gdi/MAKEFILE.MK b/vcl/win/source/gdi/MAKEFILE.MK
index a6d84d41f3ea..3d8fd904b35b 100644
--- a/vcl/win/source/gdi/MAKEFILE.MK
+++ b/vcl/win/source/gdi/MAKEFILE.MK
@@ -64,6 +64,10 @@ SLOFILES= $(SLO)$/salgdi.obj \
EXCEPTIONSFILES= $(SLO)$/salprn.obj
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+
# --- Targets ------------------------------------------------------
.INCLUDE : target.mk
diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx
index 99f276faa964..73f4d8320acc 100644
--- a/vcl/win/source/gdi/salgdi3.cxx
+++ b/vcl/win/source/gdi/salgdi3.cxx
@@ -6,9 +6,6 @@
*
* OpenOffice.org - a multi-platform office productivity suite
*
- * $RCSfile: salgdi3.cxx,v $
- * $Revision: 1.95.14.5 $
- *
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
@@ -47,6 +44,7 @@
#include "vcl/svapp.hxx"
#include "vcl/outfont.hxx"
#include "vcl/font.hxx"
+#include "vcl/fontsubset.hxx"
#include "vcl/sallayout.hxx"
#include "rtl/logfile.hxx"
@@ -74,6 +72,11 @@
#include <algorithm>
#endif
+#ifdef ENABLE_GRAPHITE
+#include <graphite/GrClient.h>
+#include <graphite/WinFont.h>
+#endif
+
#include <vector>
#include <set>
#include <map>
@@ -551,13 +554,10 @@ static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rE
aDFA.mbEmbeddable = false;
aDFA.mbSubsettable = false;
- if( (rMetric.tmPitchAndFamily & TMPF_TRUETYPE) != 0 )
- if( (rMetric.tmPitchAndFamily & TMPF_DEVICE) == 0 )
- // TODO: implement type1 or CFF subsetting
- if( 0 == (rMetric.ntmFlags & (NTM_PS_OPENTYPE | NTM_TYPE1) ) )
- aDFA.mbSubsettable = true;
- // for now we can only embed Type1 fonts
- if( 0 != (rMetric.ntmFlags & NTM_TYPE1 ) )
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
+ || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
+ aDFA.mbSubsettable = true;
+ else if( 0 != (rMetric.tmPitchAndFamily & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
aDFA.mbEmbeddable = true;
// heuristics for font quality
@@ -566,7 +566,7 @@ static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rE
aDFA.mnQuality = 0;
if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
aDFA.mnQuality += 50;
- if( rMetric.ntmFlags & NTM_TT_OPENTYPE )
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
aDFA.mnQuality += 10;
if( aDFA.mbSubsettable )
aDFA.mnQuality += 200;
@@ -633,13 +633,10 @@ static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rE
aDFA.mbEmbeddable = false;
aDFA.mbSubsettable = false;
- if( (rMetric.tmPitchAndFamily & TMPF_TRUETYPE) != 0 )
- if( (rMetric.tmPitchAndFamily & TMPF_DEVICE) == 0 )
- // TODO: implement type1 or CFF subsetting
- if( 0 == (rMetric.ntmFlags & (NTM_PS_OPENTYPE | NTM_TYPE1) ) )
- aDFA.mbSubsettable = true;
- // for now we can only embed Type1 fonts
- if( rMetric.ntmFlags & NTM_TYPE1 )
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
+ || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
+ aDFA.mbSubsettable = true;
+ else if( 0 != (rMetric.tmPitchAndFamily & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
aDFA.mbEmbeddable = true;
// heuristics for font quality
@@ -648,7 +645,7 @@ static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rE
aDFA.mnQuality = 0;
if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
aDFA.mnQuality += 50;
- if( rMetric.ntmFlags & NTM_TT_OPENTYPE )
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
aDFA.mnQuality += 10;
if( aDFA.mbSubsettable )
aDFA.mnQuality += 200;
@@ -807,6 +804,9 @@ ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
mbDisableGlyphApi( false ),
mbHasKoreanRange( false ),
mbHasCJKSupport( false ),
+#ifdef ENABLE_GRAPHITE
+ mbHasGraphiteSupport( false ),
+#endif
mbHasArabicSupport ( false ),
mbAliasSymbolsLow( false ),
mbAliasSymbolsHigh( false ),
@@ -865,6 +865,13 @@ void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
ReadCmapTable( hDC );
ReadOs2Table( hDC );
+#ifdef ENABLE_GRAPHITE
+ static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
+ if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
+ {
+ mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
+ }
+#endif
// even if the font works some fonts have problems with the glyph API
// => the heuristic below tries to figure out which fonts have the problem
@@ -993,27 +1000,25 @@ void ImplWinFontData::ReadGsubTable( HDC hDC ) const
void ImplWinFontData::ReadCmapTable( HDC hDC ) const
{
- CmapResult aResult;
- aResult.mnPairCount = 0;
- aResult.mpPairCodes = NULL;
- aResult.mpStartGlyphs = NULL;
- aResult.mbSymbolic = (meWinCharSet == SYMBOL_CHARSET);
- aResult.mbRecoded = true;
+ if( mpUnicodeMap != NULL )
+ return;
+ bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
// get the CMAP table from the font which is selected into the DC
const DWORD nCmapTag = CalcTag( "cmap" );
const RawFontData aRawFontData( hDC, nCmapTag );
// parse the CMAP table if available
- if( aRawFontData.get() )
+ if( aRawFontData.get() ) {
+ CmapResult aResult;
ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
+ mbDisableGlyphApi |= aResult.mbRecoded;
+ aResult.mbSymbolic = bIsSymbolFont;
+ if( aResult.mnRangeCount > 0 )
+ mpUnicodeMap = new ImplFontCharMap( aResult );
+ }
- mbDisableGlyphApi |= aResult.mbRecoded;
-
- if( aResult.mnPairCount > 0 )
- mpUnicodeMap = new ImplFontCharMap( aResult.mnPairCount,
- aResult.mpPairCodes, aResult.mpStartGlyphs );
- else
- mpUnicodeMap = ImplFontCharMap::GetDefaultMap();
+ if( !mpUnicodeMap )
+ mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
}
// =======================================================================
@@ -2547,6 +2552,8 @@ BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
{
+ // TODO: use more of the central font-subsetting code, move stuff there if needed
+
// create matching ImplFontSelectData
// we need just enough to get to the font file data
// use height=1000 for easier debugging (to match psprint's font units)
@@ -2554,10 +2561,14 @@ BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
// TODO: much better solution: move SetFont and restoration of old font to caller
ScopedFont aOldFont(*this);
- float fScale = 0.0;
+ float fScale = 1.0;
HFONT hOldFont = 0;
ImplDoSetFont( &aIFSD, fScale, hOldFont );
+ ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
+ pWinFontData->UpdateFromHDC( mhDC );
+/*const*/ ImplFontCharMap* pImplFontCharMap = pWinFontData->GetImplFontCharMap();
+
#if OSL_DEBUG_LEVEL > 1
// get font metrics
TEXTMETRICA aWinMetric;
@@ -2568,8 +2579,42 @@ BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
#endif
+ rtl::OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+ return FALSE;
+ const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+ const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
+
+ // check if the font has a CFF-table
+ const DWORD nCffTag = CalcTag( "CFF " );
+ const RawFontData aRawCffData( mhDC, nCffTag );
+ if( aRawCffData.get() )
+ {
+ long nRealGlyphIds[ 256 ];
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ // TODO: remap notdef glyph if needed
+ // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
+ nGlyphIdx = pImplFontCharMap->GetGlyphIndex( nGlyphIdx );
+ if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
+ {/*####*/}
+
+ nRealGlyphIds[i] = nGlyphIdx;
+ }
+
+ // provide a font subset from the CFF-table
+ FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+ rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
+ bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
+ nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
+ fclose( pOutFile );
+ return bRC;
+ }
+
// get raw font file data
- const RawFontData xRawFontData( mhDC );
+ const RawFontData xRawFontData( mhDC, NULL );
if( !xRawFontData.get() )
return FALSE;
@@ -2585,7 +2630,7 @@ BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
TTGlobalFontInfo aTTInfo;
::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
- rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TRUETYPE;
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
rInfo.m_nAscent = +aTTInfo.winAscent;
rInfo.m_nDescent = -aTTInfo.winDescent;
@@ -2593,7 +2638,7 @@ BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
Point( aTTInfo.xMax, aTTInfo.yMax ) );
rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
- // subset glyphs and get their properties
+ // subset TTF-glyphs and get their properties
// take care that subset fonts require the NotDef glyph in pos 0
int nOrigCount = nGlyphCount;
USHORT aShortIDs[ 256 ];
@@ -2649,11 +2694,6 @@ BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
free( pMetrics );
// write subset into destination file
- rtl::OUString aSysPath;
- if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
- return FALSE;
- rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
- ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
aTempEncs, nGlyphCount, 0, NULL, 0 );
return (nRC == SF_OK);
@@ -2683,7 +2723,7 @@ const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont,
TEXTMETRICA aTm;
if( !::GetTextMetricsA( mhDC, &aTm ) )
*pDataLen = 0;
- rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TYPE1;
+ rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1;
WCHAR aFaceName[64];
int nFNLen = ::GetTextFaceW( mhDC, 64, aFaceName );
// #i59854# strip eventual null byte
@@ -2876,3 +2916,4 @@ SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
}
//--------------------------------------------------------------------------
+
diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx
index 8709fc872540..5c00c786e22d 100644
--- a/vcl/win/source/gdi/salgdi_gdiplus.cxx
+++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx
@@ -64,75 +64,79 @@
void impAddB2DPolygonToGDIPlusGraphicsPath(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon)
{
- const sal_uInt32 nCount(rPolygon.count());
-
- if(nCount)
- {
- const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1);
- const bool bControls(rPolygon.areControlPointsUsed());
- basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0));
- Gdiplus::PointF aFCurr(Gdiplus::REAL(aCurr.getX()), Gdiplus::REAL(aCurr.getY()));
-
- for(sal_uInt32 a(0); a < nEdgeCount; a++)
- {
- const sal_uInt32 nNextIndex((a + 1) % nCount);
- const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
- const Gdiplus::PointF aFNext(Gdiplus::REAL(aNext.getX()), Gdiplus::REAL(aNext.getY()));
-
- if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
- {
- const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
- const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
-
- rPath.AddBezier(
- aFCurr,
- Gdiplus::PointF(Gdiplus::REAL(aCa.getX()), Gdiplus::REAL(aCa.getY())),
- Gdiplus::PointF(Gdiplus::REAL(aCb.getX()), Gdiplus::REAL(aCb.getY())),
- aFNext);
- }
- else
- {
- rPath.AddLine(aFCurr, aFNext);
- }
-
- if(a + 1 < nEdgeCount)
- {
- aCurr = aNext;
- aFCurr = aFNext;
- }
- }
- }
+ const sal_uInt32 nCount(rPolygon.count());
+
+ if(nCount)
+ {
+ const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1);
+ const bool bControls(rPolygon.areControlPointsUsed());
+ basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0));
+ Gdiplus::PointF aFCurr(Gdiplus::REAL(aCurr.getX()), Gdiplus::REAL(aCurr.getY()));
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ const sal_uInt32 nNextIndex((a + 1) % nCount);
+ const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
+ const Gdiplus::PointF aFNext(Gdiplus::REAL(aNext.getX()), Gdiplus::REAL(aNext.getY()));
+
+ if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
+ {
+ const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
+
+ rPath.AddBezier(
+ aFCurr,
+ Gdiplus::PointF(Gdiplus::REAL(aCa.getX()), Gdiplus::REAL(aCa.getY())),
+ Gdiplus::PointF(Gdiplus::REAL(aCb.getX()), Gdiplus::REAL(aCb.getY())),
+ aFNext);
+ }
+ else
+ {
+ rPath.AddLine(aFCurr, aFNext);
+ }
+
+ if(a + 1 < nEdgeCount)
+ {
+ aCurr = aNext;
+ aFCurr = aFNext;
+ }
+ }
+ }
}
bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency)
{
- const sal_uInt32 nCount(rPolyPolygon.count());
+ const sal_uInt32 nCount(rPolyPolygon.count());
if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0))
{
- Gdiplus::Graphics aGraphics(mhDC);
+ Gdiplus::Graphics aGraphics(mhDC);
const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0));
- Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor));
- Gdiplus::SolidBrush aTestBrush(aTestColor);
- Gdiplus::GraphicsPath aPath;
+ Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor));
+ Gdiplus::SolidBrush aTestBrush(aTestColor);
+ Gdiplus::GraphicsPath aPath;
for(sal_uInt32 a(0); a < nCount; a++)
{
- aPath.StartFigure();
+ if(0 != a)
+ {
+ aPath.StartFigure(); // #i101491# not needed for first run
+ }
+
impAddB2DPolygonToGDIPlusGraphicsPath(aPath, rPolyPolygon.getB2DPolygon(a));
aPath.CloseFigure();
}
if(getAntiAliasB2DDraw())
{
- aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
- }
- else
- {
- aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
- }
-
- aGraphics.FillPath(&aTestBrush, &aPath);
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
+ }
+ else
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
+ }
+
+ aGraphics.FillPath(&aTestBrush, &aPath);
}
return true;
@@ -140,53 +144,59 @@ bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly
bool WinSalGraphics::drawPolyLine(const basegfx::B2DPolygon& rPolygon, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin)
{
- const sal_uInt32 nCount(rPolygon.count());
+ const sal_uInt32 nCount(rPolygon.count());
if(mbPen && nCount)
{
- Gdiplus::Graphics aGraphics(mhDC);
- Gdiplus::Color aTestColor(255, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor));
- Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX()));
- Gdiplus::GraphicsPath aPath;
-
- switch(eLineJoin)
- {
+ Gdiplus::Graphics aGraphics(mhDC);
+ Gdiplus::Color aTestColor(255, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor));
+ Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX()));
+ Gdiplus::GraphicsPath aPath;
+
+ switch(eLineJoin)
+ {
default : // basegfx::B2DLINEJOIN_NONE :
{
break;
}
case basegfx::B2DLINEJOIN_BEVEL :
{
- aTestPen.SetLineJoin(Gdiplus::LineJoinBevel);
+ aTestPen.SetLineJoin(Gdiplus::LineJoinBevel);
break;
}
case basegfx::B2DLINEJOIN_MIDDLE :
case basegfx::B2DLINEJOIN_MITER :
{
const Gdiplus::REAL aMiterLimit(15.0);
- aTestPen.SetMiterLimit(aMiterLimit);
- aTestPen.SetLineJoin(Gdiplus::LineJoinMiter);
+ aTestPen.SetMiterLimit(aMiterLimit);
+ aTestPen.SetLineJoin(Gdiplus::LineJoinMiter);
break;
}
case basegfx::B2DLINEJOIN_ROUND :
{
- aTestPen.SetLineJoin(Gdiplus::LineJoinRound);
+ aTestPen.SetLineJoin(Gdiplus::LineJoinRound);
break;
}
- }
+ }
impAddB2DPolygonToGDIPlusGraphicsPath(aPath, rPolygon);
-
- if(getAntiAliasB2DDraw())
- {
- aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
- }
- else
- {
- aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
- }
-
- aGraphics.DrawPath(&aTestPen, &aPath);
+
+ if(rPolygon.isClosed())
+ {
+ // #i101491# needed to create the correct line joins
+ aPath.CloseFigure();
+ }
+
+ if(getAntiAliasB2DDraw())
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
+ }
+ else
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
+ }
+
+ aGraphics.DrawPath(&aTestPen, &aPath);
}
return true;
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index 8d9347e7e352..2d335808e4c1 100755
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -71,6 +71,17 @@
typedef std::hash_map<int,int> IntMap;
typedef std::set<int> IntSet;
+// Graphite headers
+#ifdef ENABLE_GRAPHITE
+#include <i18npool/mslangid.hxx>
+#include <graphite/GrClient.h>
+#include <graphite/WinFont.h>
+#include <graphite/Segment.h>
+#include <vcl/graphite_layout.hxx>
+#include <vcl/graphite_cache.hxx>
+#include <vcl/graphite_features.hxx>
+#endif
+
#define DROPPED_OUTGLYPH 0xFFFF
using namespace rtl;
@@ -1757,6 +1768,8 @@ bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
if( nMaxGlyphPos < n )
nMaxGlyphPos = n;
}
+ if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
+ nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
// extend the glyph range to account for all glyphs in referenced clusters
if( !rVisualItem.IsRTL() ) // LTR-item
@@ -2041,11 +2054,25 @@ void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
long nDelta = nNewXPos - pVI->mnXOffset;
if( nStart > nMinGlyphPos )
{
- // move the glyph by expanding its left glyph
- int i;
+ // move the glyph by expanding its left glyph but ignore dropped glyphs
+ int i, nLastUndropped = nMinGlyphPos - 1;
for( i = nMinGlyphPos; i < nStart; ++i )
- nDelta -= mpGlyphAdvances[ i ];
- mpGlyphAdvances[ i-1 ] += nDelta;
+ {
+ if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
+ {
+ nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
+ nLastUndropped = i;
+ }
+ }
+ if (nLastUndropped >= nMinGlyphPos)
+ {
+ mpGlyphAdvances[ nLastUndropped ] += nDelta;
+ if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
+ }
+ else
+ {
+ pVI->mnXOffset += nDelta;
+ }
}
else
{
@@ -2066,11 +2093,18 @@ void UniscribeLayout::DropGlyph( int nStartx8 )
--nStart;
else // nStart<=0 for first visible glyph
{
- const VisualItem* pVI = mpVisualItems;
+ VisualItem* pVI = mpVisualItems;
for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
if( GetItemSubrange( *pVI, nStart, nDummy ) )
break;
DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" );
+ int nOffset = 0;
+ int j = pVI->mnMinGlyphPos;
+ while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
+ if (j == nStart)
+ {
+ pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
+ }
}
mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
@@ -2127,11 +2161,12 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ )
}
// handle dropped glyphs at start of visual item
- int nEndGlyphPos;
- GetItemSubrange( rVI, i, nEndGlyphPos );
+ int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
+ GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
+ i = nMinGlyphPos;
while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) )
{
- rVI.mnXOffset += pGlyphWidths[ i ];
+ //rVI.mnXOffset += pGlyphWidths[ i ];
rVI.mnMinGlyphPos = ++i;
}
@@ -2141,6 +2176,17 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ )
rVI.mnEndGlyphPos = 0;
continue;
}
+ // If there are still glyphs in the cluster and mnMinGlyphPos
+ // has changed then we need to remove the dropped glyphs at start
+ // to correct logClusters, which is unsigned and relative to the
+ // item start.
+ if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
+ {
+ // drop any glyphs in the visual item outside the range
+ for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
+ mpOutGlyphs[ i ] = cDroppedGlyph;
+ rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
+ }
// handle dropped glyphs in the middle of visual item
for(; i < nEndGlyphPos; ++i )
@@ -2157,9 +2203,10 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ )
mpGlyphAdvances[ j ] = mpGlyphAdvances[ i ];
if( mpJustifications )
mpJustifications[ j ] = mpJustifications[ i ];
- int k = mpGlyphs2Chars[ i ];
+ const int k = mpGlyphs2Chars[ i ];
mpGlyphs2Chars[ j ] = k;
- mpLogClusters[ k ] = sal::static_int_cast<WORD>(j++);
+ const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
+ mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos);
}
rVI.mnEndGlyphPos = j;
@@ -2751,6 +2798,234 @@ bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
#endif // USE_UNISCRIBE
+#ifdef ENABLE_GRAPHITE
+
+class GraphiteLayoutWinImpl : public GraphiteLayout
+{
+public:
+ GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont)
+ throw()
+ : GraphiteLayout(font), mrFont(rFont) {};
+ virtual ~GraphiteLayoutWinImpl() throw() {};
+ virtual sal_GlyphId getKashidaGlyph(int & rWidth);
+private:
+ ImplWinFontEntry & mrFont;
+};
+
+sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth)
+{
+ rWidth = mrFont.GetMinKashidaWidth();
+ return mrFont.GetMinKashidaGlyph();
+}
+
+// This class uses the SIL Graphite engine to provide complex text layout services to the VCL
+// @author tse
+//
+class GraphiteWinLayout : public WinLayout
+{
+private:
+ mutable gr::WinFont mpFont;
+ grutils::GrFeatureParser * mpFeatures;
+ mutable GraphiteLayoutWinImpl maImpl;
+public:
+ GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE);
+
+ static bool IsGraphiteEnabledFont(HDC hDC) throw();
+
+ // used by upper layers
+ virtual bool LayoutText( ImplLayoutArgs& ); // first step of layout
+ virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting after fallback etc.
+ // virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+
+ // methods using string indexing
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
+ virtual long FillDXArray( long* pDXArray ) const;
+
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+
+ // methods using glyph indexing
+ virtual int GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
+ long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
+
+ // used by glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+ ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; };
+protected:
+ virtual void ReplaceDC(gr::Segment & segment) const;
+ virtual void RestoreDC(gr::Segment & segment) const;
+};
+
+bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw()
+{
+ return gr::WinFont::FontHasGraphiteTables(hDC);
+}
+
+GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw()
+ : WinLayout(hDC, rWFD, rWFE), mpFont(hDC),
+ maImpl(mpFont, rWFE)
+{
+ const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage );
+ rtl::OString name = rtl::OUStringToOString(
+ rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
+ if (nFeat > 0)
+ {
+ rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
+ mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr());
+ }
+ else
+ {
+ mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr());
+ }
+ maImpl.SetFeatures(mpFeatures);
+}
+
+void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const
+{
+ COLORREF color = GetTextColor(mhDC);
+ dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC);
+ SetTextColor(mhDC, color);
+}
+
+void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const
+{
+ dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC();
+}
+
+bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args)
+{
+ HFONT hUnRotatedFont;
+ if (args.mnOrientation)
+ {
+ // Graphite gets very confused if the font is rotated
+ LOGFONTW aLogFont;
+ ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
+ aLogFont.lfEscapement = 0;
+ aLogFont.lfOrientation = 0;
+ hUnRotatedFont = ::CreateFontIndirectW( &aLogFont);
+ ::SelectFont(mhDC, hUnRotatedFont);
+ }
+ WinLayout::AdjustLayout(args);
+ mpFont.replaceDC(mhDC);
+ maImpl.SetFontScale(WinLayout::mfFontScale);
+ //bool succeeded = maImpl.LayoutText(args);
+#ifdef GRCACHE
+ GrSegRecord * pSegRecord = NULL;
+ gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord);
+#else
+ gr::Segment * pSegment = maImpl.CreateSegment(args);
+#endif
+ bool bSucceeded = false;
+ if (pSegment)
+ {
+ // replace the DC on the font within the segment
+ ReplaceDC(*pSegment);
+ // create glyph vectors
+#ifdef GRCACHE
+ bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord);
+#else
+ bSucceeded = maImpl.LayoutGlyphs(args, pSegment);
+#endif
+ // restore original DC
+ RestoreDC(*pSegment);
+#ifdef GRCACHE
+ if (pSegRecord) pSegRecord->unlock();
+ else delete pSegment;
+#else
+ delete pSegment;
+#endif
+ }
+ mpFont.restoreDC();
+ if (args.mnOrientation)
+ {
+ // restore the rotated font
+ ::SelectFont(mhDC, mhFont);
+ ::DeleteObject(hUnRotatedFont);
+ }
+ return bSucceeded;
+}
+
+void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs)
+{
+ WinLayout::AdjustLayout(rArgs);
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray)
+ {
+ mrWinFontEntry.InitKashidaHandling(mhDC);
+ }
+ maImpl.AdjustLayout(rArgs);
+}
+
+void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const
+{
+ HFONT hOrigFont = DisableFontScaling();
+ HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).mhDC;
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ const int MAX_GLYPHS = 2;
+ sal_GlyphId glyphIntStr[MAX_GLYPHS];
+ WORD glyphWStr[MAX_GLYPHS];
+ int glyphIndex = 0;
+ Point aPos(0,0);
+ int nGlyphs = 0;
+ do
+ {
+ nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex);
+ if (nGlyphs < 1)
+ break;
+ std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
+ ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX,
+ NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
+ } while (nGlyphs);
+ if( hOrigFont )
+ DeleteFont( SelectFont( mhDC, hOrigFont ) );
+}
+
+int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ mpFont.replaceDC(mhDC);
+ int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor);
+ mpFont.restoreDC();
+ return nBreak;
+}
+
+long GraphiteWinLayout::FillDXArray( long* pDXArray ) const
+{
+ return maImpl.FillDXArray(pDXArray);
+}
+
+void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const
+{
+ maImpl.GetCaretPositions(nArraySize, pCaretXArray);
+}
+
+int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out,
+ ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const
+{
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index);
+}
+
+void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos )
+{
+ maImpl.MoveGlyph(glyph_idx, new_x_pos);
+}
+
+void GraphiteWinLayout::DropGlyph( int glyph_idx )
+{
+ maImpl.DropGlyph(glyph_idx);
+}
+
+void GraphiteWinLayout::Simplify( bool is_base )
+{
+ maImpl.Simplify(is_base);
+}
+#endif // ENABLE_GRAPHITE
// =======================================================================
SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
@@ -2766,6 +3041,11 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED)
&& (aUspModule || (bUspEnabled && InitUSP())) ) // CTL layout engine
{
+#ifdef ENABLE_GRAPHITE
+ if (rFontFace.SupportsGraphite())
+ pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
+ else
+#endif // ENABLE_GRAPHITE
// script complexity is determined in upper layers
pWinLayout = new UniscribeLayout( mhDC, rFontFace, rFontInstance );
// NOTE: it must be guaranteed that the WinSalGraphics lives longer than
@@ -2788,7 +3068,12 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
BYTE eCharSet = ANSI_CHARSET;
if( mpLogFont )
eCharSet = mpLogFont->lfCharSet;
- pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
+#ifdef ENABLE_GRAPHITE
+ if (rFontFace.SupportsGraphite())
+ pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
+ else
+#endif // ENABLE_GRAPHITE
+ pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
}
if( mfFontScale != 1.0 )