View | Details | Raw Unified | Return to issue 111054
Collapse All | Expand All

(-)a/vcl/inc/vcl/graphite_cache.hxx (-7 / +12 lines)
Lines 127-133 Link Here
127
    }
127
    }
128
    m_segMap.clear();
128
    m_segMap.clear();
129
  };
129
  };
130
  GrSegRecord * getSegment(ImplLayoutArgs & layoutArgs, bool bIsRtl)
130
  GrSegRecord * getSegment(ImplLayoutArgs & layoutArgs, bool bIsRtl, int segCharLimit)
131
  {
131
  {
132
    GrSegRecord * found = NULL;
132
    GrSegRecord * found = NULL;
133
    // try to find a segment starting at correct place, if not, try to find a
133
    // try to find a segment starting at correct place, if not, try to find a
Lines 152-159 Link Here
152
      if (found->m_seg->startCharacter() <= layoutArgs.mnMinCharPos &&
152
      if (found->m_seg->startCharacter() <= layoutArgs.mnMinCharPos &&
153
          found->m_seg->stopCharacter() >= layoutArgs.mnEndCharPos)
153
          found->m_seg->stopCharacter() >= layoutArgs.mnEndCharPos)
154
      {
154
      {
155
        const size_t seg_char_limit = min(layoutArgs.mnLength, layoutArgs.mnEndCharPos
156
          + GraphiteLayout::EXTRA_CONTEXT_LENGTH);
157
        DBG_ASSERT(found && found->m_seg, "null entry in GraphiteSegmentCache");
155
        DBG_ASSERT(found && found->m_seg, "null entry in GraphiteSegmentCache");
158
        // restore original start character, in case it has changed
156
        // restore original start character, in case it has changed
159
        found->m_seg->setTextSourceOffset(found->m_startChar);
157
        found->m_seg->setTextSourceOffset(found->m_startChar);
Lines 161-167 Link Here
161
        // interest
159
        // interest
162
        // We could use substr and ==, but substr does a copy,
160
        // We could use substr and ==, but substr does a copy,
163
        // so its probably faster to do it like this
161
        // so its probably faster to do it like this
164
        for (size_t i = layoutArgs.mnMinCharPos; i < seg_char_limit; i++)
162
        for (int i = layoutArgs.mnMinCharPos; i < segCharLimit; i++)
165
        {
163
        {
166
          //if (!found->m_rope->match(rtl::OUString(layoutArgs.mpStr[i], layoutArgs.mnLength), i - found->m_seg->startCharacter()))
164
          //if (!found->m_rope->match(rtl::OUString(layoutArgs.mpStr[i], layoutArgs.mnLength), i - found->m_seg->startCharacter()))
167
          if (found->m_rope->getStr()[i-found->m_seg->startCharacter()] != layoutArgs.mpStr[i])
165
          if (found->m_rope->getStr()[i-found->m_seg->startCharacter()] != layoutArgs.mpStr[i])
Lines 171-176 Link Here
171
        {
169
        {
172
            return NULL;
170
            return NULL;
173
        }
171
        }
172
        if (found->m_seg->stopCharacter() > layoutArgs.mnEndCharPos &&
173
            static_cast<int>(found->char2BaseGlyph().size()) > layoutArgs.mnEndCharPos)
174
        {
175
            // check that the requested end character isn't mid cluster
176
            if (found->char2BaseGlyph()[layoutArgs.mnEndCharPos-layoutArgs.mnMinCharPos] == -1)
177
            {
178
                return NULL;
179
            }
180
        }
174
//        if (found->m_lockCount != 0)
181
//        if (found->m_lockCount != 0)
175
//          OutputDebugString("Multple users of SegRecord!");
182
//          OutputDebugString("Multple users of SegRecord!");
176
        found->m_lockCount++;
183
        found->m_lockCount++;
Lines 183-192 Link Here
183
      // this is expecially needed when editing a large paragraph
190
      // this is expecially needed when editing a large paragraph
184
      // each edit changes the pointers, but if we don't reuse any segments it gets very
191
      // each edit changes the pointers, but if we don't reuse any segments it gets very
185
      // slow.
192
      // slow.
186
      const size_t seg_char_limit = min(layoutArgs.mnLength, layoutArgs.mnEndCharPos
187
          + GraphiteLayout::EXTRA_CONTEXT_LENGTH);
188
      rtl::OUString * rope = new rtl::OUString(layoutArgs.mpStr + layoutArgs.mnMinCharPos,
193
      rtl::OUString * rope = new rtl::OUString(layoutArgs.mpStr + layoutArgs.mnMinCharPos,
189
                                         seg_char_limit - layoutArgs.mnMinCharPos);
194
                                         segCharLimit - layoutArgs.mnMinCharPos);
190
      if (!rope) return NULL;
195
      if (!rope) return NULL;
191
      size_t nHash = (*(rope)).hashCode();
196
      size_t nHash = (*(rope)).hashCode();
192
      GrRMEntry range = m_ropeMap.equal_range(nHash);
197
      GrRMEntry range = m_ropeMap.equal_range(nHash);
(-)a/vcl/inc/vcl/graphite_layout.hxx (+9 lines)
Lines 75-80 Link Here
75
class VCL_DLLPUBLIC GraphiteLayout : public SalLayout
75
class VCL_DLLPUBLIC GraphiteLayout : public SalLayout
76
{
76
{
77
public:
77
public:
78
    // Mask to allow Word break status to be stored within mvChar2BaseGlyph
79
    enum {
80
        WORD_BREAK_BEFORE   = 0x40000000,
81
        HYPHEN_BREAK_BEFORE = 0x80000000,
82
        BREAK_MASK          = 0xC0000000,
83
        GLYPH_INDEX_MASK    = 0x3FFFFFFF
84
    } LineBreakMask;
85
78
    class Glyphs : public std::vector<GlyphItem>
86
    class Glyphs : public std::vector<GlyphItem>
79
    {
87
    {
80
    public:
88
    public:
Lines 159-164 Link Here
159
    std::pair<int,int>    glyph_to_chars(const GlyphItem &) const;
167
    std::pair<int,int>    glyph_to_chars(const GlyphItem &) const;
160
168
161
    std::pair<long,long>  caret_positions(size_t) const;
169
    std::pair<long,long>  caret_positions(size_t) const;
170
    void expandOrCondense(ImplLayoutArgs &rArgs);
162
};
171
};
163
172
164
173
(-)a/vcl/source/glyphs/graphite_layout.cxx (-64 / +183 lines)
Lines 86-93 Link Here
86
FILE * grLog()
86
FILE * grLog()
87
{
87
{
88
#ifdef WNT
88
#ifdef WNT
89
	std::string logFileName(getenv("TEMP"));
89
    std::string logFileName(getenv("TEMP"));
90
	logFileName.append("\\graphitelayout.log");
90
    logFileName.append("\\graphitelayout.log");
91
    if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w");
91
    if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w");
92
    else fflush(grLogFile);
92
    else fflush(grLogFile);
93
    return grLogFile;
93
    return grLogFile;
Lines 293-303 Link Here
293
    }
293
    }
294
    long nXOffset = round(fMinX * fScaling);
294
    long nXOffset = round(fMinX * fScaling);
295
    rWidth = round(fMaxX * fScaling) - nXOffset + nDxOffset;
295
    rWidth = round(fMaxX * fScaling) - nXOffset + nDxOffset;
296
	if (rWidth < 0)
296
    if (rWidth < 0)
297
	{
297
    {
298
		// This can happen when there was no base inside the range
298
        // This can happen when there was no base inside the range
299
		rWidth = 0;
299
        rWidth = 0;
300
	}
300
    }
301
    // fill up non-base char dx with cluster widths from previous base glyph
301
    // fill up non-base char dx with cluster widths from previous base glyph
302
    if (bRtl)
302
    if (bRtl)
303
    {
303
    {
Lines 353-358 Link Here
353
    assert(size() < rGlyph2Char.size());
353
    assert(size() < rGlyph2Char.size());
354
    rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] = size();
354
    rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] = size();
355
    rGlyph2Char[size()] = nFirstCharInCluster;
355
    rGlyph2Char[size()] = nFirstCharInCluster;
356
357
    // can we break before this cluster?
358
    // Glyphs may have eitehr a positive or negative breakWeight refering to
359
    // the position after or before the glyph respectively
360
    int nPrevBreakWeight = 0;
361
    if (nFirstGlyphInCluster > 0)
362
    {
363
        nPrevBreakWeight = (iGlyphs.first + (nFirstGlyphInCluster - 1))->breakweight();
364
    }
365
    int nBreakWeight = aFirstGlyph.breakweight();
366
    if (nBreakWeight < 0)
367
    {
368
        // negative means it applies to the position before the glyph's character
369
        nBreakWeight *= -1;
370
        if (nPrevBreakWeight > 0 && nPrevBreakWeight < nBreakWeight)
371
        {
372
            // prevBreakWeight wins
373
            nBreakWeight = nPrevBreakWeight;
374
        }
375
    }
376
    else
377
    {
378
        nBreakWeight = 0;
379
        // positive means break after
380
        if (nPrevBreakWeight > 0)
381
            nBreakWeight = nPrevBreakWeight;
382
    }
383
    if (nBreakWeight > gr::klbNoBreak/*0*/ &&
384
        // nBreakWeight <= gr::klbHyphenBreak) // uses Graphite hyphenation
385
        nBreakWeight <= gr::klbLetterBreak) // Needed for issue 111272
386
    {
387
        if (nBreakWeight < gr::klbHyphenBreak)
388
            rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE;
389
        else
390
            rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= HYPHEN_BREAK_BEFORE;
391
    }
392
    // always allow a break before a space even if graphite doesn't
393
    if (rArgs.mpStr[nFirstCharInCluster] == 0x20)
394
        rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE;
395
356
    bool bBaseGlyph = true;
396
    bool bBaseGlyph = true;
357
    for (int j = nFirstGlyphInCluster;
397
    for (int j = nFirstGlyphInCluster;
358
        j != nNextGlyph; j += nDelta)
398
        j != nNextGlyph; j += nDelta)
Lines 409-415 Link Here
409
        }
449
        }
410
    }
450
    }
411
#ifdef GRLAYOUT_DEBUG
451
#ifdef GRLAYOUT_DEBUG
412
    fprintf(grLog(),"Cluster g[%d-%d) c[%d-%d)%x x%ld y%f\n", nFirstGlyphInCluster, nNextGlyph, nFirstCharInCluster, nNextChar, rArgs.mpStr[nFirstCharInCluster], nXPos, aFirstGlyph.yOffset());
452
    fprintf(grLog(),"Cluster g[%d-%d) c[%d-%d)%x x%ld y%f bw%d\n", nFirstGlyphInCluster, nNextGlyph, nFirstCharInCluster, nNextChar, rArgs.mpStr[nFirstCharInCluster], nXPos, aFirstGlyph.yOffset(), nBreakWeight);
413
#endif
453
#endif
414
    return aBounds;
454
    return aBounds;
415
}
455
}
Lines 641-646 Link Here
641
        if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl))
681
        if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl))
642
            maLayout.setRightToLeft(bRtl);
682
            maLayout.setRightToLeft(bRtl);
643
683
684
        // Context is often needed beyond the specified end, however, we don't
685
        // want it if there has been a direction change, since it is hard
686
        // to tell between reordering within one direction and multi-directional
687
        // text. Extra context, can also cause problems with ligatures stradling
688
        // a hyphenation point, so disable if CTL is disabled.
689
        const int  nSegCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH);
690
        int limit = rArgs.mnEndCharPos;
691
        if ((nSegCharLimit > limit) && !(SAL_LAYOUT_COMPLEX_DISABLED & rArgs.mnFlags))
692
        {
693
            limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos,
694
                nSegCharLimit - rArgs.mnEndCharPos, bRtl);
695
        }
696
644
#ifdef GRCACHE
697
#ifdef GRCACHE
645
        GrFontHasher hasher(mrFont);
698
        GrFontHasher hasher(mrFont);
646
        sal_Int32 aFontHash = hasher.hashCode(mpFeatures);
699
        sal_Int32 aFontHash = hasher.hashCode(mpFeatures);
Lines 648-654 Link Here
648
            (GraphiteCacheHandler::instance).getCache(aFontHash);
701
            (GraphiteCacheHandler::instance).getCache(aFontHash);
