summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Hung <marklh9@gmail.com>2015-10-21 22:34:08 +0800
committerCaolán McNamara <caolanm@redhat.com>2015-11-10 11:48:53 +0000
commitf5ed3a29e995152b80bf1adc888094d735a0882c (patch)
tree741fe067abd30c6b95305432408f182d9111c124
parent610e6fddbc19dd2ac23b6a6cf4d8cbfb0dcf589a (diff)
tdf#81144 Chinese full-width punctuation does not align properly
Ideographic fullstop and comma in most Chinese fonts are centered, while those in Japanese fonts align closer to the left. Original compression algorithm trimed right side of the punctuation, making fullwidth fullstop or comma in Chinese font visually unbalanced. In worst case, it crowds together with the followed compressed punctuation. This patch fix the situation in the folowing way 1) make compression less stronger. 2) Trim space according to glyph bearing to font height ratio. 3) fix a memory access violation issue Reviewed-on: https://gerrit.libreoffice.org/19517 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Norbert Thiebaud <nthiebaud@gmail.com> Conflicts: sw/source/core/txtnode/fntcache.cxx Change-Id: Icff215064e6c442fd36eac8e01b01fb6acb27594 Reviewed-on: https://gerrit.libreoffice.org/19764 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--include/vcl/metric.hxx1
-rw-r--r--sw/source/core/inc/scriptinfo.hxx3
-rw-r--r--sw/source/core/text/porlay.cxx12
-rw-r--r--sw/source/core/txtnode/fntcache.cxx24
-rw-r--r--vcl/inc/impfont.hxx3
-rw-r--r--vcl/inc/outfont.hxx1
-rw-r--r--vcl/source/gdi/metric.cxx5
-rw-r--r--vcl/source/outdev/font.cxx19
8 files changed, 55 insertions, 13 deletions
diff --git a/include/vcl/metric.hxx b/include/vcl/metric.hxx
index e2049696e500..1f43dcd96929 100644
--- a/include/vcl/metric.hxx
+++ b/include/vcl/metric.hxx
@@ -72,6 +72,7 @@ public:
long GetExtLeading() const;
long GetLineHeight() const;
long GetSlant() const;
+ bool IsFullstopCentered() const;
FontMetric& operator=( const FontMetric& rMetric );
bool operator==( const FontMetric& rMetric ) const;
diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx
index 5ad950fd4d8b..bf3c9327fa36 100644
--- a/sw/source/core/inc/scriptinfo.hxx
+++ b/sw/source/core/inc/scriptinfo.hxx
@@ -37,7 +37,7 @@ typedef std::list< sal_Int32 > PositionList;
class SwScriptInfo
{
public:
- enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE };
+ enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE, SPECIAL_MIDDLE};
private:
//! Records a single change in script type.
@@ -255,6 +255,7 @@ public:
// modifies the kerning array according to a given compress value
long Compress( long* pKernArray, sal_Int32 nIdx, sal_Int32 nLen,
const sal_uInt16 nCompress, const sal_uInt16 nFontHeight,
+ const bool bCentered,
Point* pPoint = NULL ) const;
/** Performs a kashida justification on the kerning array
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index 4e41c32cde8e..c7afcaf5930a 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -874,12 +874,15 @@ void SwScriptInfo::InitScriptInfo( const SwTextNode& rNode, bool bRTL )
eState = SPECIAL_LEFT;
break;
// Right punctuation found
- case 0x3001: case 0x3002: case 0x3009: case 0x300B:
+ case 0x3009: case 0x300B:
case 0x300D: case 0x300F: case 0x3011: case 0x3015:
case 0x3017: case 0x3019: case 0x301B: case 0x301E:
case 0x301F:
eState = SPECIAL_RIGHT;
break;
+ case 0x3001: case 0x3002: // Fullstop or comma
+ eState = SPECIAL_MIDDLE ;
+ break;
default:
eState = ( 0x3040 <= cChar && 0x3100 > cChar ) ? KANA : NONE;
}
@@ -1509,6 +1512,7 @@ size_t SwScriptInfo::HasKana( sal_Int32 nStart, const sal_Int32 nLen ) const
long SwScriptInfo::Compress( long* pKernArray, sal_Int32 nIdx, sal_Int32 nLen,
const sal_uInt16 nCompress, const sal_uInt16 nFontHeight,
+ bool bCenter,
Point* pPoint ) const
{
SAL_WARN_IF( !nCompress, "sw.core", "Compression without compression?!" );
@@ -1571,7 +1575,7 @@ long SwScriptInfo::Compress( long* pKernArray, sal_Int32 nIdx, sal_Int32 nLen,
long nMove = 0;
if( SwScriptInfo::KANA != nType )
{
- nLast /= 20000;
+ nLast /= 24000;
if( pPoint && SwScriptInfo::SPECIAL_LEFT == nType )
{
if( nI )
@@ -1582,12 +1586,14 @@ long SwScriptInfo::Compress( long* pKernArray, sal_Int32 nIdx, sal_Int32 nLen,
nLast = 0;
}
}
+ else if( bCenter && SwScriptInfo::SPECIAL_MIDDLE == nType )
+ nMove = nLast / 2;
}
else
nLast /= 100000;
nSub -= nLast;
nLast = pKernArray[ nI ];
- if( nMove )
+ if( nI && nMove )
pKernArray[ nI - 1 ] += nMove;
pKernArray[ nI++ ] -= nSub;
++nIdx;
diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
index 3d6b35bcc516..b159121ddf38 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -629,6 +629,12 @@ static bool lcl_IsMonoSpaceFont( const vcl::RenderContext& rOut )
return nWidth1 == nWidth2;
}
+static bool lcl_IsFullstopCentered( const vcl::RenderContext& rOut )
+{
+ const FontMetric aMetric( rOut.GetFontMetric() );
+ return aMetric.IsFullstopCentered() ;
+}
+
/* This helper structure (SwForbidden) contains the already marked parts of the string
to avoid double lines (e.g grammar + spell check error) */
@@ -1053,7 +1059,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) )
{
pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
- rInf.GetKanaComp(), (sal_uInt16)aFont.GetSize().Height(), &aTextOriginPos );
+ rInf.GetKanaComp(), (sal_uInt16)aFont.GetSize().Height(), lcl_IsFullstopCentered( rInf.GetOut() ) , &aTextOriginPos );
bSpecialJust = true;
}
///Asian Justification
@@ -1224,7 +1230,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
{
pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
rInf.GetKanaComp(),
- (sal_uInt16)aFont.GetSize().Height(), &aTextOriginPos );
+ (sal_uInt16)aFont.GetSize().Height(), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
bSpecialJust = true;
}
@@ -1434,10 +1440,10 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
Point aTmpPos( aTextOriginPos );
pSI->Compress( pScrArray, rInf.GetIdx(), rInf.GetLen(),
rInf.GetKanaComp(),
- (sal_uInt16)aFont.GetSize().Height(), &aTmpPos );
+ (sal_uInt16)aFont.GetSize().Height(), lcl_IsFullstopCentered( rInf.GetOut() ), &aTmpPos );
pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
rInf.GetKanaComp(),
- (sal_uInt16)aFont.GetSize().Height(), &aTextOriginPos );
+ (sal_uInt16)aFont.GetSize().Height(), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
}
// Asian Justification
@@ -1904,7 +1910,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
if( bCompress )
rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
rInf.GetIdx(), nLn, rInf.GetKanaComp(),
- (sal_uInt16)aFont.GetSize().Height() ) );
+ (sal_uInt16)aFont.GetSize().Height() ,lcl_IsFullstopCentered( rInf.GetOut() ) ) );
else
rInf.SetKanaDiff( 0 );
@@ -1967,7 +1973,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
rInf.GetIdx(), nLn );
rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
rInf.GetIdx(), nLn, rInf.GetKanaComp(),
- (sal_uInt16) aFont.GetSize().Height() ) );
+ (sal_uInt16) aFont.GetSize().Height() ,lcl_IsFullstopCentered( rInf.GetOut() ) ) );
aTextSize.Width() = pKernArray[ nLn - 1 ];
delete[] pKernArray;
}
@@ -2027,7 +2033,8 @@ sal_Int32 SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf )
{
pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
rInf.GetKanaComp(),
- (sal_uInt16) aFont.GetSize().Height() );
+ (sal_uInt16) aFont.GetSize().Height(),
+ lcl_IsFullstopCentered( rInf.GetOut() ) );
}
// Asian Justification
@@ -2466,7 +2473,8 @@ sal_Int32 SwFont::GetTextBreak( SwDrawTextInfo& rInf, long nTextWidth )
rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
rInf.GetIdx(), nLn );
if( rInf.GetScriptInfo()->Compress( pKernArray, rInf.GetIdx(), nLn,
- rInf.GetKanaComp(), (sal_uInt16)GetHeight( nActual ) ) )
+ rInf.GetKanaComp(), (sal_uInt16)GetHeight( nActual ) ,
+ lcl_IsFullstopCentered( rInf.GetOut() ) ) )
{
long nKernAdd = nKern;
sal_Int32 nTmpBreak = nTextBreak2;
diff --git a/vcl/inc/impfont.hxx b/vcl/inc/impfont.hxx
index 3a02b1d9483a..afa1a3b479ff 100644
--- a/vcl/inc/impfont.hxx
+++ b/vcl/inc/impfont.hxx
@@ -103,7 +103,7 @@ private:
sal_uInt16 mnMiscFlags; // Misc Flags
sal_uInt32 mnRefCount; // Reference Counter
- enum { DEVICE_FLAG=1, SCALABLE_FLAG=2, LATIN_FLAG=4, CJK_FLAG=8, CTL_FLAG=16 };
+ enum { DEVICE_FLAG=1, SCALABLE_FLAG=2, LATIN_FLAG=4, CJK_FLAG=8, CTL_FLAG=16, FULLSTOP_CENTERED_FLAG=32 };
public:
ImplFontMetric();
@@ -116,6 +116,7 @@ public:
long GetExtLeading() const { return mnExtLeading; }
long GetLineHeight() const { return mnLineHeight; }
long GetSlant() const { return mnSlant; }
+ bool IsFullstopCentered() const { return ((mnMiscFlags & FULLSTOP_CENTERED_FLAG ) != 0); }
bool IsDeviceFont() const { return ((mnMiscFlags & DEVICE_FLAG) != 0); }
bool IsScalable() const { return ((mnMiscFlags & SCALABLE_FLAG) != 0); }
diff --git a/vcl/inc/outfont.hxx b/vcl/inc/outfont.hxx
index 78e1a8f65c63..107f10cb3b7d 100644
--- a/vcl/inc/outfont.hxx
+++ b/vcl/inc/outfont.hxx
@@ -187,6 +187,7 @@ public: // TODO: hide members behind accessor methods
bool mbDevice; // Flag for Device Fonts
bool mbScalableFont;
bool mbKernableFont;
+ bool mbFullstopCentered;
// font metrics that are usually derived from the measurements
long mnUnderlineSize; // Lineheight of Underline
diff --git a/vcl/source/gdi/metric.cxx b/vcl/source/gdi/metric.cxx
index 5ed467ef912e..05630c63f895 100644
--- a/vcl/source/gdi/metric.cxx
+++ b/vcl/source/gdi/metric.cxx
@@ -151,6 +151,11 @@ long FontMetric::GetSlant() const
return mpImplMetric->GetSlant();
}
+bool FontMetric::IsFullstopCentered() const
+{
+ return mpImplMetric->IsFullstopCentered();
+}
+
FontMetric& FontMetric::operator =( const FontMetric& rMetric )
{
vcl::FontInfo::operator=( rMetric );
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index 1e4632939f63..bce865190815 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -215,6 +215,8 @@ FontMetric OutputDevice::GetFontMetric() const
aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
if( pMetric->mbScalableFont )
aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
+ if ( pMetric->mbFullstopCentered)
+ aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::FULLSTOP_CENTERED_FLAG;
aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
aMetric.mpImplMetric->mnIntLeading = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
@@ -1731,6 +1733,7 @@ ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
, mnMinKashida( 0 )
, meFamilyType(FAMILY_DONTKNOW)
, mbScalableFont(false)
+ , mbFullstopCentered(false)
, mnUnderlineSize( 0 )
, mnUnderlineOffset( 0 )
, mnBUnderlineSize( 0 )
@@ -1775,6 +1778,7 @@ ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
}
}
+
void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
{
long nDescent = mnDescent;
@@ -1857,6 +1861,21 @@ void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
mnDStrikeoutSize = n2LineHeight;
mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
+
+ const vcl::Font& rFont ( pDev->GetFont() );
+ bool bCentered = true;
+ if (MsLangId::isCJK(rFont.GetLanguage()))
+ {
+ const OUString sFullstop( sal_Unicode( 0x3001 ) ); // Fullwidth fullstop
+ Rectangle aRect;
+ pDev->GetTextBoundRect( aRect, sFullstop );
+ const sal_uInt16 nH = rFont.GetSize().Height();
+ const sal_uInt16 nB = aRect.Left();
+ // Use 18.75% as a threshold to define a centered fullwidth fullstop.
+ // In general, nB/nH < 5% for most Japanese fonts.
+ bCentered = (nB > (((nH >> 1)+nH)>>3)) ? true : false;
+ }
+ mbFullstopCentered = bCentered ;
}
void ImplFontMetricData::ImplInitAboveTextLineSize()