Author: hdu Date: Tue May 20 12:00:50 2014 New Revision: 1596218 URL: http://svn.apache.org/r1596218 Log: #i124935# fix expanded/condensed text breaking in the CoreText engine
the concept of an extra-width per code-unit was obsolete at least since apps supported unicode with its different normalization forms, diacritical marks, surrogate-pairs, non-printing characters such as ZWJ/ZWNJ/RLM, etc. so of course modern engines like CoreText don't aid this typographical crime. The fix here extends the CTLayout::GetTextBreak() method to handle the obsolete semantic of per code-unit extra-widths by successively approximating the number of involved code-units. Modified: openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx Modified: openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx?rev=1596218&r1=1596217&r2=1596218&view=diff ============================================================================== --- openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx (original) +++ openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx Tue May 20 12:00:50 2014 @@ -451,13 +451,35 @@ int CTLayout::GetTextBreak( long nMaxWid return STRING_LEN; CTTypesetterRef aCTTypeSetter = CTTypesetterCreateWithAttributedString( mpAttrString ); - const double fCTMaxWidth = (double)nMaxWidth / (nFactor * mfFontScale); - CFIndex nIndex = CTTypesetterSuggestClusterBreak( aCTTypeSetter, 0, fCTMaxWidth ); - if( nIndex >= mnCharCount ) - return STRING_LEN; - nIndex += mnMinCharPos; - return (int)nIndex; + CFIndex nBestGuess = (nCharExtra >= 0) ? 0 : mnCharCount; + for( int i = 1; i <= mnCharCount; i *= 2 ) + { + // guess the target width considering char-extra expansion/condensation + const long nTargetWidth = nMaxWidth - nBestGuess * nCharExtra; + const double fCTMaxWidth = nTargetWidth / (nFactor * mfFontScale); + // calculate the breaking index for the guessed target width + const CFIndex nNewIndex = CTTypesetterSuggestClusterBreak( aCTTypeSetter, 0, fCTMaxWidth ); + if( nNewIndex >= mnCharCount ) { + CFRelease( aCTTypeSetter ); + return STRING_LEN; + } + // check if the original extra-width guess was good + if( !nCharExtra ) + nBestGuess = nNewIndex; + if( nBestGuess == nNewIndex ) + break; + // prepare another round for a different number of characters + CFIndex nNewGuess = (nNewIndex + nBestGuess + 1) / 2; + if( nNewGuess == nBestGuess ) + nNewGuess += (nNewIndex > nBestGuess) ? +1 : -1; + nBestGuess = nNewGuess; + } + + // suggest the best fitting cluster break as breaking position + CFRelease( aCTTypeSetter ); + const int nIndex = nBestGuess + mnMinCharPos; + return nIndex; } // -----------------------------------------------------------------------