649
        if (pCache)
702
        if (pCache)
650
        {
703
        {
651
            *pSegRecord = pCache->getSegment(rArgs, bRtl);
704
            *pSegRecord = pCache->getSegment(rArgs, bRtl, nSegCharLimit);
652
            if (*pSegRecord)
705
            if (*pSegRecord)
653
            {
706
            {
654
                pSegment = (*pSegRecord)->getSegment();
707
                pSegment = (*pSegRecord)->getSegment();
Lines 667-684 Link Here
667
        }
720
        }
668
#endif
721
#endif
669
722
670
        // Context is often needed beyond the specified end, however, we don't
671
        // want it if there has been a direction change, since it is hard
672
        // to tell between reordering within one direction and multi-directional
673
        // text.
674
        const int  segCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH);
675
        int limit = rArgs.mnEndCharPos;
676
        if (segCharLimit > limit)
677
        {
678
            limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos,
679
                segCharLimit - rArgs.mnEndCharPos, bRtl);
680
        }
681
682
        // Create a new TextSource object for the engine.
723
        // Create a new TextSource object for the engine.
683
        mpTextSrc = new TextSourceAdaptor(rArgs, limit);
724
        mpTextSrc = new TextSourceAdaptor(rArgs, limit);
684
        if (mpFeatures) mpTextSrc->setFeatures(mpFeatures);
