Kaydet (Commit) be899f92 authored tarafından Herbert Dürr's avatar Herbert Dürr

#i124233# fix CoreText justification of text with trailing spaces

the fix works also for EditEngine by ignoring Writer's halfspace magic.
TODO: replace that halfspace magic with a generic solution.
üst 7e578303
...@@ -72,7 +72,6 @@ private: ...@@ -72,7 +72,6 @@ private:
// cached details about the resulting layout // cached details about the resulting layout
// mutable members since these details are all lazy initialized // mutable members since these details are all lazy initialized
mutable double mfCachedWidth; // cached value of resulting typographical width mutable double mfCachedWidth; // cached value of resulting typographical width
mutable double mfTrailingSpaceWidth; // in Pixels
// x-offset relative to layout origin // x-offset relative to layout origin
// currently only used in RTL-layouts // currently only used in RTL-layouts
...@@ -89,7 +88,6 @@ CTLayout::CTLayout( const CTTextStyle* pTextStyle ) ...@@ -89,7 +88,6 @@ CTLayout::CTLayout( const CTTextStyle* pTextStyle )
, mnTrailingSpaces( 0 ) , mnTrailingSpaces( 0 )
, mfFontScale( pTextStyle->mfFontScale ) , mfFontScale( pTextStyle->mfFontScale )
, mfCachedWidth( -1 ) , mfCachedWidth( -1 )
, mfTrailingSpaceWidth( 0 )
, mnBaseAdv( 0 ) , mnBaseAdv( 0 )
{ {
CFRetain( mpTextStyle->GetStyleDict() ); CFRetain( mpTextStyle->GetStyleDict() );
...@@ -146,60 +144,49 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs ) ...@@ -146,60 +144,49 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
return; return;
const DynCoreTextSyms& rCT = DynCoreTextSyms::get(); const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
// CoreText fills trailing space during justification so we have to
// take that into account when requesting CT to justify something
mfTrailingSpaceWidth = rCT.LineGetTrailingWhitespaceWidth( mpCTLine );
const int nTrailingSpaceWidth = rint( mfFontScale * mfTrailingSpaceWidth );
int nOrigWidth = GetTextWidth();
int nPixelWidth = rArgs.mnLayoutWidth; int nPixelWidth = rArgs.mnLayoutWidth;
if( nPixelWidth ) if( rArgs.mpDXArray )
{
nPixelWidth -= nTrailingSpaceWidth;
if( nPixelWidth <= 0)
return;
}
else if( rArgs.mpDXArray )
{ {
// for now we are only interested in the layout width // for now we are only interested in the layout width
// TODO: use all mpDXArray elements for layouting // TODO: use all mpDXArray elements for layouting
nPixelWidth = rArgs.mpDXArray[ mnCharCount - 1 - mnTrailingSpaces ]; nPixelWidth = rArgs.mpDXArray[ mnCharCount-1 ];
} }
// short-circuit when justifying an all-whitespace string // short-circuit when justifying an all-whitespace string
if( mnTrailingSpaces >= mnCharCount) if( mnTrailingSpaces >= mnCharCount)
{ {
mfCachedWidth = mfTrailingSpaceWidth = nPixelWidth / mfFontScale; mfCachedWidth = nPixelWidth / mfFontScale;
return; return;
} }
// in RTL-layouts trailing spaces are leftmost
// TODO: use BiDi-algorithm to thoroughly check this assumption
if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
mnBaseAdv = nTrailingSpaceWidth;
// return early if there is nothing to do // return early if there is nothing to do
if( nPixelWidth <= 0 ) if( nPixelWidth <= 0 )
return; return;
// HACK: justification requests which change the width by just one pixel are probably // HACK: justification requests which change the width by just one pixel are probably
// #i86038# introduced by lossy conversions between integer based coordinate system // #i86038# introduced by lossy conversions between integer based coordinate system
const int nOrigWidth = GetTextWidth();
if( (nOrigWidth >= nPixelWidth-1) && (nOrigWidth <= nPixelWidth+1) ) if( (nOrigWidth >= nPixelWidth-1) && (nOrigWidth <= nPixelWidth+1) )
return; return;
// if the text to be justified has whitespace in it then // if the text to be justified has whitespace in it then
// - Writer goes crazy with its HalfSpace magic // - Writer goes crazy with its HalfSpace magic
// - LayoutEngine handles spaces specially (in particular at the text start or end) // - CoreText handles spaces specially (in particular at the text end)
if( mnTrailingSpaces ) { if( mnTrailingSpaces ) {
// adjust for Writer's SwFntObj::DrawText() Halfspace magic at the text end int nTrailingSpaceWidth = 0;
std::vector<sal_Int32> aOrigDXAry; if( rArgs.mpDXArray) {
aOrigDXAry.resize( mnCharCount); const int nFullPixWidth = nPixelWidth;
FillDXArray( &aOrigDXAry[0] ); nPixelWidth = rArgs.mpDXArray[ mnCharCount-1-mnTrailingSpaces ];
int nLastCharSpace = rArgs.mpDXArray[ mnCharCount-1-mnTrailingSpaces ] nTrailingSpaceWidth = nFullPixWidth - nPixelWidth;
- aOrigDXAry[ mnCharCount-1-mnTrailingSpaces ]; } else {
nPixelWidth -= nLastCharSpace; const double fTrailingSpaceWidth = rCT.LineGetTrailingWhitespaceWidth( mpCTLine );
if( nPixelWidth < 0 ) nTrailingSpaceWidth = rint(fTrailingSpaceWidth);
}
nPixelWidth -= nTrailingSpaceWidth;
if( nPixelWidth <= 0 )
return; return;
// recreate the CoreText line layout without trailing spaces // recreate the CoreText line layout without trailing spaces
CFRelease( mpCTLine ); CFRelease( mpCTLine );
CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL, rArgs.mpStr + mnMinCharPos, CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL, rArgs.mpStr + mnMinCharPos,
...@@ -208,9 +195,15 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs ) ...@@ -208,9 +195,15 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
mpCTLine = CTLineCreateWithAttributedString( pAttrStr ); mpCTLine = CTLineCreateWithAttributedString( pAttrStr );
CFRelease( aCFText); CFRelease( aCFText);
CFRelease( pAttrStr ); CFRelease( pAttrStr );
// in RTL-layouts trailing spaces are leftmost
// TODO: use BiDi-algorithm to thoroughly check this assumption
if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
mnBaseAdv = nTrailingSpaceWidth;
} }
CTLineRef pNewCTLine = rCT.LineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth / mfFontScale ); const double fAdjustedWidth = nPixelWidth / mfFontScale;
CTLineRef pNewCTLine = rCT.LineCreateJustifiedLine( mpCTLine, 1.0, fAdjustedWidth );
if( !pNewCTLine ) { // CTLineCreateJustifiedLine can and does fail if( !pNewCTLine ) { // CTLineCreateJustifiedLine can and does fail
// handle failure by keeping the unjustified layout // handle failure by keeping the unjustified layout
// TODO: a better solution such as // TODO: a better solution such as
...@@ -221,8 +214,7 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs ) ...@@ -221,8 +214,7 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
} }
CFRelease( mpCTLine ); CFRelease( mpCTLine );
mpCTLine = pNewCTLine; mpCTLine = pNewCTLine;
mfCachedWidth = -1; // TODO: can we set it directly to target width we requested? For now we re-measure mfCachedWidth = fAdjustedWidth;
mfTrailingSpaceWidth = 0;
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
...@@ -404,8 +396,8 @@ long CTLayout::FillDXArray( sal_Int32* pDXArray ) const ...@@ -404,8 +396,8 @@ long CTLayout::FillDXArray( sal_Int32* pDXArray ) const
CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex ); CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun ); const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun );
const CFRange aFullRange = CFRangeMake( 0, nGlyphCount ); const CFRange aFullRange = CFRangeMake( 0, nGlyphCount );
aSizeVec.reserve( nGlyphCount ); aSizeVec.resize( nGlyphCount );
aIndexVec.reserve( nGlyphCount ); aIndexVec.resize( nGlyphCount );
CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVec[0] ); CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVec[0] );
CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVec[0] ); CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVec[0] );
for( int i = 0; i != nGlyphCount; ++i ) { for( int i = 0; i != nGlyphCount; ++i ) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment