summaryrefslogtreecommitdiff
path: root/vcl/source/gdi/sallayout.cxx
diff options
context:
space:
mode:
authorOliver Bolte <obo@openoffice.org>2009-02-16 09:03:54 +0000
committerOliver Bolte <obo@openoffice.org>2009-02-16 09:03:54 +0000
commit1b52154648707fd93d6c0147d243b803a1f25711 (patch)
treefb64e717cb9b743dd53f3357ded08a6bf3650392 /vcl/source/gdi/sallayout.cxx
parent3b697a6aba0e0f33910a71b95f98d7ef724ff3a2 (diff)
CWS-TOOLING: integrate CWS kashidafix02
2009-01-27 13:52:43 +0100 hdu r266989 : #i98522# fix position of fallback glyph in RTL-contexts 2009-01-27 11:22:08 +0100 hdu r266969 : minor source layout 2009-01-27 11:18:36 +0100 hdu r266968 : #i98453# prevent kashida-injection for blank-justified text 2009-01-26 11:12:01 +0100 hdu r266911 : #i98454# simplified lcl_ConnectToPrev(), fixed spurious chars in source 2009-01-26 10:53:58 +0100 hdu r266910 : #i98453# handle arabic justification when no valid kashida positions are available 2009-01-26 10:44:30 +0100 hdu r266909 : #i98410# prevent kashida-expansion at ZWNJ 2009-01-23 16:08:17 +0100 hdu r266832 : #i93210# in RTL-contexts the trailing-spaces can be leftmost-spaces 2009-01-23 14:00:24 +0100 hdu r266814 : #i98399# add FARSI support for digit conversion 2009-01-21 15:35:03 +0100 hdu r266675 : #i97108# sub-portion adjustment of RTL-text is not needed yet 2009-01-21 13:40:21 +0100 hdu r266663 : no workaround needed for newer versions of ICU bidi 2009-01-20 09:32:11 +0100 hdu r266553 : #i85089# better cluster detection for UniscribeLayout 2009-01-19 12:39:08 +0100 hdu r266490 : silence escaped fprintf to stderr 2009-01-19 12:23:45 +0100 hdu r266488 : #i85074# improve cluster handling for justified CTL-text on UNX 2009-01-19 10:14:43 +0100 fme r266478 : #i97108# hennerdrewes: Writer's kashida justification has problems with vocalized text
Diffstat (limited to 'vcl/source/gdi/sallayout.cxx')
-rwxr-xr-xvcl/source/gdi/sallayout.cxx144
1 files changed, 90 insertions, 54 deletions
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 6b695b8a22f6..0ac6610ab784 100755
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -254,6 +254,7 @@ sal_UCS4 GetLocalizedChar( sal_UCS4 nChar, LanguageType eLang )
case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY:
nOffset = 0x0660 - '0'; // arabic-indic digits
break;
+ case LANGUAGE_FARSI & LANGUAGE_MASK_PRIMARY:
case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY:
case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //???
case LANGUAGE_SINDHI & LANGUAGE_MASK_PRIMARY:
@@ -548,7 +549,7 @@ ImplLayoutArgs::ImplLayoutArgs( const xub_Unicode* pStr, int nLen,
UBiDiLevel nLevel = UBIDI_DEFAULT_LTR;
if( mnFlags & SAL_LAYOUT_BIDI_RTL )
- nLevel = UBIDI_RTL;
+ nLevel = UBIDI_DEFAULT_RTL;
// prepare substring for BiDi analysis
// TODO: reuse allocated pParaBidi
@@ -567,20 +568,16 @@ ImplLayoutArgs::ImplLayoutArgs( const xub_Unicode* pStr, int nLen,
}
// run BiDi algorithm
- int nRunCount = ubidi_countRuns( pLineBidi, &rcI18n);
+ const int nRunCount = ubidi_countRuns( pLineBidi, &rcI18n );
//maRuns.resize( 2 * nRunCount );
- // TODO: see comment about #110273# below, remove when external issue fixed
- const UBiDiLevel* pParaLevels = ubidi_getLevels( pParaBidi, &rcI18n);
for( int i = 0; i < nRunCount; ++i )
{
int32_t nMinPos, nLength;
- ubidi_getVisualRun( pLineBidi, i, &nMinPos, &nLength );
- int nPos0 = nMinPos + mnMinCharPos;
- int nPos1 = nPos0 + nLength;
+ const UBiDiDirection nDir = ubidi_getVisualRun( pLineBidi, i, &nMinPos, &nLength );
+ const int nPos0 = nMinPos + mnMinCharPos;
+ const int nPos1 = nPos0 + nLength;
- // bool bRTL = (nDir == UBIDI_RTL);
- // workaround for #110273# (probably ICU problem TODO: analyze there)
- bool bRTL = ((pParaLevels[ nPos0 ] & 1) != 0);
+ const bool bRTL = (nDir == UBIDI_RTL);
AddRun( nPos0, nPos1, bRTL );
}
@@ -953,8 +950,8 @@ bool GenericSalLayout::GetCharWidths( sal_Int32* pCharWidths ) const
pCharWidths[n] = 0;
// determine cluster extents
- const GlyphItem* pG = mpGlyphItems;
- for( int i = mnGlyphCount; --i >= 0; ++pG )
+ const GlyphItem* const pEnd = mpGlyphItems + mnGlyphCount;
+ for( const GlyphItem* pG = mpGlyphItems; pG < pEnd; ++pG )
{
// use cluster start to get char index
if( !pG->IsClusterStart() )
@@ -974,11 +971,13 @@ bool GenericSalLayout::GetCharWidths( sal_Int32* pCharWidths ) const
// calculate right x-position for this glyph cluster
// break if no more glyphs in layout
// break at next glyph cluster start
- for(; (i > 0) && !pG[1].IsClusterStart(); --i )
+ while( (pG+1 < pEnd) && !pG[1].IsClusterStart() )
{
// advance to next glyph in cluster
++pG;
+ if( pG->IsDiacritic() )
+ continue; // ignore diacritics
// get leftmost x-extent of this glyph
long nXPos = pG->maLinearPos.X();
if( nXPosMin > nXPos )
@@ -992,8 +991,19 @@ bool GenericSalLayout::GetCharWidths( sal_Int32* pCharWidths ) const
// when the current cluster overlaps with the next one assume
// rightmost cluster edge is the leftmost edge of next cluster
- if( (i > 0) && (nXPosMax > pG[1].maLinearPos.X()) )
- nXPosMax = pG[1].maLinearPos.X();
+ // for clusters that do not have x-sorted glyphs
+ // TODO: avoid recalculation of left bound in next cluster iteration
+ for( const GlyphItem* pN = pG; ++pN < pEnd; )
+ {
+ if( pN->IsClusterStart() )
+ break;
+ if( pN->IsDiacritic() )
+ continue; // ignore diacritics
+ if( nXPosMax > pN->maLinearPos.X() )
+ nXPosMax = pN->maLinearPos.X();
+ }
+ if( nXPosMax < nXPosMin )
+ nXPosMin = nXPosMax = 0;
// character width is sum of glyph cluster widths
pCharWidths[n] += nXPosMax - nXPosMin;
@@ -1130,15 +1140,14 @@ void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs )
// adjust cluster glyph widths and positions
nDelta = nBasePointX + (nNewPos - pG->maLinearPos.X());
- if( !pG->IsRTLGlyph()
- || (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) )
+ if( !pG->IsRTLGlyph() )
{
- // for (LTR || KASHIDA) case extend rightmost glyph in cluster
+ // for LTR case extend rightmost glyph in cluster
pClusterG[-1].mnNewWidth += nDiff;
}
else
{
- // right align cluster in new space for (RTL && !KASHIDA) case
+ // right align cluster in new space for RTL case
pG->mnNewWidth += nDiff;
nDelta += nDiff;
}
@@ -1168,7 +1177,7 @@ void GenericSalLayout::Justify( long nNewWidth )
int nMaxGlyphWidth = 0;
for( pG = mpGlyphItems; pG < pGRight; ++pG )
{
- if( pG->mnOrigWidth > 0 )
+ if( !pG->IsDiacritic() )
++nStretchable;
if( nMaxGlyphWidth < pG->mnOrigWidth)
nMaxGlyphWidth = pG->mnOrigWidth;
@@ -1195,7 +1204,7 @@ void GenericSalLayout::Justify( long nNewWidth )
pG->maLinearPos.X() += nDeltaSum;
// do not stretch non-stretchable glyphs
- if( (pG->mnOrigWidth <= 0) || (nStretchable <= 0) )
+ if( pG->IsDiacritic() || (nStretchable <= 0) )
continue;
// distribute extra space equally to stretchable glyphs
@@ -1279,13 +1288,18 @@ void GenericSalLayout::KashidaJustify( long nKashidaIndex, int nKashidaWidth )
int nKashidaCount = 0, i;
for( i = 0; i < mnGlyphCount; ++i, ++pG1 )
{
+ // only inject kashidas in RTL contexts
if( !pG1->IsRTLGlyph() )
continue;
+ // no kashida-injection for blank justified expansion either
+ if( IsSpacingGlyph( pG1->mnGlyphIndex ) )
+ continue;
- int nDelta = pG1->mnNewWidth - pG1->mnOrigWidth;
+ // calculate gap, ignore if too small
+ const int nGapWidth = pG1->mnNewWidth - pG1->mnOrigWidth;
// worst case is one kashida even for mini-gaps
- if( nDelta > 0 )
- nKashidaCount += 1 + (nDelta / nKashidaWidth);
+ if( 3 * nGapWidth >= nKashidaWidth )
+ nKashidaCount += 1 + (nGapWidth / nKashidaWidth);
}
if( !nKashidaCount )
@@ -1302,19 +1316,23 @@ void GenericSalLayout::KashidaJustify( long nKashidaIndex, int nKashidaWidth )
// default action is to copy array element
*pG2 = *pG1;
- // only apply kashida in a RTL context
+ // only inject kashida in RTL contexts
if( !pG1->IsRTLGlyph() )
continue;
+ // no kashida-injection for blank justified expansion either
+ if( IsSpacingGlyph( pG1->mnGlyphIndex ) )
+ continue;
// calculate gap, skip if too small
- int nDelta = pG1->mnNewWidth - pG1->mnOrigWidth;
- if( 3*nDelta < nKashidaWidth )
+ int nGapWidth = pG1->mnNewWidth - pG1->mnOrigWidth;
+ if( 3*nGapWidth < nKashidaWidth )
continue;
// fill gap with kashidas
nKashidaCount = 0;
Point aPos = pG1->maLinearPos;
- for(; nDelta > 0; nDelta -= nKashidaWidth, ++nKashidaCount )
+ aPos.X() -= nGapWidth; // cluster is already right aligned
+ for(; nGapWidth > 0; nGapWidth -= nKashidaWidth, ++nKashidaCount )
{
*(pG2++) = GlyphItem( pG1->mnCharPos, nKashidaIndex, aPos,
GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaWidth );
@@ -1322,21 +1340,21 @@ void GenericSalLayout::KashidaJustify( long nKashidaIndex, int nKashidaWidth )
}
// fixup rightmost kashida for gap remainder
- if( nDelta < 0 )
+ if( nGapWidth < 0 )
{
- aPos.X() += nDelta;
+ aPos.X() += nGapWidth;
if( nKashidaCount <= 1 )
- nDelta /= 2; // for small gap move kashida to middle
- pG2[-1].mnNewWidth += nDelta; // adjust kashida width to gap width
- pG2[-1].maLinearPos.X() += nDelta;
+ nGapWidth /= 2; // for small gap move kashida to middle
+ pG2[-1].mnNewWidth += nGapWidth; // adjust kashida width to gap width
+ pG2[-1].maLinearPos.X() += nGapWidth;
}
- // when kashidas were used move the original glyph
+ // when kashidas were inserted move the original cluster
// to the right and shrink it to it's original width
*pG2 = *pG1;
pG2->maLinearPos.X() = aPos.X();
pG2->mnNewWidth = pG2->mnOrigWidth;
- }
+ }
// use the new glyph array
DBG_ASSERT( mnGlyphCapacity >= pG2-pNewGlyphItems, "KashidaJustify overflow" );
@@ -1487,8 +1505,16 @@ void GenericSalLayout::MoveGlyph( int nStart, long nNewXPos )
{
if( nStart >= mnGlyphCount )
return;
+
GlyphItem* pG = mpGlyphItems + nStart;
+ // the nNewXPos argument determines the new cell position
+ // as RTL-glyphs are right justified in their cell
+ // the cell position needs to be adjusted to the glyph position
+ if( pG->IsRTLGlyph() )
+ nNewXPos += pG->mnNewWidth - pG->mnOrigWidth;
+ // calculate the x-offset to the old position
long nXDelta = nNewXPos - pG->maLinearPos.X();
+ // adjust all following glyph positions if needed
if( nXDelta != 0 )
{
GlyphItem* const pGEnd = mpGlyphItems + mnGlyphCount;
@@ -1534,27 +1560,37 @@ void GenericSalLayout::Simplify( bool bIsBase )
// make sure GlyphItems are sorted left to right
void GenericSalLayout::SortGlyphItems()
{
+ // move cluster components behind their cluster start (especially for RTL)
// using insertion sort because the glyph items are "almost sorted"
- GlyphItem* pGL = mpGlyphItems;
- const GlyphItem* pGEnd = mpGlyphItems + mnGlyphCount;
- for( GlyphItem* pGR = pGL; ++pGR < pGEnd; pGL = pGR )
+ const GlyphItem* const pGEnd = mpGlyphItems + mnGlyphCount;
+ for( GlyphItem* pG = mpGlyphItems; pG < pGEnd; ++pG )
{
- // nothing to do when already in correct order
- int nXPos = pGR->maLinearPos.X();
- if( pGL->maLinearPos.X() <= nXPos )
+ // find a cluster starting with a diacritic
+ if( !pG->IsDiacritic() )
continue;
-
- // keep data of misplaced item
- GlyphItem aGI = *pGR;
- // make room for misplaced item
- do {
- pGL[1] = pGL[0];
- pGL[1].mnFlags |= GlyphItem::IS_IN_CLUSTER;
- } while( (--pGL >= mpGlyphItems) && (nXPos < pGL->maLinearPos.X()) );
- // move misplaced item to proper slot
- pGL[1] = aGI;
- // TODO: fix glyph cluster start flags
- pGL[1].mnFlags &= ~GlyphItem::IS_IN_CLUSTER;
+ if( !pG->IsClusterStart() )
+ continue;
+ for( GlyphItem* pBaseGlyph = pG; ++pBaseGlyph < pGEnd; )
+ {
+ // find the base glyph matching to the misplaced diacritic
+ if( pBaseGlyph->IsClusterStart() )
+ break;
+ if( pBaseGlyph->IsDiacritic() )
+ continue;
+
+ // found the matching base glyph
+ // => this base glyph becomes the new cluster start
+ const GlyphItem aDiacritic = *pG;
+ *pG = *pBaseGlyph;
+ *pBaseGlyph = aDiacritic;
+
+ // update glyph flags of swapped glyphitems
+ pG->mnFlags &= ~GlyphItem::IS_IN_CLUSTER;
+ pBaseGlyph->mnFlags |= GlyphItem::IS_IN_CLUSTER;
+ // prepare for checking next cluster
+ pG = pBaseGlyph;
+ break;
+ }
}
}
@@ -1871,7 +1907,7 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
// the measured width is still in fallback font units
// => convert it to base level font units
if( n > 0 ) // optimization: because (fUnitMul==1.0) for (n==0)
- nRunAdvance = static_cast<long>(nRunAdvance*fUnitMul + 0.5);
+ nRunAdvance = static_cast<long>(nRunAdvance*fUnitMul + 0.5);
}
// calculate new x position (in base level units)