725
        if (mpFeatures) mpTextSrc->setFeatures(mpFeatures);
Lines 744-752 Link Here
744
            // rightToLeft() may no longer be valid if the engine has been run
785
            // rightToLeft() may no longer be valid if the engine has been run
745
            // ltr since the segment was created.
786
            // ltr since the segment was created.
746
#ifdef GRCACHE
787
#ifdef GRCACHE
747
			bool bRtl = pSegRecord? pSegRecord->isRtl() : pSegment->rightToLeft();
788
            bool bRtl = pSegRecord? pSegRecord->isRtl() : pSegment->rightToLeft();
748
#else
789
#else
749
			bool bRtl = pSegment->rightToLeft();
790
            bool bRtl = pSegment->rightToLeft();
750
#endif
791
#endif
751
            mvGlyphs.fill_from(*pSegment, rArgs, bRtl,
792
            mvGlyphs.fill_from(*pSegment, rArgs, bRtl,
752
                mnWidth, mfScaling, mvChar2BaseGlyph, mvGlyph2Char, mvCharDxs);
793
                mnWidth, mfScaling, mvChar2BaseGlyph, mvGlyph2Char, mvCharDxs);
Lines 785-791 Link Here
785
#endif
826
#endif
786
            return false;
827
            return false;
787
        }
828
        }
788
	}
829
    }
789
    else
830
    else
