summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorJens-Heiner Rechtien <hr@openoffice.org>2009-01-05 15:33:41 +0000
committerJens-Heiner Rechtien <hr@openoffice.org>2009-01-05 15:33:41 +0000
commit347a1622743363ae11cd12bc00d5827c5c952f79 (patch)
treecec8eee1bab3c33c4154ed08dd3066ad55679f81 /vcl
parent50afe624b996edb05856bfe1be390639f458a88e (diff)
CWS-TOOLING: integrate CWS kashidafix
2008-12-15 15:31:40 +0100 hde r265507 : #i97098# 2008-12-15 15:30:52 +0100 hde r265506 : #i97098# 2008-12-10 14:08:07 +0100 fredrikh r265184 : i97098 2008-11-27 15:07:01 +0100 hdu r264493 : #i60594# only determine GetNextGlyphs() charpos if requested+available 2008-11-27 14:09:42 +0100 hdu r264487 : #i60594# simplify RTL-glyph-injection also for manual-cell-aligned cases 2008-11-26 13:25:08 +0100 fme r264379 : #i60594# Kashida fixes - syntax error 2008-11-26 13:16:22 +0100 hdu r264374 : #i60594# allow glyph injection even if there is not enough room if they can overlap 2008-11-25 16:40:20 +0100 hdu r264314 : #i60594# fix glyph-injection for PDF-export for usp>=1.6 2008-11-24 16:17:11 +0100 hdu r264254 : #i71804# adjust glyph-fallback usp-methods for new glyph-injection infrastructure 2008-11-24 16:15:30 +0100 hdu r264253 : #i71804# disable glyph-injection for glyph-fallback mixing 2008-11-20 08:29:15 +0100 fme r264027 : #i60594# Fix correction 2008-11-14 10:10:54 +0100 fme r263666 : CWS-TOOLING: rebase CWS kashidafix to trunk@263288 (milestone: DEV300:m35) 2008-10-30 16:35:30 +0100 fme r262834 : #i60594# migrate cws kashidafix to SVN.
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/vcl/outdev.hxx15
-rw-r--r--vcl/inc/vcl/outfont.hxx12
-rwxr-xr-xvcl/inc/vcl/sallayout.hxx4
-rw-r--r--vcl/source/gdi/outdev3.cxx59
-rwxr-xr-xvcl/source/gdi/sallayout.cxx7
-rw-r--r--vcl/win/inc/salgdi.h7
-rw-r--r--vcl/win/source/gdi/salgdi3.cxx18
-rwxr-xr-xvcl/win/source/gdi/winlayout.cxx425
8 files changed, 481 insertions, 66 deletions
diff --git a/vcl/inc/vcl/outdev.hxx b/vcl/inc/vcl/outdev.hxx
index 578eb2b787a9..98c096087a66 100644
--- a/vcl/inc/vcl/outdev.hxx
+++ b/vcl/inc/vcl/outdev.hxx
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: outdev.hxx,v $
- * $Revision: 1.11.28.1 $
+ * $Revision: 1.7.20.4 $
*
* This file is part of OpenOffice.org.
*
@@ -1032,6 +1032,19 @@ public:
xub_StrLen HasGlyphs( const Font& rFont, const String& rStr,
xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN ) const;
+ long GetMinKashida() const;
+ long GetMinKashida( const Font& rFont ) const;
+
+ // i60594
+ // validate kashida positions against the current font
+ // returns count of invalid kashida positions
+ xub_StrLen ValidateKashidas ( const String& rTxt,
+ xub_StrLen nIdx, xub_StrLen nLen,
+ xub_StrLen nKashCount, // number of suggested kashida positions (in)
+ const xub_StrLen* pKashidaPos, // suggested kashida positions (in)
+ xub_StrLen* pKashidaPosDropped // invalid kashida positions (out)
+ ) const;
+
USHORT GetBitCount() const;
BOOL GetTextIsRTL( const String&, xub_StrLen nIndex,
diff --git a/vcl/inc/vcl/outfont.hxx b/vcl/inc/vcl/outfont.hxx
index 44c0975cd8f2..86a5e59f6345 100644
--- a/vcl/inc/vcl/outfont.hxx
+++ b/vcl/inc/vcl/outfont.hxx
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: outfont.hxx,v $
- * $Revision: 1.6 $
+ * $Revision: 1.6.14.2 $
*
* This file is part of OpenOffice.org.
*
@@ -279,17 +279,25 @@ public:
void ImplInitAboveTextLineSize();
public: // TODO: hide members behind accessor methods
+ // font instance attributes from the font request
long mnWidth; // Reference Width
+ short mnOrientation; // Rotation in 1/10 degrees
+
+ // font metrics measured for the font instance
long mnAscent; // Ascent
long mnDescent; // Descent
long mnIntLeading; // Internal Leading
long mnExtLeading; // External Leading
int mnSlant; // Slant (Italic/Oblique)
+ long mnMinKashida; // Minimal width of kashida (Arabic)
+
+ // font attributes queried from the font instance
int meFamilyType; // Font Family Type
- short mnOrientation; // Rotation in 1/10 degrees
bool mbDevice; // Flag for Device Fonts
bool mbScalableFont;
bool mbKernableFont;
+
+ // font metrics that are usually derived from the measurements
long mnUnderlineSize; // Lineheight of Underline
long mnUnderlineOffset; // Offset from Underline to Baseline
long mnBUnderlineSize; // Hoehe von fetter Unterstreichung
diff --git a/vcl/inc/vcl/sallayout.hxx b/vcl/inc/vcl/sallayout.hxx
index 6e736de87526..d40dde9014bc 100755
--- a/vcl/inc/vcl/sallayout.hxx
+++ b/vcl/inc/vcl/sallayout.hxx
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: sallayout.hxx,v $
- * $Revision: 1.8 $
+ * $Revision: 1.8.54.1 $
*
* This file is part of OpenOffice.org.
*
@@ -206,6 +206,7 @@ public:
virtual long FillDXArray( sal_Int32* pDXArray ) const = 0;
virtual long GetTextWidth() const { return FillDXArray( NULL ); }
virtual void GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const = 0;
+ virtual bool IsKashidaPosValid ( int /*nCharPos*/ ) const { return true; } // i60594
// methods using glyph indexing
virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIdAry, Point& rPos, int&,
@@ -223,6 +224,7 @@ public:
virtual void MoveGlyph( int nStart, long nNewXPos ) = 0;
virtual void DropGlyph( int nStart ) = 0;
virtual void Simplify( bool bIsBase ) = 0;
+ virtual void DisableGlyphInjection( bool /*bDisable*/ ) {}
protected:
// used by layout engines
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
index 19a9778ebb04..60db5cc152c2 100644
--- a/vcl/source/gdi/outdev3.cxx
+++ b/vcl/source/gdi/outdev3.cxx
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: outdev3.cxx,v $
- * $Revision: 1.245 $
+ * $Revision: 1.240.14.5 $
*
* This file is part of OpenOffice.org.
*
@@ -3734,9 +3734,11 @@ void OutputDevice::ImplInitAboveTextLineSize()
ImplFontMetricData::ImplFontMetricData( const ImplFontSelectData& rFontSelData )
: ImplFontAttributes( rFontSelData )
{
+ // initialize the members provided by the font request
mnWidth = rFontSelData.mnWidth;
mnOrientation = sal::static_int_cast<short>(rFontSelData.mnOrientation);
+ // intialize the used font name
if( rFontSelData.mpFontData )
{
maName = rFontSelData.mpFontData->maName;
@@ -3753,12 +3755,15 @@ ImplFontMetricData::ImplFontMetricData( const ImplFontSelectData& rFontSelData )
mbKernableFont = false;
}
+ // reset metrics that are usually measured for the font instance
mnAscent = 0;
mnDescent = 0;
mnIntLeading = 0;
mnExtLeading = 0;
mnSlant = 0;
+ mnMinKashida = 0;
+ // reset metrics that are usually derived from the measurements
mnUnderlineSize = 0;
mnUnderlineOffset = 0;
mnBUnderlineSize = 0;
@@ -7557,6 +7562,58 @@ FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
// -----------------------------------------------------------------------
+long OutputDevice::GetMinKashida() const
+{
+ DBG_TRACE( "OutputDevice::GetMinKashida()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ if( mbNewFont && !ImplNewFont() )
+ return 0;
+
+ ImplFontEntry* pEntry = mpFontEntry;
+ ImplFontMetricData* pMetric = &(pEntry->maMetric);
+ return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
+}
+// -----------------------------------------------------------------------
+
+long OutputDevice::GetMinKashida( const Font& rFont ) const
+{
+ // select font, query Kashida, select original font again
+ Font aOldFont = GetFont();
+ const_cast<OutputDevice*>(this)->SetFont( rFont );
+ long aKashida = GetMinKashida();
+ const_cast<OutputDevice*>(this)->SetFont( aOldFont );
+ return aKashida;
+}
+
+// -----------------------------------------------------------------------
+xub_StrLen OutputDevice::ValidateKashidas ( const String& rTxt,
+ xub_StrLen nIdx, xub_StrLen nLen,
+ xub_StrLen nKashCount,
+ const xub_StrLen* pKashidaPos,
+ xub_StrLen* pKashidaPosDropped ) const
+{
+ // do layout
+ SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
+ if( !pSalLayout )
+ return 0;
+ xub_StrLen nDropped = 0;
+ for( int i = 0; i < nKashCount; ++i )
+ {
+ if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
+ {
+ pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
+ ++nDropped;
+ }
+ }
+ pSalLayout->Release();
+ return nDropped;
+}
+
+
+
+// -----------------------------------------------------------------------
+
+
// TODO: best is to get rid of this method completely
ULONG OutputDevice::GetKerningPairCount() const
{
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 9e02b42aa789..9dd0bfdc0197 100755
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -1715,6 +1715,9 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
}
mpLayouts[n]->AdjustLayout( aMultiArgs );
+ // disable glyph-injection for glyph-fallback SalLayout iteration
+ mpLayouts[n]->DisableGlyphInjection( true );
+
// remove unused parts of component
if( n > 0 )
{
@@ -1893,6 +1896,10 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
}
mpLayouts[0]->Simplify( true );
+
+ // reenable glyph-injection
+ for( n = 0; n < mnLevel; ++n )
+ mpLayouts[n]->DisableGlyphInjection( false );
}
// -----------------------------------------------------------------------
diff --git a/vcl/win/inc/salgdi.h b/vcl/win/inc/salgdi.h
index cea6fc5dbbb3..f9d4681e0e6e 100644
--- a/vcl/win/inc/salgdi.h
+++ b/vcl/win/inc/salgdi.h
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: salgdi.h,v $
- * $Revision: 1.32 $
+ * $Revision: 1.30.20.5 $
*
* This file is part of OpenOffice.org.
*
@@ -52,7 +52,7 @@ class ImplFontAttrCache;
#define PALRGB_TO_RGB(nPalRGB) ((nPalRGB)&0x00ffffff)
// win32 platform specific options. Move them to the PMK file?
-#define USE_UNISCRIBE
+
#define GCP_KERN_HACK
#define GNG_VERT_HACK
@@ -78,6 +78,7 @@ public:
bool IsGlyphApiDisabled() const { return mbDisableGlyphApi; }
bool SupportsKorean() const { return mbHasKoreanRange; }
bool SupportsCJK() const { return mbHasCJKSupport; }
+ bool SupportsArabic() const { return mbHasArabicSupport; }
bool AliasSymbolsHigh() const { return mbAliasSymbolsHigh; }
bool AliasSymbolsLow() const { return mbAliasSymbolsLow; }
@@ -96,6 +97,7 @@ private:
mutable bool mbDisableGlyphApi;
mutable bool mbHasKoreanRange;
mutable bool mbHasCJKSupport;
+ mutable bool mbHasArabicSupport;
mutable ImplFontCharMap* mpUnicodeMap;
mutable const Ucs2SIntMap* mpEncodingVector;
@@ -337,6 +339,7 @@ public:
bool bVertical,
Int32Vector& rWidths,
Ucs2UIntMap& rUnicodeEnc );
+ virtual int GetMinKashidaWidth();
virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& );
diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx
index 4511ff0c3fef..de08f1c25b50 100644
--- a/vcl/win/source/gdi/salgdi3.cxx
+++ b/vcl/win/source/gdi/salgdi3.cxx
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: salgdi3.cxx,v $
- * $Revision: 1.97 $
+ * $Revision: 1.95.14.5 $
*
* This file is part of OpenOffice.org.
*
@@ -33,6 +33,7 @@
#include <string.h>
#include <malloc.h>
+#include <osl/module.h>
#include <tools/svwin.h>
#include <rtl/logfile.hxx>
#include <rtl/tencinfo.h>
@@ -72,14 +73,13 @@
#include <tools/stream.hxx>
#include <rtl/bootstrap.hxx>
-
#include <vector>
#include <set>
-#ifndef INCLUDED_MAP
+//#ifndef INCLUDED_MAP
#include <map>
-#define INCLUDED_MAP
-#endif
+//#define INCLUDED_MAP
+//#endif
static const int MAXFONTHEIGHT = 2048;
@@ -111,6 +111,8 @@ static bool bImplSalCourierNew = false;
// =======================================================================
+// -----------------------------------------------------------------------
+
// TODO: also support temporary TTC font files
typedef std::map< String, ImplDevFontAttributes > FontAttrMap;
@@ -806,6 +808,7 @@ ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
mbDisableGlyphApi( false ),
mbHasKoreanRange( false ),
mbHasCJKSupport( false ),
+ mbHasArabicSupport ( false ),
mbAliasSymbolsLow( false ),
mbAliasSymbolsHigh( false ),
mnId( 0 ),
@@ -936,7 +939,8 @@ void ImplWinFontData::ReadOs2Table( HDC hDC ) const
mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
| (ulUnicodeRange2 & 0x01100000);
- }
+ mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
+ }
}
// -----------------------------------------------------------------------
@@ -1521,6 +1525,8 @@ void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
if( mpWinFontData[0]->SupportsKorean() )
pMetric->mnDescent += pMetric->mnExtLeading;
}
+
+ pMetric->mnMinKashida = GetMinKashidaWidth();
}
// -----------------------------------------------------------------------
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index 36cb76800eac..26cdc9cd7587 100755
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: winlayout.cxx,v $
- * $Revision: 1.115 $
+ * $Revision: 1.113.6.9 $
*
* This file is part of OpenOffice.org.
*
@@ -54,6 +54,7 @@
// for GetMirroredChar
#include <vcl/svapp.hxx>
+#define USE_UNISCRIBE
#ifdef USE_UNISCRIBE
#include <Usp10.h>
#include <ShLwApi.h>
@@ -102,8 +103,15 @@ private:
public:
int GetCachedGlyphWidth( int nCharCode ) const;
void CacheGlyphWidth( int nCharCode, int nCharWidth );
+
+ bool InitKashidaHandling( HDC );
+ int GetMinKashidaWidth() const { return mnMinKashidaWidth; }
+ int GetMinKashidaGlyph() const { return mnMinKashidaGlyph; }
+
private:
IntMap maWidthMap;
+ mutable int mnMinKashidaWidth;
+ mutable int mnMinKashidaGlyph;
};
// -----------------------------------------------------------------------
@@ -545,6 +553,8 @@ bool SimpleWinLayout::LayoutText( ImplLayoutArgs& rArgs )
}
// scale layout metrics if needed
+ // TODO: does it make the code more simple if the metric scaling
+ // is moved to the methods that need metric scaling (e.g. FillDXArray())?
if( mfFontScale != 1.0 )
{
mnWidth = (long)(mnWidth * mfFontScale);
@@ -886,7 +896,7 @@ void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
nOldWidth += mpGlyphAdvances[ j ];
int nDiff = nOldWidth - pDXArray[ i ];
- // disabled because of #104768#
+ // disabled because of #104768#
// works great for static text, but problems when typing
// if( nDiff>+1 || nDiff<-1 )
// only bother with changing anything when something moved
@@ -1046,11 +1056,15 @@ public:
//long mnPixelWidth;
int mnXOffset;
ABC maABCWidths;
+ bool mbHasKashidas;
public:
bool IsEmpty() const { return (mnEndGlyphPos <= 0); }
+ bool HasKashidas() const { return mbHasKashidas; }
};
+// -----------------------------------------------------------------------
+
class UniscribeLayout : public WinLayout
{
public:
@@ -1065,11 +1079,13 @@ public:
virtual long FillDXArray( long* pDXArray ) const;
virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+ virtual bool IsKashidaPosValid ( int nCharPos ) const;
// for glyph+font+script fallback
virtual void MoveGlyph( int nStart, long nNewXPos );
virtual void DropGlyph( int nStart );
virtual void Simplify( bool bIsBase );
+ virtual void DisableGlyphInjection( bool bDisable ) { mbDisableGlyphInjection = bDisable; }
protected:
virtual ~UniscribeLayout();
@@ -1103,6 +1119,15 @@ private:
GOFFSET* mpGlyphOffsets; // glyph offsets to the "naive" layout
SCRIPT_VISATTR* mpVisualAttrs; // glyph visual attributes
mutable int* mpGlyphs2Chars; // map from absolute_glyph_pos to absolute_char_pos
+
+ // kashida stuff
+ void InitKashidaHandling();
+ void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos );
+ bool KashidaWordFix( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos );
+
+ int mnMinKashidaWidth;
+ int mnMinKashidaGlyph;
+ bool mbDisableGlyphInjection;
};
// -----------------------------------------------------------------------
@@ -1243,21 +1268,23 @@ static bool InitUSP()
UniscribeLayout::UniscribeLayout( HDC hDC,
const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
: WinLayout( hDC, rWinFontData, rWinFontEntry ),
- mnItemCount(0),
+ mnItemCount( 0 ),
mpScriptItems( NULL ),
mpVisualItems( NULL ),
mpLogClusters( NULL ),
mpCharWidths( NULL ),
mnCharCapacity( 0 ),
mnSubStringMin( 0 ),
- mnGlyphCapacity(0),
+ mnGlyphCapacity( 0 ),
mnGlyphCount( 0 ),
mpOutGlyphs( NULL ),
mpGlyphAdvances( NULL ),
mpJustifications( NULL ),
mpGlyphOffsets( NULL ),
mpVisualAttrs( NULL ),
- mpGlyphs2Chars( NULL )
+ mpGlyphs2Chars( NULL ),
+ mnMinKashidaGlyph( 0 ),
+ mbDisableGlyphInjection( false )
{}
// -----------------------------------------------------------------------
@@ -1669,6 +1696,8 @@ bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
}
// scale layout metrics if needed
+ // TODO: does it make the code more simple if the metric scaling
+ // is moved to the methods that need metric scaling (e.g. FillDXArray())?
if( mfFontScale != 1.0 )
{
mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
@@ -1757,9 +1786,16 @@ bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
// -----------------------------------------------------------------------
int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
- int& nStart, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const
+ int& nStartx8, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const
{
- if( nStart > mnGlyphCount ) // nStart>MAX means no more glyphs
+ // HACK to allow fake-glyph insertion (e.g. for kashidas)
+ // TODO: use iterator idiom instead of GetNextGlyphs(...)
+ // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
+ int nSubIter = nStartx8 & 0xff;
+ int nStart = nStartx8 >> 8;
+
+ // check the glyph iterator
+ if( nStart > mnGlyphCount ) // nStart>MAX means no more glyphs
return 0;
// find the visual item for the nStart glyph position
@@ -1788,9 +1824,9 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
}
// after the last visual item there are no more glyphs
- if( nItem >= mnItemCount )
+ if( (nItem >= mnItemCount) || (nStart < 0) )
{
- nStart = mnGlyphCount + 1;
+ nStartx8 = (mnGlyphCount + 1) << 8;
return 0;
}
@@ -1809,7 +1845,10 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
DBG_ASSERT( bRC, "USPLayout::GNG GISR() returned false" );
if( !bRC )
+ {
+ nStartx8 = (mnGlyphCount + 1) << 8;
return 0;
+ }
// make sure nStart is inside the range of relevant glyphs
if( nStart < nMinGlyphPos )
@@ -1880,16 +1919,72 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
int nCount = 0;
while( nCount < nLen )
{
+ // prepare return values
+ sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
+ int nGlyphWidth = pGlyphWidths[ nStart ];
+ int nCharPos = -1; // no need to determine charpos
+ if( mpGlyphs2Chars ) // unless explicitly requested+provided
+ nCharPos = mpGlyphs2Chars[ nStart ];
+
+ // inject kashida glyphs if needed
+ if( !mbDisableGlyphInjection
+ && mpJustifications
+ && mnMinKashidaWidth
+ && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
+ {
+ // prepare draw position adjustment
+ int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
+ // calculate space available for the injected glyphs
+ nGlyphWidth = mpGlyphAdvances[ nStart ];
+ const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
+ const int nToFillWidth = nExtraWidth - nExtraOfs;
+ if( (4*nToFillWidth >= mnMinKashidaWidth) // prevent glyph-injection if there is no room
+ || ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
+ {
+ // handle if there is not sufficient room for a full glyph
+ if( nToFillWidth < mnMinKashidaWidth )
+ {
+ // overlap it with the previously injected glyph if possible
+ int nOverlap = mnMinKashidaWidth - nToFillWidth;
+ // else overlap it with both neighboring glyphs
+ if( nSubIter <= 1 )
+ nOverlap /= 2;
+ nExtraOfs -= nOverlap;
+ }
+ nGlyphWidth = mnMinKashidaWidth;
+ aGlyphId = mnMinKashidaGlyph;
+ nCharPos = -1;
+ }
+ else
+ {
+ nExtraOfs += nToFillWidth; // at right of cell
+ nSubIter = 0; // done with glyph injection
+ }
+ if( !bManualCellAlign )
+ nExtraOfs -= nExtraWidth; // adjust for right-aligned cells
+
+ // adjust the draw position for the injected-glyphs case
+ if( nExtraOfs )
+ {
+ aRelativePos.X() += nExtraOfs;
+ rPos = GetDrawPosition( aRelativePos );
+ }
+ }
+
// update return values
- *(pGlyphs++) = mpOutGlyphs[ nStart ];
+ *(pGlyphs++) = aGlyphId;
if( pGlyphAdvances )
- *(pGlyphAdvances++) = pGlyphWidths[ nStart ];
+ *(pGlyphAdvances++) = nGlyphWidth;
if( pCharPosAry )
- *(pCharPosAry++) = mpGlyphs2Chars[ nStart ];
+ *(pCharPosAry++) = nCharPos;
// increment counter of returned glyphs
++nCount;
+ // reduce code complexity by returning early in glyph-injection case
+ if( nSubIter != 0 )
+ break;
+
// stop after the last visible glyph in this visual item
if( ++nStart >= nEndGlyphPos )
{
@@ -1899,7 +1994,7 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
// RTL-justified glyph positioning is not easy
// simplify the code by just returning only one glyph at a time
- if( mpJustifications && !bManualCellAlign && pVI->mpScriptItem->a.fRTL )
+ if( mpJustifications && pVI->mpScriptItem->a.fRTL )
break;
// stop when the x-position of the next glyph is unexpected
@@ -1914,13 +2009,16 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
}
++nStart;
+ nStartx8 = (nStart << 8) + nSubIter;
return nCount;
}
// -----------------------------------------------------------------------
-void UniscribeLayout::MoveGlyph( int nStart, long nNewXPos )
+void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
{
+ DBG_ASSERT( (nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
+ int nStart = nStartx8 >> 8;
if( nStart > mnGlyphCount )
return;
@@ -1940,14 +2038,9 @@ void UniscribeLayout::MoveGlyph( int nStart, long nNewXPos )
for( int i = mnItemCount; --i >= 0; ++pVI )
if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
break;
- #if OSL_DEBUG_LEVEL > 0
- bool bRC =
- #endif
- GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
+ bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
+ (void)bRC; // avoid var-not-used warning
DBG_ASSERT( bRC, "USPLayout::MoveG GISR() returned false" );
- #if OSL_DEBUG_LEVEL > 0
- (void)bRC;
- #endif
}
long nDelta = nNewXPos - pVI->mnXOffset;
@@ -1968,13 +2061,15 @@ void UniscribeLayout::MoveGlyph( int nStart, long nNewXPos )
// -----------------------------------------------------------------------
-void UniscribeLayout::DropGlyph( int nStart )
+void UniscribeLayout::DropGlyph( int nStartx8 )
{
+ DBG_ASSERT( (nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
+ int nStart = nStartx8 >> 8;
DBG_ASSERT( nStart<=mnGlyphCount, "USPLayout::MoveG nStart overflow" );
if( nStart > 0 ) // nStart>0 means absolute glyph pos + 1
--nStart;
- else // if( !nStart ) // nStart==0 for first visible glyph
+ else // nStart<=0 for first visible glyph
{
const VisualItem* pVI = mpVisualItems;
for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
@@ -2336,19 +2431,25 @@ void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
|| (rVisualItem.mnEndCharPos <= mnMinCharPos) )
continue;
- bool bHasKashida = false;
+ // if needed prepare special handling for arabic justification
+ rVisualItem.mbHasKashidas = false;
if( rVisualItem.mpScriptItem->a.fRTL )
{
for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
- if ( (1U << mpVisualAttrs[i].uJustification) & 0x7F89 ) // any Arabic justification ?
- {
- // yes
- bHasKashida = true;
+ if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF89 ) // any Arabic justification ?
+ { // the last SCRIPT_JUSTIFY_xxx
+ // yes // == 15 (usp 1.6)
+ rVisualItem.mbHasKashidas = true;
+ // so prepare for kashida handling
+ InitKashidaHandling();
break;
}
- if ( bHasKashida )
+
+ if( rVisualItem.HasKashidas() )
for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
{
+ // TODO: check if we still need this hack after correction of kashida placing?
+ // (i87688): apparently yes, we still need it!
if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE )
// usp decided that justification can't be applied here
// but maybe our Kashida algorithm thinks differently.
@@ -2363,7 +2464,6 @@ void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
}
}
-
// convert virtual charwidths to glyph justification values
HRESULT nRC = (*pScriptApplyLogicalWidth)(
mpCharWidths + rVisualItem.mnMinCharPos,
@@ -2383,24 +2483,23 @@ void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
break;
}
- // TODO: for kashida justification
- // check the widths which are added to mpJustification
- // if added width is smaller than iKashidaWidth returned by
- // ScriptGetFontProperties, do something (either enlarge to
- // iKashidaWidth, or reduce to original width).
- // Need to think of a way to compensate the change in overall
- // width.
-
// to prepare for the next visual item
// update nXOffset to the next items position
// before the mpJustifications[] array gets modified
int nMinGlyphPos, nEndGlyphPos;
if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
+ {
for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
nXOffset += mpJustifications[ i ];
+ if( rVisualItem.mbHasKashidas )
+ KashidaItemFix( nMinGlyphPos, nEndGlyphPos );
+ }
+
+ // workaround needed for older USP versions:
// right align the justification-adjusted glyphs in their cells for RTL-items
- if( bManualCellAlign && rVisualItem.mpScriptItem->a.fRTL && !bHasKashida )
+ // unless the right alignment is done by inserting kashidas
+ if( bManualCellAlign && rVisualItem.mpScriptItem->a.fRTL && !rVisualItem.HasKashidas() )
{
for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
{
@@ -2417,17 +2516,164 @@ void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
// -----------------------------------------------------------------------
+void UniscribeLayout::InitKashidaHandling()
+{
+ if( mnMinKashidaGlyph != 0 ) // already initialized
+ return;
+
+ mrWinFontEntry.InitKashidaHandling( mhDC );
+ mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth());
+ mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph();
+}
+
+// adjust the kashida placement matching to the WriterEngine
+void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos )
+{
+ // workaround needed for all known USP versions:
+ // ApplyLogicalWidth does not match ScriptJustify behaviour
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ {
+ // check for vowels
+ if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ])
+ && (1U << mpVisualAttrs[i].uJustification) & 0xFF89 )
+ {
+ // vowel, we do it like ScriptJustify does
+ // the vowel gets the extra width
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ mpJustifications [ i ] = mpGlyphAdvances [ i ];
+ mpJustifications [ i - 1 ] += nSpaceAdded;
+ }
+ }
+
+ // redistribute the widths for kashidas
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; )
+ KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i );
+}
+
+bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos )
+{
+ // doing pixel work within a word.
+ // sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
+
+ // find the next kashida
+ int nMinPos = *pnCurrentPos;
+ int nMaxPos = *pnCurrentPos;
+ for( int i = nMaxPos; i < nEndGlyphPos; ++i )
+ {
+ if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK)
+ && (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) )
+ break;
+ nMaxPos = i;
+ }
+ *pnCurrentPos = nMaxPos + 1;
+ if( nMinPos == nMaxPos )
+ return false;
+
+ // calculate the available space for an extra kashida
+ long nMaxAdded = 0;
+ int nKashPos = -1;
+ for( int i = nMaxPos; i >= nMinPos; --i )
+ {
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ if( nSpaceAdded > nMaxAdded )
+ {
+ nKashPos = i;
+ nMaxAdded = nSpaceAdded;
+ }
+ }
+
+ // return early if there is no need for an extra kashida
+ if ( nMaxAdded <= 0 )
+ return false;
+ // return early if there is not enough space for an extra kashida
+ if( 2*nMaxAdded < mnMinKashidaWidth )
+ return false;
+
+ // redistribute the extra spacing to the kashida position
+ for( int i = nMinPos; i <= nMaxPos; ++i )
+ {
+ if( i == nKashPos )
+ continue;
+ // everything else should not have extra spacing
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ if( nSpaceAdded > 0 )
+ {
+ mpJustifications[ i ] -= nSpaceAdded;
+ mpJustifications[ nKashPos ] += nSpaceAdded;
+ }
+ }
+
+ // check if we fulfill minimal kashida width
+ long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ];
+ if( nSpaceAdded < mnMinKashidaWidth )
+ {
+ // ugly: steal some pixels
+ long nSteal = 1;
+ if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos)))
+ nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos);
+ for( int i = nMinPos; i <= nMaxPos; ++i )
+ {
+ if( i == nKashPos )
+ continue;
+ nSteal = Min( mnMinKashidaWidth - nSpaceAdded, nSteal );
+ if ( nSteal > 0 )
+ {
+ mpJustifications [ i ] -= nSteal;
+ mpJustifications [ nKashPos ] += nSteal;
+ nSpaceAdded += nSteal;
+ }
+ if( nSpaceAdded >= mnMinKashidaWidth )
+ return true;
+ }
+ }
+
+ // blank padding
+ long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded;
+ if( nSpaceMissing > 0 )
+ {
+ // inner glyph: distribute extra space evenly
+ if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) )
+ {
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ long nHalfSpace = nSpaceMissing / 2;
+ mpJustifications [ nMinPos - 1 ] -= nHalfSpace;
+ mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace;
+ }
+ // rightmost: left glyph gets extra space
+ else if( nMinPos > nMinGlyphPos )
+ {
+ mpJustifications [ nMinPos - 1 ] -= nSpaceMissing;
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ }
+ // leftmost: right glyph gets extra space
+ else if( nMaxPos < nEndGlyphPos - 1 )
+ {
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing;
+ }
+ else
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
void UniscribeLayout::Justify( long nNewWidth )
{
long nOldWidth = 0;
int i;
for( i = mnMinCharPos; i < mnEndCharPos; ++i )
nOldWidth += mpCharWidths[ i ];
+ if( nOldWidth <= 0 )
+ return;
- nNewWidth *= mnUnitsPerPixel;
+ nNewWidth *= mnUnitsPerPixel; // convert into font units
if( nNewWidth == nOldWidth )
return;
- double fStretch = (double)nNewWidth / nOldWidth;
+ // prepare to distribute the extra width evenly among the visual items
+ const double fStretch = (double)nNewWidth / nOldWidth;
// initialize justifications array
mpJustifications = new int[ mnGlyphCapacity ];
@@ -2451,18 +2697,12 @@ void UniscribeLayout::Justify( long nNewWidth )
nItemWidth += mpCharWidths[ i ];
nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5);
- SCRIPT_FONTPROPERTIES aFontProperties;
- int nMinKashida = 1;
- HRESULT nRC = (*pScriptGetFontProperties)( mhDC, &rScriptCache, &aFontProperties );
- if( !nRC )
- nMinKashida = aFontProperties.iKashidaWidth;
-
- nRC = (*pScriptJustify) (
+ HRESULT nRC = (*pScriptJustify) (
mpVisualAttrs + rVisualItem.mnMinGlyphPos,
mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
nItemWidth,
- nMinKashida,
+ mnMinKashidaWidth,
mpJustifications + rVisualItem.mnMinGlyphPos );
rVisualItem.mnXOffset = nXOffset;
@@ -2471,6 +2711,45 @@ void UniscribeLayout::Justify( long nNewWidth )
}
}
+// -----------------------------------------------------------------------
+
+bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
+{
+ // we have to find the visual item first since the mpLogClusters[]
+ // needed to find the cluster start is relative to to the visual item
+ int nMinGlyphIndex = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ if( (nCharPos >= rVisualItem.mnMinCharPos)
+ && (nCharPos < rVisualItem.mnEndCharPos) )
+ {
+ nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
+ break;
+ }
+ }
+ // Invalid char pos or leftmost glyph in visual item
+ if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] )
+ return false;
+
+// This test didn't give the expected results
+/* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
+ // two chars, one glyph
+ return false;*/
+
+ const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex;
+ if( nGlyphPos <= 0 )
+ return true;
+ // justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
+ // and not SCRIPT_JUSTIFY_ARABIC_BLANK
+ // special case: glyph to the left is vowel (no advance width)
+ if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK
+ || ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE
+ && mpGlyphAdvances [ nGlyphPos-1 ] ))
+ return false;
+ return true;
+}
+
#endif // USE_UNISCRIBE
// =======================================================================
@@ -2519,13 +2798,26 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
return pWinLayout;
}
+// -----------------------------------------------------------------------
+
+int WinSalGraphics::GetMinKashidaWidth()
+{
+ if( !mpWinFontEntry[0] )
+ return 0;
+ mpWinFontEntry[0]->InitKashidaHandling( mhDC );
+ int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth());
+ return nMinKashida;
+}
+
// =======================================================================
ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD )
-: ImplFontEntry( rFSD ),
- maWidthMap( 512 ),
- mpKerningPairs( NULL ),
- mnKerningPairs( -1 )
+: ImplFontEntry( rFSD )
+, maWidthMap( 512 )
+, mpKerningPairs( NULL )
+, mnKerningPairs( -1 )
+, mnMinKashidaWidth( -1 )
+, mnMinKashidaGlyph( -1 )
{
#ifdef USE_UNISCRIBE
maScriptCache = NULL;
@@ -2582,6 +2874,33 @@ int ImplWinFontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
return nKernAmount;
}
+// -----------------------------------------------------------------------
+
+bool ImplWinFontEntry::InitKashidaHandling( HDC hDC )
+{
+ if( mnMinKashidaWidth >= 0 ) // already cached?
+ return mnMinKashidaWidth;
+
+ // initialize the kashida width
+ mnMinKashidaWidth = 0;
+ mnMinKashidaGlyph = 0;
+#ifdef USE_UNISCRIBE
+ if (aUspModule || (bUspEnabled && InitUSP()))
+ {
+ SCRIPT_FONTPROPERTIES aFontProperties;
+ aFontProperties.cBytes = sizeof (aFontProperties);
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ HRESULT nRC = (*pScriptGetFontProperties)( hDC, &rScriptCache, &aFontProperties );
+ if( nRC != 0 )
+ return false;
+ mnMinKashidaWidth = aFontProperties.iKashidaWidth;
+ mnMinKashidaGlyph = aFontProperties.wgKashida;
+ }
+#endif // USE_UNISCRIBE
+
+ return true;
+}
+
// =======================================================================
ImplFontData* ImplWinFontData::Clone() const