diff options
-rwxr-xr-x | vcl/aqua/source/gdi/salatslayout.cxx | 35 | ||||
-rwxr-xr-x | vcl/inc/vcl/sallayout.hxx | 1 | ||||
-rw-r--r-- | vcl/source/gdi/outdev6.cxx | 1 | ||||
-rwxr-xr-x | vcl/source/gdi/sallayout.cxx | 144 | ||||
-rw-r--r-- | vcl/source/glyphs/gcach_ftyp.cxx | 11 | ||||
-rwxr-xr-x | vcl/source/glyphs/gcach_layout.cxx | 67 | ||||
-rwxr-xr-x | vcl/win/source/gdi/winlayout.cxx | 50 |
7 files changed, 205 insertions, 104 deletions
diff --git a/vcl/aqua/source/gdi/salatslayout.cxx b/vcl/aqua/source/gdi/salatslayout.cxx index ca1a38c94043..01808d4d2a0d 100755 --- a/vcl/aqua/source/gdi/salatslayout.cxx +++ b/vcl/aqua/source/gdi/salatslayout.cxx @@ -86,6 +86,7 @@ private: // mutable members since these details are all lazy initialized mutable int mnGlyphCount; // glyph count mutable Fixed mnCachedWidth; // cached value of resulting typographical width + int mnTrailingSpaceWidth; // in Pixels mutable ATSGlyphRef* mpGlyphIds; // ATSU glyph ids mutable Fixed* mpCharWidths; // map relative charpos to charwidth @@ -104,8 +105,8 @@ private: mutable class FallbackInfo* mpFallbackInfo; // x-offset relative to layout origin - // currently always zero since we use native glyph fallback - static const Fixed mnBaseAdv = 0; + // currently only used in RTL-layouts + mutable Fixed mnBaseAdv; }; class FallbackInfo @@ -130,6 +131,7 @@ ATSLayout::ATSLayout( ATSUStyle& rATSUStyle, float fFontScale ) mfFontScale( fFontScale ), mnGlyphCount( -1 ), mnCachedWidth( 0 ), + mnTrailingSpaceWidth( 0 ), mpGlyphIds( NULL ), mpCharWidths( NULL ), mpChars2Glyphs( NULL ), @@ -138,7 +140,8 @@ ATSLayout::ATSLayout( ATSUStyle& rATSUStyle, float fFontScale ) mpGlyphAdvances( NULL ), mpGlyphOrigAdvs( NULL ), mpDeltaY( NULL ), - mpFallbackInfo( NULL ) + mpFallbackInfo( NULL ), + mnBaseAdv( 0 ) {} // ----------------------------------------------------------------------- @@ -277,12 +280,16 @@ void ATSLayout::AdjustLayout( ImplLayoutArgs& rArgs ) nPixelWidth = rArgs.mpDXArray[ mnCharCount - 1 ]; // workaround for ATSUI not using trailing spaces for justification - int nTrailingSpaceWidth = 0; + mnTrailingSpaceWidth = 0; int i = mnCharCount; while( (--i > 0) && IsSpacingGlyph( rArgs.mpStr[mnMinCharPos+i]|GF_ISCHAR ) ) - nTrailingSpaceWidth += rArgs.mpDXArray[i] - rArgs.mpDXArray[i-1]; - nOrigWidth -= nTrailingSpaceWidth; - nPixelWidth -= nTrailingSpaceWidth; + mnTrailingSpaceWidth += rArgs.mpDXArray[i] - rArgs.mpDXArray[i-1]; + nOrigWidth -= mnTrailingSpaceWidth; + nPixelWidth -= mnTrailingSpaceWidth; + // trailing spaces can be leftmost spaces in RTL-layouts + // TODO: use BiDi-algorithm to thoroughly check this assumption + if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) + mnBaseAdv = mnTrailingSpaceWidth; // TODO: use all mpDXArray elements for layouting } @@ -606,9 +613,11 @@ long ATSLayout::GetTextWidth() const // measure the bound extremas mnCachedWidth = nRightBound - nLeftBound; + // adjust for eliminated trailing space widths } - const int nScaledWidth = Fixed2Vcl( mnCachedWidth ); + int nScaledWidth = Fixed2Vcl( mnCachedWidth ); + nScaledWidth += mnTrailingSpaceWidth; return nScaledWidth; } @@ -628,6 +637,9 @@ long ATSLayout::FillDXArray( long* pDXArray ) const if( !pDXArray ) return GetTextWidth(); + // check assumptions + DBG_ASSERT( !nTrailingSpaceWidth, "ATSLayout::FillDXArray() with nTSW!=0" ); + // initialize details about the resulting layout InitGIA(); @@ -667,6 +679,10 @@ int ATSLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) cons // get a quick overview on what could fit const long nPixelWidth = (nMaxWidth - (nCharExtra * mnCharCount)) / nFactor; + // check assumptions + DBG_ASSERT( !nTrailingSpaceWidth, "ATSLayout::GetTextBreak() with nTSW!=0" ); + + // initial measurement of text break position UniCharArrayOffset nBreakPos = mnMinCharPos; const ATSUTextMeasurement nATSUMaxWidth = Vcl2Fixed( nPixelWidth ); OSStatus nStatus = ATSUBreakLine( maATSULayout, mnMinCharPos, @@ -894,7 +910,8 @@ bool ATSLayout::InitGIA( ImplLayoutArgs* pArgs ) const if( pArgs && pArgs->mpDXArray ) { // TODO: non-strong-LTR case cases should be handled too - if( 0 == (~pArgs->mnFlags & (TEXT_LAYOUT_BIDI_STRONG|TEXT_LAYOUT_BIDI_LTR)) ) + if( (pArgs->mnFlags & TEXT_LAYOUT_BIDI_STRONG) + && !(pArgs->mnFlags & TEXT_LAYOUT_BIDI_RTL) ) { Fixed nSumCharWidths = 0; SubPortion aSubPortion = { mnMinCharPos, 0, 0 }; diff --git a/vcl/inc/vcl/sallayout.hxx b/vcl/inc/vcl/sallayout.hxx index d40dde9014bc..fe7cee130a3a 100755 --- a/vcl/inc/vcl/sallayout.hxx +++ b/vcl/inc/vcl/sallayout.hxx @@ -333,6 +333,7 @@ public: bool IsClusterStart() const { return !(mnFlags & IS_IN_CLUSTER); } bool IsRTLGlyph() const { return ((mnFlags & IS_RTL_GLYPH) != 0); } + bool IsDiacritic() const { return (mnOrigWidth <= 0); } // TODO: better heuristic }; // --------------- diff --git a/vcl/source/gdi/outdev6.cxx b/vcl/source/gdi/outdev6.cxx index d4c24ff44e20..f76aa6b1dd55 100644 --- a/vcl/source/gdi/outdev6.cxx +++ b/vcl/source/gdi/outdev6.cxx @@ -166,7 +166,6 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, DBG_TRACE( "OutputDevice::DrawTransparent(B2D&,transparency)" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); -fprintf(stderr,"OD::DT( fT=%f, bAA=%d)\n",fTransparency,mnAntialiasing);//############## // AW: Do NOT paint empty PolyPolygons if(!rB2DPolyPoly.count()) return; 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) diff --git a/vcl/source/glyphs/gcach_ftyp.cxx b/vcl/source/glyphs/gcach_ftyp.cxx index f6d93963540b..3fe2f7cd0ec2 100644 --- a/vcl/source/glyphs/gcach_ftyp.cxx +++ b/vcl/source/glyphs/gcach_ftyp.cxx @@ -1031,6 +1031,17 @@ void FreetypeServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor rTo.mnDescent += nOtherHalfTmpExtLeading; } } + + // initialize kashida width + // TODO: what if there are different versions of this glyph available + rTo.mnMinKashida = rTo.mnAscent / 4; // a reasonable default + const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 ); + if( nKashidaGlyphId ) + { + GlyphData aGlyphData; + InitGlyphData( nKashidaGlyphId, aGlyphData ); + rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth(); + } } // ----------------------------------------------------------------------- diff --git a/vcl/source/glyphs/gcach_layout.cxx b/vcl/source/glyphs/gcach_layout.cxx index bdd2444013c0..1e2f83f5f128 100755 --- a/vcl/source/glyphs/gcach_layout.cxx +++ b/vcl/source/glyphs/gcach_layout.cxx @@ -60,8 +60,6 @@ void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const rSalGraphics.DrawServerFontLayout( *this ); } -//-------------------------------------------------------------------------- - // ----------------------------------------------------------------------- bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs ) @@ -481,6 +479,9 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr // layout bidi/script runs and export them to a ServerFontLayout // convert results to GlyphItems int nLastCharPos = -1; + int nClusterMinPos = -1; + int nClusterMaxPos = -1; + bool bClusterStart = true; int nFilteredRunGlyphCount = 0; const IcuPosition* pPos = pGlyphPositions; for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos ) @@ -518,14 +519,6 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr continue; } - // if ICU feeds us a character index sequence like [1,0,1] (which - // is completely valid), smooth out the sequence so that our cluster - // detection routines work better. The best knowledge where the - // cluster boundaries are should be provided by the layout engine... - if( nLastCharPos != -1 ) - if( (nCharPos < nLastCharPos) ^ bRightToLeft ) - nCharPos = nLastCharPos; - // apply vertical flags, etc. if( nCharPos >= 0 ) { @@ -549,25 +542,68 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rAr const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex ); int nGlyphWidth = rGM.GetCharWidth(); - // heuristic to detect group clusters using "smoothed" char positions + // heuristic to detect glyph clusters + bool bInCluster = true; + if( nLastCharPos == -1 ) + { + nClusterMinPos = nClusterMaxPos = nCharPos; + bInCluster = false; + } + else if( !bRightToLeft ) + { + // left-to-right case + if( nClusterMinPos > nCharPos ) + nClusterMinPos = nCharPos; // extend cluster + else if( nCharPos <= nClusterMaxPos ) + /*NOTHING*/; // inside cluster + else if( nGlyphWidth <= 0 ) + nClusterMaxPos = nCharPos; // add diacritic to cluster + else { + nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster + bInCluster = false; + } + } + else + { + // right-to-left case + if( nClusterMaxPos < nCharPos ) + nClusterMaxPos = nCharPos; // extend cluster + else if( nCharPos >= nClusterMinPos ) + /*NOTHING*/; // inside cluster + else if( nGlyphWidth <= 0 ) + { + nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*] + if( bClusterStart ) { + nClusterMaxPos = nCharPos; + bInCluster = false; + } + } + else + { + nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster + bInCluster = !bClusterStart; + } + } + long nGlyphFlags = 0; - if( nLastCharPos != -1 ) - if( (nCharPos == nLastCharPos) || (nGlyphWidth <= 0) ) - nGlyphFlags = GlyphItem::IS_IN_CLUSTER; + if( bInCluster ) + nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; if( bRightToLeft ) nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; // add resulting glyph item to layout - GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth ); + const GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth ); rLayout.AppendGlyph( aGI ); ++nFilteredRunGlyphCount; nLastCharPos = nCharPos; + bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath } aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) ); nGlyphCount += nFilteredRunGlyphCount; } // sort glyphs in visual order + // and then in logical order (e.g. diacritics after cluster start) rLayout.SortGlyphItems(); // determine need for kashida justification @@ -594,3 +630,4 @@ ServerFontLayoutEngine* FreetypeServerFont::GetLayoutEngine() } // ======================================================================= + diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 24f45d6cba1e..046dcf17171c 100755 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -1060,6 +1060,7 @@ public: public: bool IsEmpty() const { return (mnEndGlyphPos <= 0); } + bool IsRTL() const { return mpScriptItem->a.fRTL; } bool HasKashidas() const { return mbHasKashidas; } }; @@ -1520,7 +1521,7 @@ bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs ) // fallback request is limited to the characters in the original request // => this is handled in ImplLayoutArgs::PrepareFallback() rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos, - rVisualItem.mpScriptItem->a.fRTL ); + rVisualItem.IsRTL() ); // don't bother to do a default layout in a fallback level if( 0 != (rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) ) @@ -1574,7 +1575,7 @@ bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs ) mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH; // request fallback for the whole cell that resulted in a NotDef glyph // TODO: optimize algorithm - bool bRTL = rVisualItem.mpScriptItem->a.fRTL; + const bool bRTL = rVisualItem.IsRTL(); if( !bRTL ) { // request fallback for the left-to-right cell @@ -1762,23 +1763,22 @@ bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem, nMaxGlyphPos = n; } - // account for multiple glyphs at rightmost character - // test only needed when rightmost glyph isn't referenced - if( rEndGlyphPos > nMaxGlyphPos + 1 ) + // extend the glyph range to account for all glyphs in referenced clusters + if( !rVisualItem.IsRTL() ) // LTR-item { - // find the end of the glyph cluster - // TODO: optimize for case when LTR/RTL correspond to monotonous glyph indexes - for( int i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i ) - { - int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos; - if( (rEndGlyphPos > n) && (n > nMaxGlyphPos) ) - { - rEndGlyphPos = n; - if( n-1 <= nMaxGlyphPos ) - break; - } - } + // extend to rightmost glyph of rightmost referenced cluster + for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i ) + if( mpVisualAttrs[i].fClusterStart ) + break; } + else // RTL-item + { + // extend to leftmost glyph of leftmost referenced cluster + for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i ) + if( mpVisualAttrs[i].fClusterStart ) + break; + } + rEndGlyphPos = nMaxGlyphPos + 1; return true; } @@ -1864,7 +1864,7 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, // adjust the nXOffset relative to glyph cluster start int c = mnMinCharPos; - if( !pVI->mpScriptItem->a.fRTL ) + if( !pVI->IsRTL() ) // LTR-case { // LTR case: subtract the remainder of the cell from xoffset int nTmpIndex = mpLogClusters[c]; @@ -1872,7 +1872,7 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, && (nTmpIndex == mpLogClusters[c]) ) nXOffset -= mpCharWidths[c]; } - else + else // RTL-case { // RTL case: add the remainder of the cell from xoffset int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ]; @@ -1994,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 && pVI->mpScriptItem->a.fRTL ) + if( mpJustifications && pVI->IsRTL() ) break; // stop when the x-position of the next glyph is unexpected @@ -2191,7 +2191,7 @@ void UniscribeLayout::DrawText( SalGraphics& ) const if( nBaseGlyphPos < 0 ) { // adjust draw position relative to cluster start - if( rVisualItem.mpScriptItem->a.fRTL ) + if( rVisualItem.IsRTL() ) nBaseGlyphPos = nEndGlyphPos - 1; else nBaseGlyphPos = nMinGlyphPos; @@ -2207,7 +2207,7 @@ void UniscribeLayout::DrawText( SalGraphics& ) const && (nBaseGlyphPos == mpLogClusters[i]) ) nBaseClusterOffset += mpCharWidths[i]; - if( !rVisualItem.mpScriptItem->a.fRTL ) + if( !rVisualItem.IsRTL() ) nBaseClusterOffset = -nBaseClusterOffset; } @@ -2341,7 +2341,7 @@ void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const { int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos; int nCurrIdx = i * 2; - if( !rVisualItem.mpScriptItem->a.fRTL ) + if( !rVisualItem.IsRTL() ) { // normal positions for LTR case pCaretXArray[ nCurrIdx ] = pGlyphPos[ j ]; @@ -2433,7 +2433,7 @@ void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs ) // if needed prepare special handling for arabic justification rVisualItem.mbHasKashidas = false; - if( rVisualItem.mpScriptItem->a.fRTL ) + if( rVisualItem.IsRTL() ) { for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i ) if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF89 ) // any Arabic justification ? @@ -2499,7 +2499,7 @@ void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs ) // workaround needed for older USP versions: // right align the justification-adjusted glyphs in their cells for RTL-items // unless the right alignment is done by inserting kashidas - if( bManualCellAlign && rVisualItem.mpScriptItem->a.fRTL && !rVisualItem.HasKashidas() ) + if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() ) { for( i = nMinGlyphPos; i < nEndGlyphPos; ++i ) { |