790
    {
831
    {
791
        mnWidth = 0;
832
        mnWidth = 0;
Lines 795-821 Link Here
795
836
796
int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) const
837
int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) const
797
{
838
{
798
    // Adjust maxmnWidth so FindNextBreakPoint returns a sensible answer.
839
#ifdef GRLAYOUT_DEBUG
799
    maxmnWidth -= (mnEndCharPos-mnMinCharPos-1)*char_extra;  // extra character spacing.
840
    fprintf(grLog(),"Gr::GetTextBreak c[%d-%d) maxWidth %ld char extra %ld factor %d\n",
800
    maxmnWidth /= factor;                                    // scaling factor.
841
        mnMinCharPos, mnEndCharPos, maxmnWidth, char_extra, factor);
842
#endif
801
843
802
    // Ask the segment for the nearest whole letter break for the width.
803
    //float width;
804
    float targetWidth = maxmnWidth/mfScaling;
805
    // return quickly if this segment is narrower than the target width
844
    // return quickly if this segment is narrower than the target width
806
    // (sometimes graphite doesn't seem to realise this!)
845
    if (maxmnWidth > mnWidth * factor + char_extra * (mnEndCharPos - mnMinCharPos - 1))
807
    if (targetWidth > mnWidth)
808
        return STRING_LEN;
846
        return STRING_LEN;
809
    //int    nBreak = mpSegment->findNextBreakPoint(mnMinCharPos,
810
    //        gr::klbWordBreak, gr::klbLetterBreak, targetWidth, &width);
811
847
812
    // LineFillSegment seems to give better results that findNextBreakPoint
848
    long nWidth = mvCharDxs[0] * factor;
813
    // though it may be slower
849
    int nLastBreak = -1;
814
    gr::LayoutEnvironment aLE;
850
    for (size_t i = 1; i < mvCharDxs.size(); i++)
815
    gr::LineFillSegment lineSeg(const_cast<gr::Font *>(&mrFont), mpTextSrc, &aLE,
851
    {
816
                                mnMinCharPos, mpTextSrc->getContextLength(),
852
        nWidth += char_extra;
817
                                targetWidth);
853
        if (nWidth > maxmnWidth) break;
818
    int nBreak = lineSeg.stopCharacter();
854
        if (mvChar2BaseGlyph[i] != -1)
855
        {
856
            if (mvChar2BaseGlyph[i] & (WORD_BREAK_BEFORE | HYPHEN_BREAK_BEFORE))
857
                nLastBreak = static_cast<int>(i);
858
        }
859
        nWidth += (mvCharDxs[i] - mvCharDxs[i-1]) * factor;
860
    }
861
    int nBreak = mnMinCharPos;
862
    if (nLastBreak > -1)
863
        nBreak += nLastBreak;
864
865
#ifdef GRLAYOUT_DEBUG
866
    fprintf(grLog(), "Gr::GetTextBreak break after %d\n", nBreak - mnMinCharPos);
867
#endif
819
868
820
    if (nBreak > mnEndCharPos) nBreak = STRING_LEN;
869
    if (nBreak > mnEndCharPos) nBreak = STRING_LEN;
821
    else if (nBreak < mnMinCharPos) nBreak = mnMinCharPos;
870
    else if (nBreak < mnMinCharPos) nBreak = mnMinCharPos;
Lines 833-841 Link Here
833
    {
882
    {
834
        for (size_t i = 0; i < mvCharDxs.size(); i++)
883
        for (size_t i = 0; i < mvCharDxs.size(); i++)
835
        {
884
        {
836
            assert((mvChar2BaseGlyph[i] >= -1) && (mvChar2BaseGlyph[i] < (signed)mvGlyphs.size()));
885
            assert((mvChar2BaseGlyph[i] >= -1) &&
886
                ((mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK) < (signed)mvGlyphs.size()));
837
            if (mvChar2BaseGlyph[i] != -1 &&
887
            if (mvChar2BaseGlyph[i] != -1 &&
838
                mvGlyphs[mvChar2BaseGlyph[i]].mnGlyphIndex == GF_DROPPED)
888
                mvGlyphs[mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK].mnGlyphIndex == GF_DROPPED)
839
            {
889
            {
840
                // when used in MultiSalLayout::GetTextBreak dropped glyphs
890
                // when used in MultiSalLayout::GetTextBreak dropped glyphs
841
                // must have zero width
891
                // must have zero width
Lines 865-871 Link Here
865
void  GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs)
915
void  GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs)
866
{
916
{
867
    SalLayout::AdjustLayout(rArgs);
917
    SalLayout::AdjustLayout(rArgs);
868
869
    if(rArgs.mpDXArray)
918
    if(rArgs.mpDXArray)
870
    {
919
    {
871
        std::vector<int> vDeltaWidths(mvGlyphs.size(), 0);
920
        std::vector<int> vDeltaWidths(mvGlyphs.size(), 0);
Lines 894-901 Link Here
894
            }
943
            }
895
        }
944
        }
896
    }
945
    }
946
    else if (rArgs.mnLayoutWidth > 0)
947
    {
948
#ifdef GRLAYOUT_DEBUG
949
        fprintf(grLog(), "AdjustLayout width %ld=>%ld\n", mnWidth, rArgs.mnLayoutWidth);
950
#endif
951
        expandOrCondense(rArgs);
952
    }
897
}
953
}
898
954
955
void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs)
956
{
957
    int nDeltaWidth = rArgs.mnLayoutWidth - mnWidth;
958
    if (nDeltaWidth > 0) // expand, just expand between clusters
959
    {
960
        int nClusterCount = 0;
961
        for (size_t j = 0; j < mvGlyphs.size(); j++)
962
        {
963
            if (mvGlyphs[j].IsClusterStart())
964
            {
965
                ++nClusterCount;
966
            }
967
        }
968
        if (nClusterCount > 1)
969
        {
970
            float fExtraPerCluster = static_cast<float>(nDeltaWidth) / static_cast<float>(nClusterCount - 1);
971
            int nCluster = 0;
972
            int nOffset = 0;
973
            for (size_t i = 0; i < mvGlyphs.size(); i++)
974
            {
975
                if (mvGlyphs[i].IsClusterStart())
976
                {
977
                    nOffset = fExtraPerCluster * nCluster;
978
                    size_t nCharIndex = mvGlyph2Char[i];
979
                    mvCharDxs[nCharIndex] += nOffset;
980
                    // adjust char dxs for rest of characters in cluster
981
                    while (++nCharIndex < mvGlyph2Char.size())
982
                    {
983
                        int nChar2Base = (mvChar2BaseGlyph[nCharIndex] == -1)? -1 : mvChar2BaseGlyph[nCharIndex] & GLYPH_INDEX_MASK;
984
                        if (nChar2Base == -1 || nChar2Base == static_cast<int>(i))
985
                            mvCharDxs[nCharIndex] += nOffset;
986
                    }
987
                    ++nCluster;
988
                }
989
                mvGlyphs[i].maLinearPos.X() += nOffset;
990
            }
991
        }
992
    }
993
    else // condense - apply a factor to all glyph positions
994
    {
995
        if (mvGlyphs.size() == 0) return;
996
        Glyphs::iterator iLastGlyph = mvGlyphs.begin() + (mvGlyphs.size() - 1);
997
        // position last glyph using original width
998
        float fXFactor = static_cast<float>(rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth) / static_cast<float>(iLastGlyph->maLinearPos.X());
999
#ifdef GRLAYOUT_DEBUG
1000
        fprintf(grLog(), "Condense by factor %f\n", fXFactor);
1001
#endif
1002
        iLastGlyph->maLinearPos.X() = rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth;
1003
        Glyphs::iterator iGlyph = mvGlyphs.begin();
1004
        while (iGlyph != iLastGlyph)
1005
        {
1006
            iGlyph->maLinearPos.X() = static_cast<float>(iGlyph->maLinearPos.X()) * fXFactor;
1007
            ++iGlyph;
1008
        }
1009
        for (size_t i = 0; i < mvCharDxs.size(); i++)
1010
        {
1011
            mvCharDxs[i] = fXFactor * static_cast<float>(mvCharDxs[i]);
1012
        }
1013
    }
1014
}
899
1015
900
void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDeltaWidth)
1016
void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDeltaWidth)
901
{
1017
{
Lines 917-953 Link Here
917
    int nPrevClusterLastChar = -1;
1033
    int nPrevClusterLastChar = -1;
918
    for (size_t i = 0; i < nChars; i++)
1034
    for (size_t i = 0; i < nChars; i++)
919
    {
1035
    {
920
        if (mvChar2BaseGlyph[i] > -1 && mvChar2BaseGlyph[i] != nPrevClusterGlyph)
1036
        int nChar2Base = (mvChar2BaseGlyph[i] == -1)? -1 : mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK;
1037
        if ((nChar2Base > -1) && (nChar2Base != nPrevClusterGlyph))
921
        {
1038
        {
922
            assert((mvChar2BaseGlyph[i] > -1) && (mvChar2BaseGlyph[i] < (signed)mvGlyphs.size()));
1039
            assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size()));
923
            GlyphItem & gi = mvGlyphs[mvChar2BaseGlyph[i]];
1040
            GlyphItem & gi = mvGlyphs[nChar2Base];
924
            if (!gi.IsClusterStart())
1041
            if (!gi.IsClusterStart())
925
                continue;
1042
                continue;
926
1043
927
            // find last glyph of this cluster
1044
            // find last glyph of this cluster
928
            size_t j = i + 1;
1045
            size_t j = i + 1;
929
            int nLastChar = i;
1046
            int nLastChar = i;
930
            int nLastGlyph = mvChar2BaseGlyph[i];
1047
            int nLastGlyph = nChar2Base;
931
            for (; j < nChars; j++)
1048
            for (; j < nChars; j++)
932
            {
1049
            {
933
                assert((mvChar2BaseGlyph[j] >= -1) && (mvChar2BaseGlyph[j] < (signed)mvGlyphs.size()));
1050
                int nChar2BaseJ = (mvChar2BaseGlyph[j] == -1)? -1 : mvChar2BaseGlyph[j] & GLYPH_INDEX_MASK;
934
                if (mvChar2BaseGlyph[j] != -1 && mvGlyphs[mvChar2BaseGlyph[j]].IsClusterStart())
1051
                assert((nChar2BaseJ >= -1) && (nChar2BaseJ < (signed)mvGlyphs.size()));
1052
                if (nChar2BaseJ != -1 && mvGlyphs[nChar2BaseJ].IsClusterStart())
935
                {
1053
                {
936
                    nLastGlyph = mvChar2BaseGlyph[j] + ((bRtl)? 1 : -1);
1054
                    nLastGlyph = nChar2BaseJ + ((bRtl)? 1 : -1);
937
                    nLastChar = j - 1;
1055
                    nLastChar = j - 1;
938
                    break;
1056
                    break;
939
                }
1057
                }
940
            }
1058
            }
941
            if (nLastGlyph < 0)
1059
            if (nLastGlyph < 0)
942
            {
1060
            {
943
                nLastGlyph = mvChar2BaseGlyph[i];
1061
                nLastGlyph = nChar2Base;
944
            }
1062
            }
945
            // Its harder to find the last glyph rtl, since the first of
1063
            // Its harder to find the last glyph rtl, since the first of
946
            // cluster is still on the left so we need to search towards
1064
            // cluster is still on the left so we need to search towards
947
            // the previous cluster to the right
1065
            // the previous cluster to the right
948
            if (bRtl)
1066
            if (bRtl)
949
            {
1067
            {
950
                nLastGlyph = mvChar2BaseGlyph[i];
1068
                nLastGlyph = nChar2Base;
951
                while (nLastGlyph + 1 < (signed)mvGlyphs.size() &&
1069
                while (nLastGlyph + 1 < (signed)mvGlyphs.size() &&
952
                       !mvGlyphs[nLastGlyph+1].IsClusterStart())
1070
                       !mvGlyphs[nLastGlyph+1].IsClusterStart())
953
                {
1071
                {
Lines 983-989 Link Here
983
            // update glyph positions
1101
            // update glyph positions
984
            if (bRtl)
1102
            if (bRtl)
985
            {
1103
            {
986
                for (int n = mvChar2BaseGlyph[i]; n <= nLastGlyph; n++)
1104
                for (int n = nChar2Base; n <= nLastGlyph; n++)
987
                {
1105
                {
988
                    assert((n > - 1) && (n < (signed)mvGlyphs.size()));
1106
                    assert((n > - 1) && (n < (signed)mvGlyphs.size()));
989
                    mvGlyphs[n].maLinearPos.X() += -nDGlyphOrigin + nXOffset;
1107
                    mvGlyphs[n].maLinearPos.X() += -nDGlyphOrigin + nXOffset;
Lines 991-1007 Link Here
991
            }
1109
            }
992
            else
1110
            else
993
            {
1111
            {
994
                for (int n = mvChar2BaseGlyph[i]; n <= nLastGlyph; n++)
1112
                for (int n = nChar2Base; n <= nLastGlyph; n++)
995
                {
1113
                {
996
                    assert((n > - 1) && (n < (signed)mvGlyphs.size()));
1114
                    assert((n > - 1) && (n < (signed)mvGlyphs.size()));
997
                    mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + nXOffset;
1115
                    mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + nXOffset;
998
                }
1116
                }
999
            }
1117
            }
1000
            rDeltaWidth[mvChar2BaseGlyph[i]] = nDWidth;
1118
            rDeltaWidth[nChar2Base] = nDWidth;
1001
#ifdef GRLAYOUT_DEBUG
1119
#ifdef GRLAYOUT_DEBUG
1002
            fprintf(grLog(),"c%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld\t", (int)i, mvChar2BaseGlyph[i], nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[mvChar2BaseGlyph[i]].maLinearPos.X());
1120
            fprintf(grLog(),"c%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld\t", (int)i, nChar2Base, nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[nChar2Base].maLinearPos.X());
1003
#endif
1121
#endif
1004
            nPrevClusterGlyph = mvChar2BaseGlyph[i];
1122
            nPrevClusterGlyph = nChar2Base;
1005
            nPrevClusterLastChar = nLastChar;
1123
            nPrevClusterLastChar = nLastChar;
1006
            i = nLastChar;
1124
            i = nLastChar;
1007
        }
1125
        }
Lines 1043-1049 Link Here
1043
            continue;
1161
            continue;
1044
        }
1162
        }
1045
        // calculate gap, ignore if too small
1163
        // calculate gap, ignore if too small
1046
        int nGapWidth = rDeltaWidths[nOrigGlyphIndex];;
1164
        int nGapWidth = rDeltaWidths[nOrigGlyphIndex];
1047
        // worst case is one kashida even for mini-gaps
1165
        // worst case is one kashida even for mini-gaps
1048
        if( 3 * nGapWidth < nKashidaWidth )
1166
        if( 3 * nGapWidth < nKashidaWidth )
1049
        {
1167
        {
Lines 1104-1116 Link Here
1104
    {
1222
    {
1105
        if (mvChar2BaseGlyph[nCharSlot] != -1)
1223
        if (mvChar2BaseGlyph[nCharSlot] != -1)
1106
        {
1224
        {
1107
            assert((mvChar2BaseGlyph[nCharSlot] > -1) && (mvChar2BaseGlyph[nCharSlot] < (signed)mvGlyphs.size()));
1225
            int nChar2Base = mvChar2BaseGlyph[nCharSlot] & GLYPH_INDEX_MASK;
1108
            GlyphItem gi = mvGlyphs[mvChar2BaseGlyph[nCharSlot]];
1226
            assert((mvChar2BaseGlyph[nCharSlot] > -1) && (nChar2Base < (signed)mvGlyphs.size()));
1227
            GlyphItem gi = mvGlyphs[nChar2Base];
1109
            if (gi.mnGlyphIndex == GF_DROPPED)
1228
            if (gi.mnGlyphIndex == GF_DROPPED)
1110
            {
1229
            {
1111
                continue;
1230
                continue;
1112
            }
1231
            }
1113
            int nCluster = mvChar2BaseGlyph[nCharSlot];
1232
            int nCluster = nChar2Base;
1114
            long origClusterWidth = gi.mnNewWidth;
1233
            long origClusterWidth = gi.mnNewWidth;
1115
            long nMin = gi.maLinearPos.X();
1234
            long nMin = gi.maLinearPos.X();
1116
            long nMax = gi.maLinearPos.X() + gi.mnNewWidth;
1235
            long nMax = gi.maLinearPos.X() + gi.mnNewWidth;
Lines 1135-1141 Link Here
1135
                pCaretXArray[i] = nMin;
1254
                pCaretXArray[i] = nMin;
1136
                pCaretXArray[i+1] = nMax;
1255
                pCaretXArray[i+1] = nMax;
1137
            }
1256
            }
1138
            prevBase = mvChar2BaseGlyph[nCharSlot];
1257
            prevBase = nChar2Base;
1139
            prevClusterWidth = origClusterWidth;
1258
            prevClusterWidth = origClusterWidth;
1140
        }
1259
        }
1141
        else if (prevBase > -1)
1260
        else if (prevBase > -1)
Lines 1268-1274 Link Here
1268
1387
1269
#ifdef GRLAYOUT_DEBUG
1388
#ifdef GRLAYOUT_DEBUG
1270
    fprintf(grLog(),"GetNextGlyphs g%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", glyph_slot - 1,
1389
    fprintf(grLog(),"GetNextGlyphs g%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", glyph_slot - 1,
1271
            mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance,
1390
            GLYPH_INDEX_MASK&mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance,
1272
            aPosOut.X(), aPosOut.Y());
1391
            aPosOut.X(), aPosOut.Y());
1273
#endif
1392
#endif
1274
1393

Return to issue 111054