19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
109f62ea84SAndrew Rist  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
129f62ea84SAndrew Rist  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
199f62ea84SAndrew Rist  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
229f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // Description: An implementation of the SalLayout interface that uses the
25cdf0e10cSrcweir //              Graphite engine.
26cdf0e10cSrcweir 
27cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
28cdf0e10cSrcweir #include "precompiled_vcl.hxx"
29cdf0e10cSrcweir 
30cdf0e10cSrcweir // We need this to enable namespace support in libgrengine headers.
31cdf0e10cSrcweir #define GR_NAMESPACE
32cdf0e10cSrcweir 
33cdf0e10cSrcweir // Enable lots of debug info
34cdf0e10cSrcweir #ifdef DEBUG
35cdf0e10cSrcweir //#define GRLAYOUT_DEBUG 1
36cdf0e10cSrcweir //#undef NDEBUG
37cdf0e10cSrcweir #endif
38cdf0e10cSrcweir 
39cdf0e10cSrcweir // Header files
40cdf0e10cSrcweir //
41cdf0e10cSrcweir // Standard Library
42cdf0e10cSrcweir #include <algorithm>
43cdf0e10cSrcweir #include <cassert>
44cdf0e10cSrcweir #include <functional>
45cdf0e10cSrcweir #include <limits>
46cdf0e10cSrcweir #include <numeric>
47cdf0e10cSrcweir #include <deque>
48cdf0e10cSrcweir 
49cdf0e10cSrcweir // Platform
50cdf0e10cSrcweir #ifdef WNT
51cdf0e10cSrcweir #include <tools/svwin.h>
52cdf0e10cSrcweir #include <svsys.h>
53cdf0e10cSrcweir #endif
54cdf0e10cSrcweir 
55cdf0e10cSrcweir #ifdef UNX
56cdf0e10cSrcweir #include <graphite_adaptors.hxx>
57cdf0e10cSrcweir #endif
58cdf0e10cSrcweir 
59cdf0e10cSrcweir #include <salgdi.hxx>
60cdf0e10cSrcweir 
61cdf0e10cSrcweir #include <unicode/uchar.h>
62cdf0e10cSrcweir #include <unicode/ubidi.h>
63cdf0e10cSrcweir #include <unicode/uscript.h>
64cdf0e10cSrcweir 
65cdf0e10cSrcweir // Graphite Libraries (must be after vcl headers on windows)
66cdf0e10cSrcweir #include <preextstl.h>
67cdf0e10cSrcweir #include <graphite/GrClient.h>
68cdf0e10cSrcweir #include <graphite/Font.h>
69cdf0e10cSrcweir #include <graphite/ITextSource.h>
70cdf0e10cSrcweir #include <graphite/Segment.h>
71cdf0e10cSrcweir #include <graphite/SegmentPainter.h>
72cdf0e10cSrcweir #include <postextstl.h>
73cdf0e10cSrcweir 
74cdf0e10cSrcweir #include <graphite_layout.hxx>
75cdf0e10cSrcweir #include <graphite_features.hxx>
76cdf0e10cSrcweir #include "graphite_textsrc.hxx"
77cdf0e10cSrcweir 
78cdf0e10cSrcweir 
79cdf0e10cSrcweir // Module private type definitions and forward declarations.
80cdf0e10cSrcweir //
81cdf0e10cSrcweir // Module private names.
82cdf0e10cSrcweir //
83cdf0e10cSrcweir 
84cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
85cdf0e10cSrcweir FILE * grLogFile = NULL;
grLog()86cdf0e10cSrcweir FILE * grLog()
87cdf0e10cSrcweir {
88cdf0e10cSrcweir #ifdef WNT
89cdf0e10cSrcweir     std::string logFileName(getenv("TEMP"));
90cdf0e10cSrcweir     logFileName.append("\\graphitelayout.log");
91cdf0e10cSrcweir     if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w");
92cdf0e10cSrcweir     else fflush(grLogFile);
93cdf0e10cSrcweir     return grLogFile;
94cdf0e10cSrcweir #else
95cdf0e10cSrcweir     return stdout;
96cdf0e10cSrcweir #endif
97cdf0e10cSrcweir }
98cdf0e10cSrcweir #endif
99cdf0e10cSrcweir 
100cdf0e10cSrcweir #ifdef GRCACHE
101cdf0e10cSrcweir #include <graphite_cache.hxx>
102cdf0e10cSrcweir #endif
103cdf0e10cSrcweir 
104cdf0e10cSrcweir 
105cdf0e10cSrcweir namespace
106cdf0e10cSrcweir {
107cdf0e10cSrcweir     typedef ext_std::pair<gr::GlyphIterator, gr::GlyphIterator>       glyph_range_t;
108cdf0e10cSrcweir     typedef ext_std::pair<gr::GlyphSetIterator, gr::GlyphSetIterator> glyph_set_range_t;
109cdf0e10cSrcweir 
round2long(const float n)110*f549c9e0Struckman     inline long round2long(const float n) {
111cdf0e10cSrcweir         return long(n + (n < 0 ? -0.5 : 0.5));
112cdf0e10cSrcweir     }
113cdf0e10cSrcweir 
114cdf0e10cSrcweir 
115cdf0e10cSrcweir     template<typename T>
in_range(const T i,const T b,const T e)116cdf0e10cSrcweir     inline bool in_range(const T i, const T b, const T e) {
117cdf0e10cSrcweir         return !(b > i) && i < e;
118cdf0e10cSrcweir     }
119cdf0e10cSrcweir 
120cdf0e10cSrcweir 
121cdf0e10cSrcweir     template<typename T>
is_subrange(const T sb,const T se,const T b,const T e)122cdf0e10cSrcweir     inline bool is_subrange(const T sb, const T se, const T b, const T e) {
123cdf0e10cSrcweir         return !(b > sb || se > e);
124cdf0e10cSrcweir     }
125cdf0e10cSrcweir 
126cdf0e10cSrcweir 
127cdf0e10cSrcweir     template<typename T>
is_subrange(const std::pair<T,T> & s,const T b,const T e)128cdf0e10cSrcweir     inline bool is_subrange(const std::pair<T, T> &s, const T b, const T e) {
129cdf0e10cSrcweir         return is_subrange(s.first, s.second, b, e);
130cdf0e10cSrcweir     }
131cdf0e10cSrcweir 
findSameDirLimit(const xub_Unicode * buffer,int charCount,bool rtl)132cdf0e10cSrcweir     int findSameDirLimit(const xub_Unicode* buffer, int charCount, bool rtl)
133cdf0e10cSrcweir     {
134cdf0e10cSrcweir         UErrorCode status = U_ZERO_ERROR;
135cdf0e10cSrcweir         UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
136cdf0e10cSrcweir         int limit = 0;
137cdf0e10cSrcweir         ubidi_setPara(ubidi, reinterpret_cast<const UChar *>(buffer), charCount,
138cdf0e10cSrcweir             (rtl)?UBIDI_DEFAULT_RTL:UBIDI_DEFAULT_LTR, NULL, &status);
139cdf0e10cSrcweir         UBiDiLevel level = 0;
140cdf0e10cSrcweir         ubidi_getLogicalRun(ubidi, 0, &limit, &level);
141cdf0e10cSrcweir         ubidi_close(ubidi);
142cdf0e10cSrcweir         if ((rtl && !(level & 1)) || (!rtl && (level & 1)))
143cdf0e10cSrcweir         {
144cdf0e10cSrcweir             limit = 0;
145cdf0e10cSrcweir         }
146cdf0e10cSrcweir         return limit;
147cdf0e10cSrcweir     }
148cdf0e10cSrcweir 
149cdf0e10cSrcweir } // namespace
150cdf0e10cSrcweir 
151cdf0e10cSrcweir 
152cdf0e10cSrcweir 
153cdf0e10cSrcweir // Impementation of the GraphiteLayout::Glyphs container class.
154cdf0e10cSrcweir //    This is an extended vector class with methods added to enable
155cdf0e10cSrcweir //        o Correctly filling with glyphs.
156cdf0e10cSrcweir //        o Querying clustering relationships.
157cdf0e10cSrcweir //        o manipulations that affect neighouring glyphs.
158cdf0e10cSrcweir 
159cdf0e10cSrcweir const int GraphiteLayout::EXTRA_CONTEXT_LENGTH = 10;
160cdf0e10cSrcweir #ifdef GRCACHE
161cdf0e10cSrcweir GraphiteCacheHandler GraphiteCacheHandler::instance;
162cdf0e10cSrcweir #endif
163cdf0e10cSrcweir 
164cdf0e10cSrcweir // The Graphite glyph stream is really a sequence of glyph attachment trees
165cdf0e10cSrcweir //  each rooted at a non-attached base glyph.  fill_from walks the glyph stream
166cdf0e10cSrcweir //  find each non-attached base glyph and calls append to record them as a
167cdf0e10cSrcweir //  sequence of clusters.
168cdf0e10cSrcweir void
fill_from(gr::Segment & rSegment,ImplLayoutArgs & rArgs,bool bRtl,long & rWidth,float fScaling,std::vector<int> & rChar2Base,std::vector<int> & rGlyph2Char,std::vector<int> & rCharDxs)169cdf0e10cSrcweir GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs,
170cdf0e10cSrcweir     bool bRtl, long &rWidth, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs)
171cdf0e10cSrcweir {
172cdf0e10cSrcweir     // Create a glyph item for each of the glyph and append it to the base class glyph list.
173cdf0e10cSrcweir     typedef ext_std::pair< gr::GlyphSetIterator, gr::GlyphSetIterator > GrGlyphSet;
174cdf0e10cSrcweir     int nChar = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
175cdf0e10cSrcweir     glyph_range_t iGlyphs = rSegment.glyphs();
176cdf0e10cSrcweir     int nGlyphs = iGlyphs.second - iGlyphs.first;
177cdf0e10cSrcweir     gr::GlyphIterator prevBase = iGlyphs.second;
178cdf0e10cSrcweir     float fSegmentAdvance = rSegment.advanceWidth();
179cdf0e10cSrcweir     float fMinX = fSegmentAdvance;
180cdf0e10cSrcweir     float fMaxX = 0.0f;
181cdf0e10cSrcweir     rGlyph2Char.assign(nGlyphs, -1);
182cdf0e10cSrcweir     long nDxOffset = 0;
183cdf0e10cSrcweir     int nGlyphIndex = (bRtl)? (nGlyphs - 1) : 0;
184cdf0e10cSrcweir     // OOo always expects the glyphs in ltr order
185cdf0e10cSrcweir     int nDelta = (bRtl)? -1 : 1;
186cdf0e10cSrcweir 
187cdf0e10cSrcweir     int nLastGlyph = (bRtl)? nGlyphs - 1: 0;
188cdf0e10cSrcweir     int nNextChar = (bRtl)? (rSegment.stopCharacter() - 1) : rSegment.startCharacter();//rArgs.mnMinCharPos;
189cdf0e10cSrcweir     // current glyph number (Graphite glyphs)
190cdf0e10cSrcweir     //int currGlyph = 0;
191cdf0e10cSrcweir     int nFirstCharInCluster = nNextChar;
192cdf0e10cSrcweir     int nFirstGlyphInCluster = nLastGlyph;
193cdf0e10cSrcweir 
194cdf0e10cSrcweir     // ltr first char in cluster is lowest, same is true for rtl
195cdf0e10cSrcweir     // ltr first glyph in cluster is lowest, rtl first glyph is highest
196cdf0e10cSrcweir 
197cdf0e10cSrcweir     // loop over the glyphs determining which characters are linked to them
198cdf0e10cSrcweir     gr::GlyphIterator gi;
199cdf0e10cSrcweir     for (gi = iGlyphs.first + nGlyphIndex;
200cdf0e10cSrcweir          nGlyphIndex >= 0 && nGlyphIndex < nGlyphs;
201cdf0e10cSrcweir          nGlyphIndex+= nDelta, gi = iGlyphs.first + nGlyphIndex)
202cdf0e10cSrcweir     {
203cdf0e10cSrcweir         gr::GlyphInfo info = (*gi);
204cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
205cdf0e10cSrcweir         fprintf(grLog(),"Glyph %d %f,%f\n", (int)info.logicalIndex(), info.origin(), info.yOffset());
206cdf0e10cSrcweir #endif
207cdf0e10cSrcweir         // the last character associated with this glyph is after
208cdf0e10cSrcweir         // our current cluster buffer position
209cdf0e10cSrcweir         if ((bRtl && ((signed)info.firstChar() <= nNextChar)) ||
210cdf0e10cSrcweir             (!bRtl && ((signed)info.lastChar() >= nNextChar)))
211cdf0e10cSrcweir         {
212cdf0e10cSrcweir             if ((bRtl && nGlyphIndex < nLastGlyph) ||
213cdf0e10cSrcweir                 (!bRtl && nGlyphIndex > nLastGlyph))
214cdf0e10cSrcweir             {
215cdf0e10cSrcweir                 // this glyph is after the previous one left->right
216cdf0e10cSrcweir                 // if insertion is allowed before it then we are in a
217cdf0e10cSrcweir                 // new cluster
218cdf0e10cSrcweir                 int nAttachedBase = (*(info.attachedClusterBase())).logicalIndex();
219cdf0e10cSrcweir                 if (!info.isAttached() ||
220cdf0e10cSrcweir                     !in_range(nAttachedBase, nFirstGlyphInCluster, nGlyphIndex))
221cdf0e10cSrcweir                 {
222cdf0e10cSrcweir                     if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) &&
223cdf0e10cSrcweir                         nFirstGlyphInCluster != nGlyphIndex)
224cdf0e10cSrcweir                     {
225cdf0e10cSrcweir                         std::pair <float,float> aBounds =
226cdf0e10cSrcweir                             appendCluster(rSegment, rArgs, bRtl,
227cdf0e10cSrcweir                             fSegmentAdvance, nFirstCharInCluster,
228cdf0e10cSrcweir                             nNextChar, nFirstGlyphInCluster, nGlyphIndex, fScaling,
229cdf0e10cSrcweir                             rChar2Base, rGlyph2Char, rCharDxs, nDxOffset);
230cdf0e10cSrcweir                         fMinX = std::min(aBounds.first, fMinX);
231cdf0e10cSrcweir                         fMaxX = std::max(aBounds.second, fMaxX);
232cdf0e10cSrcweir                     }
233cdf0e10cSrcweir                     nFirstCharInCluster = (bRtl)? info.lastChar() : info.firstChar();
234cdf0e10cSrcweir                     nFirstGlyphInCluster = nGlyphIndex;
235cdf0e10cSrcweir                 }
236cdf0e10cSrcweir                 nLastGlyph = (bRtl)? std::min(nGlyphIndex, nAttachedBase) :
237cdf0e10cSrcweir                     std::max(nGlyphIndex, nAttachedBase);
238cdf0e10cSrcweir             }
239cdf0e10cSrcweir             // loop over chacters associated with this glyph and characters
240cdf0e10cSrcweir             // between nextChar and the last character associated with this glyph
241cdf0e10cSrcweir             // giving them the current cluster id.  This allows for character /glyph
242cdf0e10cSrcweir             // order reversal.
243cdf0e10cSrcweir             // For each character we do a reverse glyph id look up
244cdf0e10cSrcweir             // and store the glyph id with the highest logical index in nLastGlyph
245cdf0e10cSrcweir             while ((bRtl && ((signed)info.firstChar() <= nNextChar)) ||
246cdf0e10cSrcweir                    (!bRtl && (signed)info.lastChar() >= nNextChar))
247cdf0e10cSrcweir             {
248cdf0e10cSrcweir                 GrGlyphSet charGlyphs = rSegment.charToGlyphs(nNextChar);
249cdf0e10cSrcweir                 nNextChar += nDelta;
250cdf0e10cSrcweir                 gr::GlyphSetIterator gj = charGlyphs.first;
251cdf0e10cSrcweir                 while (gj != charGlyphs.second)
252cdf0e10cSrcweir                 {
253cdf0e10cSrcweir                     nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*gj).logicalIndex()) : max(nLastGlyph, (signed)(*gj).logicalIndex());
254cdf0e10cSrcweir                     ++gj;
255cdf0e10cSrcweir                 }
256cdf0e10cSrcweir             }
257cdf0e10cSrcweir             // Loop over attached glyphs and make sure they are all in the cluster since you
258cdf0e10cSrcweir             // can have glyphs attached with another base glyph in between
259cdf0e10cSrcweir             glyph_set_range_t iAttached = info.attachedClusterGlyphs();
260cdf0e10cSrcweir             for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi)
261cdf0e10cSrcweir             {
262cdf0e10cSrcweir                 nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*agi).logicalIndex()) : max(nLastGlyph, (signed)(*agi).logicalIndex());
263cdf0e10cSrcweir             }
264cdf0e10cSrcweir 
265cdf0e10cSrcweir             // if this is a rtl attached glyph, then we need to include its
266cdf0e10cSrcweir             // base in the cluster, which will have a lower graphite index
267cdf0e10cSrcweir             if (bRtl)
268cdf0e10cSrcweir             {
269cdf0e10cSrcweir                 if ((signed)info.attachedClusterBase()->logicalIndex() < nLastGlyph)
270cdf0e10cSrcweir                 {
271cdf0e10cSrcweir                     nLastGlyph = info.attachedClusterBase()->logicalIndex();
272cdf0e10cSrcweir                 }
273cdf0e10cSrcweir             }
274cdf0e10cSrcweir         }
275cdf0e10cSrcweir 
276cdf0e10cSrcweir         // it is possible for the lastChar to be after nextChar and
277cdf0e10cSrcweir         // firstChar to be before the nFirstCharInCluster in rare
278cdf0e10cSrcweir         // circumstances e.g. Myanmar word for cemetery
279cdf0e10cSrcweir         if ((bRtl && ((signed)info.lastChar() > nFirstCharInCluster)) ||
280cdf0e10cSrcweir             (!bRtl && ((signed)info.firstChar() < nFirstCharInCluster)))
281cdf0e10cSrcweir         {
282cdf0e10cSrcweir             nFirstCharInCluster = info.firstChar();
283cdf0e10cSrcweir         }
284cdf0e10cSrcweir     }
285cdf0e10cSrcweir     // process last cluster
286cdf0e10cSrcweir     if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) &&
287cdf0e10cSrcweir         nFirstGlyphInCluster != nGlyphIndex)
288cdf0e10cSrcweir     {
289cdf0e10cSrcweir         std::pair <float,float> aBounds =
290cdf0e10cSrcweir             appendCluster(rSegment, rArgs, bRtl, fSegmentAdvance,
291cdf0e10cSrcweir                           nFirstCharInCluster, nNextChar,
292cdf0e10cSrcweir                           nFirstGlyphInCluster, nGlyphIndex, fScaling,
293cdf0e10cSrcweir                           rChar2Base, rGlyph2Char, rCharDxs, nDxOffset);
294cdf0e10cSrcweir         fMinX = std::min(aBounds.first, fMinX);
295cdf0e10cSrcweir         fMaxX = std::max(aBounds.second, fMaxX);
296cdf0e10cSrcweir     }
297*f549c9e0Struckman     long nXOffset = round2long(fMinX * fScaling);
298*f549c9e0Struckman     rWidth = round2long(fMaxX * fScaling) - nXOffset + nDxOffset;
299cdf0e10cSrcweir     if (rWidth < 0)
300cdf0e10cSrcweir     {
301cdf0e10cSrcweir         // This can happen when there was no base inside the range
302cdf0e10cSrcweir         rWidth = 0;
303cdf0e10cSrcweir     }
304cdf0e10cSrcweir     // fill up non-base char dx with cluster widths from previous base glyph
305cdf0e10cSrcweir     if (bRtl)
306cdf0e10cSrcweir     {
307cdf0e10cSrcweir         if (rCharDxs[nChar-1] == -1)
308cdf0e10cSrcweir             rCharDxs[nChar-1] = 0;
309cdf0e10cSrcweir         else
310cdf0e10cSrcweir             rCharDxs[nChar-1] -= nXOffset;
311cdf0e10cSrcweir         for (int i = nChar - 2; i >= 0; i--)
312cdf0e10cSrcweir         {
313cdf0e10cSrcweir             if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i+1];
314cdf0e10cSrcweir             else rCharDxs[i] -= nXOffset;
315cdf0e10cSrcweir         }
316cdf0e10cSrcweir     }
317cdf0e10cSrcweir     else
318cdf0e10cSrcweir     {
319cdf0e10cSrcweir         if (rCharDxs[0] == -1)
320cdf0e10cSrcweir             rCharDxs[0] = 0;
321cdf0e10cSrcweir         else
322cdf0e10cSrcweir             rCharDxs[0] -= nXOffset;
323cdf0e10cSrcweir         for (int i = 1; i < nChar; i++)
324cdf0e10cSrcweir         {
325cdf0e10cSrcweir             if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i-1];
326cdf0e10cSrcweir             else rCharDxs[i] -= nXOffset;
327cdf0e10cSrcweir         }
328cdf0e10cSrcweir     }
329cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
330cdf0e10cSrcweir     fprintf(grLog(),"Glyphs xOff%ld dropDx%ld w%ld\n", nXOffset, nDxOffset, rWidth);
331cdf0e10cSrcweir #endif
332cdf0e10cSrcweir     // remove offset due to context if there is one
333cdf0e10cSrcweir     if (nXOffset != 0)
334cdf0e10cSrcweir     {
335cdf0e10cSrcweir         for (size_t i = 0; i < size(); i++)
336cdf0e10cSrcweir             (*this)[i].maLinearPos.X() -= nXOffset;
337cdf0e10cSrcweir     }
338cdf0e10cSrcweir }
339cdf0e10cSrcweir 
appendCluster(gr::Segment & rSeg,ImplLayoutArgs & rArgs,bool bRtl,float fSegmentAdvance,int nFirstCharInCluster,int nNextChar,int nFirstGlyphInCluster,int nNextGlyph,float fScaling,std::vector<int> & rChar2Base,std::vector<int> & rGlyph2Char,std::vector<int> & rCharDxs,long & rDXOffset)340cdf0e10cSrcweir std::pair<float,float> GraphiteLayout::Glyphs::appendCluster(gr::Segment& rSeg,
341cdf0e10cSrcweir     ImplLayoutArgs & rArgs, bool bRtl,float fSegmentAdvance,
342cdf0e10cSrcweir     int nFirstCharInCluster, int nNextChar, int nFirstGlyphInCluster,
343cdf0e10cSrcweir     int nNextGlyph, float fScaling, std::vector<int> & rChar2Base,
344cdf0e10cSrcweir     std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset)
345cdf0e10cSrcweir {
346cdf0e10cSrcweir     glyph_range_t iGlyphs = rSeg.glyphs();
347cdf0e10cSrcweir     int nGlyphs = iGlyphs.second - iGlyphs.first;
348cdf0e10cSrcweir     int nDelta = (bRtl)? -1 : 1;
349cdf0e10cSrcweir     gr::GlyphInfo aFirstGlyph = *(iGlyphs.first + nFirstGlyphInCluster);
350cdf0e10cSrcweir     std::pair <float, float> aBounds;
351cdf0e10cSrcweir     aBounds.first = aFirstGlyph.origin();
352cdf0e10cSrcweir     aBounds.second = aFirstGlyph.origin();
353cdf0e10cSrcweir     // before we add the glyphs to this vector, we record the
354cdf0e10cSrcweir     // glyph's index in the vector (which is not the same as
355cdf0e10cSrcweir     // the Segment's glyph index!)
356cdf0e10cSrcweir     assert(size() < rGlyph2Char.size());
357cdf0e10cSrcweir     rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] = size();
358cdf0e10cSrcweir     rGlyph2Char[size()] = nFirstCharInCluster;
359cdf0e10cSrcweir 
360cdf0e10cSrcweir     // can we break before this cluster?
361cdf0e10cSrcweir     // Glyphs may have either a positive or negative breakWeight refering to
362cdf0e10cSrcweir     // the position after or before the glyph respectively
363cdf0e10cSrcweir     int nPrevBreakWeight = 0;
364cdf0e10cSrcweir     if (nFirstGlyphInCluster > 0)
365cdf0e10cSrcweir     {
366cdf0e10cSrcweir         nPrevBreakWeight = (iGlyphs.first + (nFirstGlyphInCluster - 1))->breakweight();
367cdf0e10cSrcweir     }
368cdf0e10cSrcweir     int nBreakWeight = aFirstGlyph.breakweight();
369cdf0e10cSrcweir     if (nBreakWeight < 0)
370cdf0e10cSrcweir     {
371cdf0e10cSrcweir         // negative means it applies to the position before the glyph's character
372cdf0e10cSrcweir         nBreakWeight *= -1;
373cdf0e10cSrcweir         if (nPrevBreakWeight > 0 && nPrevBreakWeight < nBreakWeight)
374cdf0e10cSrcweir         {
375cdf0e10cSrcweir             // prevBreakWeight wins
376cdf0e10cSrcweir             nBreakWeight = nPrevBreakWeight;
377cdf0e10cSrcweir         }
378cdf0e10cSrcweir     }
379cdf0e10cSrcweir     else
380cdf0e10cSrcweir     {
381cdf0e10cSrcweir         nBreakWeight = 0;
382cdf0e10cSrcweir         // positive means break after
383cdf0e10cSrcweir         if (nPrevBreakWeight > 0)
384cdf0e10cSrcweir             nBreakWeight = nPrevBreakWeight;
385cdf0e10cSrcweir     }
386cdf0e10cSrcweir     if (nBreakWeight > gr::klbNoBreak/*0*/ &&
387cdf0e10cSrcweir         // nBreakWeight <= gr::klbHyphenBreak) // uses Graphite hyphenation
388cdf0e10cSrcweir         nBreakWeight <= gr::klbLetterBreak) // Needed for issue 111272
389cdf0e10cSrcweir     {
390cdf0e10cSrcweir         if (nBreakWeight < gr::klbHyphenBreak)
391cdf0e10cSrcweir             rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE;
392cdf0e10cSrcweir         else
393cdf0e10cSrcweir             rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= HYPHEN_BREAK_BEFORE;
394cdf0e10cSrcweir     }
395cdf0e10cSrcweir     // always allow a break before a space even if graphite doesn't
396cdf0e10cSrcweir     if (rArgs.mpStr[nFirstCharInCluster] == 0x20)
397cdf0e10cSrcweir         rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE;
398cdf0e10cSrcweir 
399cdf0e10cSrcweir     bool bBaseGlyph = true;
400cdf0e10cSrcweir     for (int j = nFirstGlyphInCluster;
401cdf0e10cSrcweir         j != nNextGlyph; j += nDelta)
402cdf0e10cSrcweir     {
403cdf0e10cSrcweir         long nNextOrigin;
404cdf0e10cSrcweir         float fNextOrigin;
405cdf0e10cSrcweir         gr::GlyphInfo aGlyph = *(iGlyphs.first + j);
406cdf0e10cSrcweir         if (j + nDelta >= nGlyphs || j + nDelta < 0) // at rhs ltr,rtl
407cdf0e10cSrcweir         {
408cdf0e10cSrcweir             fNextOrigin = fSegmentAdvance;
409*f549c9e0Struckman             nNextOrigin = round2long(fSegmentAdvance * fScaling + rDXOffset);
410cdf0e10cSrcweir             aBounds.second = std::max(fSegmentAdvance, aBounds.second);
411cdf0e10cSrcweir         }
412cdf0e10cSrcweir         else
413cdf0e10cSrcweir         {
414cdf0e10cSrcweir             gr::GlyphInfo aNextGlyph = *(iGlyphs.first + j + nDelta);
415cdf0e10cSrcweir             fNextOrigin = std::max(aNextGlyph.attachedClusterBase()->origin(), aNextGlyph.origin());
416cdf0e10cSrcweir             aBounds.second = std::max(fNextOrigin, aBounds.second);
417*f549c9e0Struckman             nNextOrigin = round2long(fNextOrigin * fScaling + rDXOffset);
418cdf0e10cSrcweir         }
419cdf0e10cSrcweir         aBounds.first = std::min(aGlyph.origin(), aBounds.first);
420cdf0e10cSrcweir         if ((signed)aGlyph.firstChar() < rArgs.mnEndCharPos &&
421cdf0e10cSrcweir             (signed)aGlyph.firstChar() >= rArgs.mnMinCharPos)
422cdf0e10cSrcweir         {
423cdf0e10cSrcweir             rCharDxs[aGlyph.firstChar()-rArgs.mnMinCharPos] = nNextOrigin;
424cdf0e10cSrcweir         }
425cdf0e10cSrcweir         if ((signed)aGlyph.attachedClusterBase()->logicalIndex() == j)
426cdf0e10cSrcweir         {
427cdf0e10cSrcweir             append(rSeg, rArgs, aGlyph, fNextOrigin, fScaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, bBaseGlyph);
428cdf0e10cSrcweir             bBaseGlyph = false;
429cdf0e10cSrcweir         }
430cdf0e10cSrcweir     }
431cdf0e10cSrcweir     // from the point of view of the dx array, the xpos is
432cdf0e10cSrcweir     // the origin of the first glyph of the next cluster ltr
433cdf0e10cSrcweir     // rtl it is the origin of the 1st glyph of the cluster
434cdf0e10cSrcweir     long nXPos = (bRtl)?
435*f549c9e0Struckman         round2long(aFirstGlyph.attachedClusterBase()->origin() * fScaling) + rDXOffset :
436*f549c9e0Struckman         round2long(aBounds.second * fScaling) + rDXOffset;
437cdf0e10cSrcweir     // force the last char in range to have the width of the cluster
438cdf0e10cSrcweir     if (bRtl)
439cdf0e10cSrcweir     {
440cdf0e10cSrcweir         for (int n = nNextChar + 1; n <= nFirstCharInCluster; n++)
441cdf0e10cSrcweir         {
442cdf0e10cSrcweir             if ((n < rArgs.mnEndCharPos) && (n >= rArgs.mnMinCharPos))
443cdf0e10cSrcweir                 rCharDxs[n-rArgs.mnMinCharPos] = nXPos;
444cdf0e10cSrcweir         }
445cdf0e10cSrcweir     }
446cdf0e10cSrcweir     else
447cdf0e10cSrcweir     {
448cdf0e10cSrcweir         for (int n = nNextChar - 1; n >= nFirstCharInCluster; n--)
449cdf0e10cSrcweir         {
450cdf0e10cSrcweir             if (n < rArgs.mnEndCharPos && n >= rArgs.mnMinCharPos)
451cdf0e10cSrcweir                 rCharDxs[n-rArgs.mnMinCharPos] = nXPos;
452cdf0e10cSrcweir         }
453cdf0e10cSrcweir     }
454cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
455cdf0e10cSrcweir     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);
456cdf0e10cSrcweir #endif
457cdf0e10cSrcweir     return aBounds;
458cdf0e10cSrcweir }
459cdf0e10cSrcweir 
460cdf0e10cSrcweir // append walks an attachment tree, flattening it, and converting it into a
461cdf0e10cSrcweir // sequence of GlyphItem objects which we can later manipulate.
462cdf0e10cSrcweir void
append(gr::Segment & segment,ImplLayoutArgs & args,gr::GlyphInfo & gi,float nextGlyphOrigin,float scaling,std::vector<int> & rChar2Base,std::vector<int> & rGlyph2Char,std::vector<int> & rCharDxs,long & rDXOffset,bool bIsBase)463cdf0e10cSrcweir GraphiteLayout::Glyphs::append(gr::Segment &segment, ImplLayoutArgs &args, gr::GlyphInfo & gi, float nextGlyphOrigin, float scaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset, bool bIsBase)
464cdf0e10cSrcweir {
465cdf0e10cSrcweir     float nextOrigin = nextGlyphOrigin;
466cdf0e10cSrcweir     int firstChar = std::min(gi.firstChar(), gi.lastChar());
467cdf0e10cSrcweir     assert(size() < rGlyph2Char.size());
468cdf0e10cSrcweir     if (!bIsBase) rGlyph2Char[size()] = firstChar;
469cdf0e10cSrcweir     // is the next glyph attached or in the next cluster?
470cdf0e10cSrcweir     glyph_set_range_t iAttached = gi.attachedClusterGlyphs();
471cdf0e10cSrcweir     if (iAttached.first != iAttached.second)
472cdf0e10cSrcweir     {
473cdf0e10cSrcweir         nextOrigin = iAttached.first->origin();
474cdf0e10cSrcweir     }
475cdf0e10cSrcweir     long glyphId = gi.glyphID();
476cdf0e10cSrcweir     long deltaOffset = 0;
477*f549c9e0Struckman     int glyphWidth = round2long(nextOrigin * scaling) - round2long(gi.origin() * scaling);
478cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
479cdf0e10cSrcweir     fprintf(grLog(),"c%d g%d gWidth%d x%f ", firstChar, (int)gi.logicalIndex(), glyphWidth, nextOrigin);
480cdf0e10cSrcweir #endif
481cdf0e10cSrcweir     if (glyphId == 0)
482cdf0e10cSrcweir     {
483cdf0e10cSrcweir         args.NeedFallback(
484cdf0e10cSrcweir             firstChar,
485cdf0e10cSrcweir             gr::RightToLeftDir(gr::DirCode(gi.directionality())));
486cdf0e10cSrcweir         if( (SAL_LAYOUT_FOR_FALLBACK & args.mnFlags ))
487cdf0e10cSrcweir         {
488cdf0e10cSrcweir             glyphId = GF_DROPPED;
489cdf0e10cSrcweir             deltaOffset -= glyphWidth;
490cdf0e10cSrcweir             glyphWidth = 0;
491cdf0e10cSrcweir         }
492cdf0e10cSrcweir     }
493cdf0e10cSrcweir     else if(args.mnFlags & SAL_LAYOUT_FOR_FALLBACK)
494cdf0e10cSrcweir     {
495cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
496cdf0e10cSrcweir         fprintf(grLog(),"fallback c%d %x in run %d\n", firstChar, args.mpStr[firstChar],
497cdf0e10cSrcweir             args.maRuns.PosIsInAnyRun(firstChar));
498cdf0e10cSrcweir #endif
499cdf0e10cSrcweir         // glyphs that aren't requested for fallback will be taken from base
500cdf0e10cSrcweir         // layout, so mark them as dropped (should this wait until Simplify(false) is called?)
501cdf0e10cSrcweir         if (!args.maRuns.PosIsInAnyRun(firstChar) &&
502cdf0e10cSrcweir             in_range(firstChar, args.mnMinCharPos, args.mnEndCharPos))
503cdf0e10cSrcweir         {
504cdf0e10cSrcweir             glyphId = GF_DROPPED;
505cdf0e10cSrcweir             deltaOffset -= glyphWidth;
506cdf0e10cSrcweir             glyphWidth = 0;
507cdf0e10cSrcweir         }
508cdf0e10cSrcweir     }
509cdf0e10cSrcweir     // append this glyph.
510cdf0e10cSrcweir     long nGlyphFlags = bIsBase ? 0 : GlyphItem::IS_IN_CLUSTER;
511cdf0e10cSrcweir     // directionality seems to be unreliable
512cdf0e10cSrcweir     //nGlyphFlags |= gr::RightToLeftDir(gr::DirCode(gi.attachedClusterBase()->directionality())) ? GlyphItem::IS_RTL_GLYPH : 0;
513cdf0e10cSrcweir     nGlyphFlags |= (gi.directionLevel() & 0x1)? GlyphItem::IS_RTL_GLYPH : 0;
514cdf0e10cSrcweir     GlyphItem aGlyphItem(size(),//gi.logicalIndex(),
515cdf0e10cSrcweir         glyphId,
516*f549c9e0Struckman         Point(round2long(gi.origin() * scaling + rDXOffset),
517*f549c9e0Struckman             round2long((-gi.yOffset() * scaling) - segment.AscentOffset()* scaling)),
518cdf0e10cSrcweir         nGlyphFlags,
519cdf0e10cSrcweir         glyphWidth);
520*f549c9e0Struckman     aGlyphItem.mnOrigWidth = round2long(gi.advanceWidth() * scaling);
521cdf0e10cSrcweir     push_back(aGlyphItem);
522cdf0e10cSrcweir 
523cdf0e10cSrcweir     // update the offset if this glyph was dropped
524cdf0e10cSrcweir     rDXOffset += deltaOffset;
525cdf0e10cSrcweir 
526cdf0e10cSrcweir     // Recursively apply append all the attached glyphs.
527cdf0e10cSrcweir     for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi)
528cdf0e10cSrcweir     {
529cdf0e10cSrcweir         if (agi + 1 == iAttached.second)
530cdf0e10cSrcweir             append(segment, args, *agi, nextGlyphOrigin, scaling, rChar2Base, rGlyph2Char,rCharDxs, rDXOffset, false);
531cdf0e10cSrcweir         else
532cdf0e10cSrcweir             append(segment, args, *agi, (agi + 1)->origin(), scaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, false);
533cdf0e10cSrcweir     }
534cdf0e10cSrcweir }
535cdf0e10cSrcweir 
536cdf0e10cSrcweir //
537cdf0e10cSrcweir // An implementation of the SalLayout interface to enable Graphite enabled fonts to be used.
538cdf0e10cSrcweir //
GraphiteLayout(const gr::Font & font,const grutils::GrFeatureParser * pFeatures)539cdf0e10cSrcweir GraphiteLayout::GraphiteLayout(const gr::Font & font, const grutils::GrFeatureParser * pFeatures) throw()
540cdf0e10cSrcweir   : mpTextSrc(0),
541cdf0e10cSrcweir     mrFont(font),
542cdf0e10cSrcweir     mnWidth(0),
543cdf0e10cSrcweir     mfScaling(1.0),
544cdf0e10cSrcweir     mpFeatures(pFeatures)
545cdf0e10cSrcweir {
546cdf0e10cSrcweir     // Line settings can have subtle affects on space handling
547cdf0e10cSrcweir     // since we don't really know whether it is the end of a line or just a run
548cdf0e10cSrcweir     // in the middle, it is hard to know what to set them to.
549cdf0e10cSrcweir     // If true, it can cause end of line spaces to be hidden e.g. Doulos SIL
550cdf0e10cSrcweir     maLayout.setStartOfLine(false);
551cdf0e10cSrcweir     maLayout.setEndOfLine(false);
552cdf0e10cSrcweir     maLayout.setDumbFallback(true);
553cdf0e10cSrcweir     // trailing ws doesn't seem to always take affect if end of line is true
554cdf0e10cSrcweir     maLayout.setTrailingWs(gr::ktwshAll);
555cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
556cdf0e10cSrcweir     gr::ScriptDirCode aDirCode = font.getSupportedScriptDirections();
557cdf0e10cSrcweir     fprintf(grLog(),"GraphiteLayout scripts %x %lx\n", aDirCode, long(this));
558cdf0e10cSrcweir #endif
559cdf0e10cSrcweir }
560cdf0e10cSrcweir 
561cdf0e10cSrcweir 
~GraphiteLayout()562cdf0e10cSrcweir GraphiteLayout::~GraphiteLayout() throw()
563cdf0e10cSrcweir {
564cdf0e10cSrcweir     clear();
565cdf0e10cSrcweir     // the features are owned by the platform layers
566cdf0e10cSrcweir     mpFeatures = NULL;
567cdf0e10cSrcweir }
568cdf0e10cSrcweir 
clear()569cdf0e10cSrcweir void GraphiteLayout::clear()
570cdf0e10cSrcweir {
571cdf0e10cSrcweir     // Destroy the segment and text source from any previous invocation of
572cdf0e10cSrcweir     // LayoutText
573cdf0e10cSrcweir     mvGlyphs.clear();
574cdf0e10cSrcweir     mvCharDxs.clear();
575cdf0e10cSrcweir     mvChar2BaseGlyph.clear();
576cdf0e10cSrcweir     mvGlyph2Char.clear();
577cdf0e10cSrcweir 
578cdf0e10cSrcweir #ifndef GRCACHE
579cdf0e10cSrcweir     delete mpTextSrc;
580cdf0e10cSrcweir #endif
581cdf0e10cSrcweir 
582cdf0e10cSrcweir     // Reset the state to the empty state.
583cdf0e10cSrcweir     mpTextSrc=0;
584cdf0e10cSrcweir     mnWidth = 0;
585cdf0e10cSrcweir     // Don't reset the scaling, because it is set before LayoutText
586cdf0e10cSrcweir }
587cdf0e10cSrcweir 
588cdf0e10cSrcweir // This method shouldn't be called on windows, since it needs the dc reset
LayoutText(ImplLayoutArgs & rArgs)589cdf0e10cSrcweir bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs)
590cdf0e10cSrcweir {
591cdf0e10cSrcweir #ifdef GRCACHE
592cdf0e10cSrcweir     GrSegRecord * pSegRecord = NULL;
593cdf0e10cSrcweir     gr::Segment * pSegment = NULL;
594cdf0e10cSrcweir     // Graphite can in rare cases crash with a zero length
595cdf0e10cSrcweir     if (rArgs.mnMinCharPos < rArgs.mnEndCharPos)
596cdf0e10cSrcweir     {
597cdf0e10cSrcweir         pSegment = CreateSegment(rArgs, &pSegRecord);
598cdf0e10cSrcweir         if (!pSegment)
599cdf0e10cSrcweir             return false;
600cdf0e10cSrcweir     }
601cdf0e10cSrcweir     else
602cdf0e10cSrcweir     {
603cdf0e10cSrcweir         clear();
604cdf0e10cSrcweir         return true;
605cdf0e10cSrcweir     }
606cdf0e10cSrcweir     // layout the glyphs as required by OpenOffice
607cdf0e10cSrcweir     bool success = LayoutGlyphs(rArgs, pSegment, pSegRecord);
608cdf0e10cSrcweir 
609cdf0e10cSrcweir     if (pSegRecord) pSegRecord->unlock();
610cdf0e10cSrcweir     else delete pSegment;
611cdf0e10cSrcweir #else
612cdf0e10cSrcweir     gr::Segment * pSegment = NULL;
613cdf0e10cSrcweir     bool success = true;
614cdf0e10cSrcweir     if (rArgs.mnMinCharPos < rArgs.mnEndCharPos)
615cdf0e10cSrcweir     {
616cdf0e10cSrcweir         pSegment = CreateSegment(rArgs);
617cdf0e10cSrcweir         if (!pSegment)
618cdf0e10cSrcweir             return false;
619cdf0e10cSrcweir         success = LayoutGlyphs(rArgs, pSegment);
620cdf0e10cSrcweir         if (pSegment) delete pSegment;
621cdf0e10cSrcweir     }
622cdf0e10cSrcweir     else
623cdf0e10cSrcweir     {
624cdf0e10cSrcweir         clear();
625cdf0e10cSrcweir     }
626cdf0e10cSrcweir #endif
627cdf0e10cSrcweir     return success;
628cdf0e10cSrcweir }
629cdf0e10cSrcweir 
630cdf0e10cSrcweir #ifdef GRCACHE
631cdf0e10cSrcweir class GrFontHasher : public gr::Font
632cdf0e10cSrcweir {
633cdf0e10cSrcweir public:
GrFontHasher(const gr::Font & aFont)634cdf0e10cSrcweir     GrFontHasher(const gr::Font & aFont) : gr::Font(aFont), mrRealFont(const_cast<gr::Font&>(aFont)) {};
~GrFontHasher()635cdf0e10cSrcweir     ~GrFontHasher(){};
bold()636cdf0e10cSrcweir     virtual bool bold() { return mrRealFont.bold(); };
italic()637cdf0e10cSrcweir     virtual bool italic() { return mrRealFont.italic(); };
ascent()638cdf0e10cSrcweir     virtual float ascent()  { return mrRealFont.ascent(); };
descent()639cdf0e10cSrcweir     virtual float descent()  { return mrRealFont.descent(); };
height()640cdf0e10cSrcweir     virtual float height()  { return mrRealFont.height(); };
copyThis()641cdf0e10cSrcweir     virtual gr::Font* copyThis() { return mrRealFont.copyThis(); };
getDPIx()642cdf0e10cSrcweir     virtual unsigned int getDPIx() { return mrRealFont.getDPIx(); };
getDPIy()643cdf0e10cSrcweir     virtual unsigned int getDPIy() { return mrRealFont.getDPIy(); };
getTable(gr::fontTableId32 nId,size_t * nSize)644cdf0e10cSrcweir     virtual const void* getTable(gr::fontTableId32 nId, size_t* nSize)
645cdf0e10cSrcweir     { return mrRealFont.getTable(nId,nSize); }
getFontMetrics(float * pA,float * pB,float * pC)646cdf0e10cSrcweir     virtual void getFontMetrics(float*pA, float*pB, float*pC) { mrRealFont.getFontMetrics(pA,pB,pC); };
647cdf0e10cSrcweir 
hashCode(const grutils::GrFeatureParser * mpFeatures)648cdf0e10cSrcweir     sal_Int32 hashCode(const grutils::GrFeatureParser * mpFeatures)
649cdf0e10cSrcweir     {
650cdf0e10cSrcweir         // is this sufficient?
651cdf0e10cSrcweir         ext_std::wstring aFace;
652cdf0e10cSrcweir         bool bBold;
653cdf0e10cSrcweir         bool bItalic;
654cdf0e10cSrcweir         UniqueCacheInfo(aFace, bBold, bItalic);
655cdf0e10cSrcweir         sal_Unicode uName[32]; // max length used in gr::Font
656cdf0e10cSrcweir         // Note: graphite stores font names as UTF-16 even if wchar_t is 32bit
657cdf0e10cSrcweir         // this conversion should be OK.
658cdf0e10cSrcweir         for (size_t i = 0; i < aFace.size() && i < 32; i++)
659cdf0e10cSrcweir         {
660cdf0e10cSrcweir             uName[i] = aFace[i];
661cdf0e10cSrcweir         }
662cdf0e10cSrcweir         size_t iSize = aFace.size();
663cdf0e10cSrcweir         if (0 == iSize) return 0;
664cdf0e10cSrcweir         sal_Int32 hash = rtl_ustr_hashCode_WithLength(uName, iSize);
665cdf0e10cSrcweir         hash ^= static_cast<sal_Int32>(height());
666cdf0e10cSrcweir         hash |= (bBold)? 0x1000000 : 0;
667cdf0e10cSrcweir         hash |= (bItalic)? 0x2000000 : 0;
668cdf0e10cSrcweir         if (mpFeatures)
669cdf0e10cSrcweir             hash ^= mpFeatures->hashCode();
670cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
671cdf0e10cSrcweir         fprintf(grLog(), "font hash %x size %f\n", (int)hash, height());
672cdf0e10cSrcweir #endif
673cdf0e10cSrcweir         return hash;
674cdf0e10cSrcweir     };
675cdf0e10cSrcweir protected:
UniqueCacheInfo(ext_std::wstring & stuFace,bool & fBold,bool & fItalic)676cdf0e10cSrcweir     virtual void UniqueCacheInfo( ext_std::wstring& stuFace, bool& fBold, bool& fItalic )
677cdf0e10cSrcweir     {
678cdf0e10cSrcweir #ifdef WIN32
679cdf0e10cSrcweir         dynamic_cast<GraphiteWinFont&>(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic);
680cdf0e10cSrcweir #else
681cdf0e10cSrcweir #ifdef UNX
682cdf0e10cSrcweir         dynamic_cast<GraphiteFontAdaptor&>(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic);
683cdf0e10cSrcweir #else
684cdf0e10cSrcweir #error Unknown base type for gr::Font::UniqueCacheInfo
685cdf0e10cSrcweir #endif
686cdf0e10cSrcweir #endif
687cdf0e10cSrcweir     }
688cdf0e10cSrcweir private:
689cdf0e10cSrcweir     gr::Font & mrRealFont;
690cdf0e10cSrcweir };
691cdf0e10cSrcweir #endif
692cdf0e10cSrcweir 
693cdf0e10cSrcweir #ifdef GRCACHE
CreateSegment(ImplLayoutArgs & rArgs,GrSegRecord ** pSegRecord)694cdf0e10cSrcweir gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs, GrSegRecord ** pSegRecord)
695cdf0e10cSrcweir #else
696cdf0e10cSrcweir gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs)
697cdf0e10cSrcweir #endif
698cdf0e10cSrcweir {
699cdf0e10cSrcweir     assert(rArgs.mnLength >= 0);
700cdf0e10cSrcweir 
701cdf0e10cSrcweir     gr::Segment * pSegment = NULL;
702cdf0e10cSrcweir 
703cdf0e10cSrcweir     // Set the SalLayouts values to be the inital ones.
704cdf0e10cSrcweir     SalLayout::AdjustLayout(rArgs);
705cdf0e10cSrcweir     // TODO check if this is needed
706cdf0e10cSrcweir     if (mnUnitsPerPixel > 1)
707cdf0e10cSrcweir         mfScaling = 1.0f / mnUnitsPerPixel;
708cdf0e10cSrcweir 
709cdf0e10cSrcweir     // Clear out any previous buffers
710cdf0e10cSrcweir     clear();
711cdf0e10cSrcweir     bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
712cdf0e10cSrcweir     try
713cdf0e10cSrcweir     {
714cdf0e10cSrcweir         // Don't set RTL if font doesn't support it otherwise it forces rtl on
715cdf0e10cSrcweir         // everything
716cdf0e10cSrcweir         if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl))
717cdf0e10cSrcweir             maLayout.setRightToLeft(bRtl);
718cdf0e10cSrcweir 
719cdf0e10cSrcweir         // Context is often needed beyond the specified end, however, we don't
720cdf0e10cSrcweir         // want it if there has been a direction change, since it is hard
721cdf0e10cSrcweir         // to tell between reordering within one direction and multi-directional
722cdf0e10cSrcweir         // text. Extra context, can also cause problems with ligatures stradling
723cdf0e10cSrcweir         // a hyphenation point, so disable if CTL is disabled.
724cdf0e10cSrcweir         const int  nSegCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH);
725cdf0e10cSrcweir         int limit = rArgs.mnEndCharPos;
726cdf0e10cSrcweir         if ((nSegCharLimit > limit) && !(SAL_LAYOUT_COMPLEX_DISABLED & rArgs.mnFlags))
727cdf0e10cSrcweir         {
728cdf0e10cSrcweir             limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos,
729cdf0e10cSrcweir                 nSegCharLimit - rArgs.mnEndCharPos, bRtl);
730cdf0e10cSrcweir         }
731cdf0e10cSrcweir 
732cdf0e10cSrcweir #ifdef GRCACHE
733cdf0e10cSrcweir         GrFontHasher hasher(mrFont);
734cdf0e10cSrcweir         sal_Int32 aFontHash = hasher.hashCode(mpFeatures);
735cdf0e10cSrcweir         GraphiteSegmentCache * pCache =
736cdf0e10cSrcweir             (GraphiteCacheHandler::instance).getCache(aFontHash);
737cdf0e10cSrcweir         if (pCache)
738cdf0e10cSrcweir         {
739cdf0e10cSrcweir             *pSegRecord = pCache->getSegment(rArgs, bRtl, limit);
740cdf0e10cSrcweir             if (*pSegRecord)
741cdf0e10cSrcweir             {
742cdf0e10cSrcweir                 pSegment = (*pSegRecord)->getSegment();
743cdf0e10cSrcweir                 mpTextSrc = (*pSegRecord)->getTextSrc();
744cdf0e10cSrcweir                 maLayout.setRightToLeft((*pSegRecord)->isRtl());
745cdf0e10cSrcweir                 if (rArgs.mpStr != mpTextSrc->getLayoutArgs().mpStr ||
746cdf0e10cSrcweir                     rArgs.mnMinCharPos != mpTextSrc->getLayoutArgs().mnMinCharPos ||
747cdf0e10cSrcweir                     rArgs.mnEndCharPos != mpTextSrc->getLayoutArgs().mnEndCharPos ||
748cdf0e10cSrcweir                     (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) )
749cdf0e10cSrcweir                 {
750cdf0e10cSrcweir                     (*pSegRecord)->clearVectors();
751cdf0e10cSrcweir                 }
752cdf0e10cSrcweir                 mpTextSrc->switchLayoutArgs(rArgs);
753cdf0e10cSrcweir                 if (limit > rArgs.mnMinCharPos && limit == rArgs.mnEndCharPos
754cdf0e10cSrcweir                     && pSegment->stopCharacter() != limit)
755cdf0e10cSrcweir                 {
756cdf0e10cSrcweir                     // check that the last character is not part of a ligature
757cdf0e10cSrcweir                     glyph_set_range_t aGlyphSet = pSegment->charToGlyphs(limit - 1);
758cdf0e10cSrcweir                     if (aGlyphSet.first == aGlyphSet.second)
759cdf0e10cSrcweir                     {
760cdf0e10cSrcweir                         // no glyphs associated with this glyph - occurs mid ligature
761cdf0e10cSrcweir                         pSegment = NULL;
762cdf0e10cSrcweir                         *pSegRecord = NULL;
763cdf0e10cSrcweir                     }
764cdf0e10cSrcweir                     else
765cdf0e10cSrcweir                     {
766cdf0e10cSrcweir                         while (aGlyphSet.first != aGlyphSet.second)
767cdf0e10cSrcweir                         {
768cdf0e10cSrcweir                             int lastChar = static_cast<int>((*aGlyphSet.first).lastChar());
769cdf0e10cSrcweir                             if (lastChar >= limit)
770cdf0e10cSrcweir                             {
771cdf0e10cSrcweir                                 pSegment = NULL;
772cdf0e10cSrcweir                                 *pSegRecord = NULL;
773cdf0e10cSrcweir                                 break;
774cdf0e10cSrcweir                             }
775cdf0e10cSrcweir                             aGlyphSet.first++;
776cdf0e10cSrcweir                         }
777cdf0e10cSrcweir                     }
778cdf0e10cSrcweir                 }
779cdf0e10cSrcweir                 if (pSegment)
780cdf0e10cSrcweir                     return pSegment;
781cdf0e10cSrcweir             }
782cdf0e10cSrcweir         }
783cdf0e10cSrcweir #endif
784cdf0e10cSrcweir 
785cdf0e10cSrcweir         // Create a new TextSource object for the engine.
786cdf0e10cSrcweir         mpTextSrc = new TextSourceAdaptor(rArgs, limit);
787cdf0e10cSrcweir         if (mpFeatures) mpTextSrc->setFeatures(mpFeatures);
788cdf0e10cSrcweir 
789cdf0e10cSrcweir         pSegment = new gr::RangeSegment((gr::Font *)&mrFont, mpTextSrc, &maLayout, mnMinCharPos, limit);
790cdf0e10cSrcweir         if (pSegment != NULL)
791cdf0e10cSrcweir         {
792cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
793cdf0e10cSrcweir             fprintf(grLog(),"Gr::LayoutText %d-%d, context %d,len%d rtl%d/%d scaling %f\n", rArgs.mnMinCharPos,
794cdf0e10cSrcweir                rArgs.mnEndCharPos, limit, rArgs.mnLength, maLayout.rightToLeft(), pSegment->rightToLeft(), mfScaling);
795cdf0e10cSrcweir #endif
796cdf0e10cSrcweir #ifdef GRCACHE
797cdf0e10cSrcweir             // on a new segment rightToLeft should be correct
798cdf0e10cSrcweir             *pSegRecord = pCache->cacheSegment(mpTextSrc, pSegment, pSegment->rightToLeft());
799cdf0e10cSrcweir #endif
800cdf0e10cSrcweir         }
801cdf0e10cSrcweir         else
802cdf0e10cSrcweir         {
803cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
804cdf0e10cSrcweir             fprintf(grLog(), "Gr::LayoutText failed: ");
805cdf0e10cSrcweir             for (int i = mnMinCharPos; i < limit; i++)
806cdf0e10cSrcweir             {
807cdf0e10cSrcweir                 fprintf(grLog(), "%04x ", rArgs.mpStr[i]);
808cdf0e10cSrcweir             }
809cdf0e10cSrcweir             fprintf(grLog(), "\n");
810cdf0e10cSrcweir #endif
811cdf0e10cSrcweir             clear();
812cdf0e10cSrcweir             return NULL;
813cdf0e10cSrcweir         }
814cdf0e10cSrcweir     }
815cdf0e10cSrcweir     catch (...)
816cdf0e10cSrcweir     {
817cdf0e10cSrcweir         clear();  // destroy the text source and any partially built segments.
818cdf0e10cSrcweir         return NULL;
819cdf0e10cSrcweir     }
820cdf0e10cSrcweir     return pSegment;
821cdf0e10cSrcweir }
822cdf0e10cSrcweir 
823cdf0e10cSrcweir #ifdef GRCACHE
LayoutGlyphs(ImplLayoutArgs & rArgs,gr::Segment * pSegment,GrSegRecord * pSegRecord)824cdf0e10cSrcweir bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment, GrSegRecord * pSegRecord)
825cdf0e10cSrcweir #else
826cdf0e10cSrcweir bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment)
827cdf0e10cSrcweir #endif
828cdf0e10cSrcweir {
829cdf0e10cSrcweir #ifdef GRCACHE
830cdf0e10cSrcweir #ifdef GRCACHE_REUSE_VECTORS
831cdf0e10cSrcweir     // if we have an exact match, then we can reuse the glyph vectors from before
832cdf0e10cSrcweir     if (pSegRecord && (pSegRecord->glyphs().size() > 0) &&
833cdf0e10cSrcweir         (pSegRecord->fontScale() == mfScaling) &&
834cdf0e10cSrcweir         !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) )
835cdf0e10cSrcweir     {
836cdf0e10cSrcweir         mnWidth = pSegRecord->width();
837cdf0e10cSrcweir         mvGlyphs = pSegRecord->glyphs();
838cdf0e10cSrcweir         mvCharDxs = pSegRecord->charDxs();
839cdf0e10cSrcweir         mvChar2BaseGlyph = pSegRecord->char2BaseGlyph();
840cdf0e10cSrcweir         mvGlyph2Char = pSegRecord->glyph2Char();
841cdf0e10cSrcweir         return true;
842cdf0e10cSrcweir     }
843cdf0e10cSrcweir #endif
844cdf0e10cSrcweir #endif
845cdf0e10cSrcweir     // Calculate the initial character dxs.
846cdf0e10cSrcweir     mvCharDxs.assign(mnEndCharPos - mnMinCharPos, -1);
847cdf0e10cSrcweir     mvChar2BaseGlyph.assign(mnEndCharPos - mnMinCharPos, -1);
848cdf0e10cSrcweir     mnWidth = 0;
849cdf0e10cSrcweir     if (mvCharDxs.size() > 0)
850cdf0e10cSrcweir     {
851cdf0e10cSrcweir         // Discover all the clusters.
852cdf0e10cSrcweir         try
853cdf0e10cSrcweir         {
854cdf0e10cSrcweir             // Note: we use the layout rightToLeft() because in cached segments
855cdf0e10cSrcweir             // rightToLeft() may no longer be valid if the engine has been run
856cdf0e10cSrcweir             // ltr since the segment was created.
857cdf0e10cSrcweir #ifdef GRCACHE
858cdf0e10cSrcweir             bool bRtl = pSegRecord? pSegRecord->isRtl() : pSegment->rightToLeft();
859cdf0e10cSrcweir #else
860cdf0e10cSrcweir             bool bRtl = pSegment->rightToLeft();
861cdf0e10cSrcweir #endif
862cdf0e10cSrcweir             mvGlyphs.fill_from(*pSegment, rArgs, bRtl,
863cdf0e10cSrcweir                 mnWidth, mfScaling, mvChar2BaseGlyph, mvGlyph2Char, mvCharDxs);
864cdf0e10cSrcweir 
865cdf0e10cSrcweir             if (bRtl)
866cdf0e10cSrcweir             {
867cdf0e10cSrcweir                 // not needed for adjacent differences, but for mouse clicks to char
868cdf0e10cSrcweir                 std::transform(mvCharDxs.begin(), mvCharDxs.end(), mvCharDxs.begin(),
869cdf0e10cSrcweir                     std::bind1st(std::minus<long>(), mnWidth));
870cdf0e10cSrcweir                 // fixup last dx to ensure it always equals the width
871cdf0e10cSrcweir                 mvCharDxs[mvCharDxs.size() - 1] = mnWidth;
872cdf0e10cSrcweir             }
873cdf0e10cSrcweir #ifdef GRCACHE
874cdf0e10cSrcweir #ifdef GRCACHE_REUSE_VECTORS
875cdf0e10cSrcweir             if (pSegRecord && rArgs.maReruns.IsEmpty() &&
876cdf0e10cSrcweir                 !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags))
877cdf0e10cSrcweir             {
878cdf0e10cSrcweir                 pSegRecord->setGlyphVectors(mnWidth, mvGlyphs, mvCharDxs,
879cdf0e10cSrcweir                                             mvChar2BaseGlyph, mvGlyph2Char,
880cdf0e10cSrcweir                                             mfScaling);
881cdf0e10cSrcweir             }
882cdf0e10cSrcweir #endif
883cdf0e10cSrcweir #endif
884cdf0e10cSrcweir         }
885adad3ae8SHerbert Dürr         catch (std::exception& e)
886cdf0e10cSrcweir         {
887cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
888cdf0e10cSrcweir             fprintf(grLog(),"LayoutGlyphs failed %s\n", e.what());
889cdf0e10cSrcweir #endif
890cdf0e10cSrcweir             return false;
891cdf0e10cSrcweir         }
892cdf0e10cSrcweir         catch (...)
893cdf0e10cSrcweir         {
894cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
895cdf0e10cSrcweir             fprintf(grLog(),"LayoutGlyphs failed with exception");
896cdf0e10cSrcweir #endif
897cdf0e10cSrcweir             return false;
898cdf0e10cSrcweir         }
899cdf0e10cSrcweir     }
900cdf0e10cSrcweir     else
901cdf0e10cSrcweir     {
902cdf0e10cSrcweir         mnWidth = 0;
903cdf0e10cSrcweir     }
904cdf0e10cSrcweir     return true;
905cdf0e10cSrcweir }
906cdf0e10cSrcweir 
GetTextBreak(long maxmnWidth,long char_extra,int factor) const907cdf0e10cSrcweir int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) const
908cdf0e10cSrcweir {
909cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
910cdf0e10cSrcweir     fprintf(grLog(),"Gr::GetTextBreak c[%d-%d) maxWidth %ld char extra %ld factor %d\n",
911cdf0e10cSrcweir         mnMinCharPos, mnEndCharPos, maxmnWidth, char_extra, factor);
912cdf0e10cSrcweir #endif
913cdf0e10cSrcweir 
914cdf0e10cSrcweir     // return quickly if this segment is narrower than the target width
915cdf0e10cSrcweir     if (maxmnWidth > mnWidth * factor + char_extra * (mnEndCharPos - mnMinCharPos - 1))
916cdf0e10cSrcweir         return STRING_LEN;
917cdf0e10cSrcweir 
918cdf0e10cSrcweir     long nWidth = mvCharDxs[0] * factor;
919cdf0e10cSrcweir     int nLastBreak = -1;
920cdf0e10cSrcweir     for (size_t i = 1; i < mvCharDxs.size(); i++)
921cdf0e10cSrcweir     {
922cdf0e10cSrcweir         nWidth += char_extra;
923cdf0e10cSrcweir         if (nWidth > maxmnWidth) break;
924cdf0e10cSrcweir         if (mvChar2BaseGlyph[i] != -1)
925cdf0e10cSrcweir         {
926cdf0e10cSrcweir             if (mvChar2BaseGlyph[i] & (WORD_BREAK_BEFORE | HYPHEN_BREAK_BEFORE))
927cdf0e10cSrcweir                 nLastBreak = static_cast<int>(i);
928cdf0e10cSrcweir         }
929cdf0e10cSrcweir         nWidth += (mvCharDxs[i] - mvCharDxs[i-1]) * factor;
930cdf0e10cSrcweir     }
931cdf0e10cSrcweir     int nBreak = mnMinCharPos;
932cdf0e10cSrcweir     if (nLastBreak > -1)
933cdf0e10cSrcweir         nBreak += nLastBreak;
934cdf0e10cSrcweir 
935cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
936cdf0e10cSrcweir     fprintf(grLog(), "Gr::GetTextBreak break after %d\n", nBreak - mnMinCharPos);
937cdf0e10cSrcweir #endif
938cdf0e10cSrcweir 
939cdf0e10cSrcweir     if (nBreak > mnEndCharPos) nBreak = STRING_LEN;
940cdf0e10cSrcweir     else if (nBreak < mnMinCharPos) nBreak = mnMinCharPos;
941cdf0e10cSrcweir     return nBreak;
942cdf0e10cSrcweir }
943cdf0e10cSrcweir 
944cdf0e10cSrcweir 
FillDXArray(sal_Int32 * pDXArray) const945cdf0e10cSrcweir long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const
946cdf0e10cSrcweir {
947cdf0e10cSrcweir     if (mnEndCharPos == mnMinCharPos)
948cdf0e10cSrcweir         // Then we must be zero width!
949cdf0e10cSrcweir         return 0;
950cdf0e10cSrcweir 
951cdf0e10cSrcweir     if (pDXArray)
952cdf0e10cSrcweir     {
953cdf0e10cSrcweir         for (size_t i = 0; i < mvCharDxs.size(); i++)
954cdf0e10cSrcweir         {
955cdf0e10cSrcweir             assert( (mvChar2BaseGlyph[i] == -1) ||
956cdf0e10cSrcweir                 ((signed)(mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK) < (signed)mvGlyphs.size()));
957cdf0e10cSrcweir             if (mvChar2BaseGlyph[i] != -1 &&
958248a599fSHerbert Dürr                 mvGlyphs[mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK].maGlyphId == GF_DROPPED)
959cdf0e10cSrcweir             {
960cdf0e10cSrcweir                 // when used in MultiSalLayout::GetTextBreak dropped glyphs
961cdf0e10cSrcweir                 // must have zero width
962cdf0e10cSrcweir                 pDXArray[i] = 0;
963cdf0e10cSrcweir             }
964cdf0e10cSrcweir             else
965cdf0e10cSrcweir             {
966cdf0e10cSrcweir                 pDXArray[i] = mvCharDxs[i];
967cdf0e10cSrcweir                 if (i > 0) pDXArray[i] -= mvCharDxs[i-1];
968cdf0e10cSrcweir             }
969cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
970cdf0e10cSrcweir             fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
971cdf0e10cSrcweir #endif
972cdf0e10cSrcweir         }
973cdf0e10cSrcweir         //std::adjacent_difference(mvCharDxs.begin(), mvCharDxs.end(), pDXArray);
974cdf0e10cSrcweir         //for (size_t i = 0; i < mvCharDxs.size(); i++)
975cdf0e10cSrcweir         //    fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
976cdf0e10cSrcweir         //fprintf(grLog(),"FillDX %ld,%d\n", mnWidth, std::accumulate(pDXArray, pDXArray + mvCharDxs.size(), 0));
977cdf0e10cSrcweir     }
978cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
979cdf0e10cSrcweir     fprintf(grLog(),"FillDXArray %d-%d,%d=%ld\n", mnMinCharPos, mnEndCharPos, (int)mpTextSrc->getLength(), mnWidth);
980cdf0e10cSrcweir #endif
981cdf0e10cSrcweir     return mnWidth;
982cdf0e10cSrcweir }
983cdf0e10cSrcweir 
984cdf0e10cSrcweir 
AdjustLayout(ImplLayoutArgs & rArgs)985cdf0e10cSrcweir void  GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs)
986cdf0e10cSrcweir {
987cdf0e10cSrcweir     SalLayout::AdjustLayout(rArgs);
988cdf0e10cSrcweir     if(rArgs.mpDXArray)
989cdf0e10cSrcweir     {
990cdf0e10cSrcweir         std::vector<int> vDeltaWidths(mvGlyphs.size(), 0);
991cdf0e10cSrcweir         ApplyDXArray(rArgs, vDeltaWidths);
992cdf0e10cSrcweir 
993cdf0e10cSrcweir         if( (mnLayoutFlags & SAL_LAYOUT_BIDI_RTL) &&
994cdf0e10cSrcweir            !(rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
995cdf0e10cSrcweir         {
996cdf0e10cSrcweir             // check if this is a kashida script
997cdf0e10cSrcweir             bool bKashidaScript = false;
998cdf0e10cSrcweir             for (int i = rArgs.mnMinCharPos; i < rArgs.mnEndCharPos; i++)
999cdf0e10cSrcweir             {
1000cdf0e10cSrcweir                 UErrorCode aStatus = U_ZERO_ERROR;
1001cdf0e10cSrcweir                 UScriptCode scriptCode = uscript_getScript(rArgs.mpStr[i], &aStatus);
1002cdf0e10cSrcweir                 if (scriptCode == USCRIPT_ARABIC || scriptCode == USCRIPT_SYRIAC)
1003cdf0e10cSrcweir                 {
1004cdf0e10cSrcweir                     bKashidaScript = true;
1005cdf0e10cSrcweir                     break;
1006cdf0e10cSrcweir                 }
1007cdf0e10cSrcweir             }
1008cdf0e10cSrcweir             int nKashidaWidth = 0;
1009cdf0e10cSrcweir             int nKashidaIndex = getKashidaGlyph(nKashidaWidth);
1010cdf0e10cSrcweir             if( nKashidaIndex != 0 && bKashidaScript)
1011cdf0e10cSrcweir             {
1012cdf0e10cSrcweir                 kashidaJustify( vDeltaWidths, nKashidaIndex, nKashidaWidth );
1013cdf0e10cSrcweir             }
1014cdf0e10cSrcweir         }
1015cdf0e10cSrcweir     }
1016cdf0e10cSrcweir     else if (rArgs.mnLayoutWidth > 0)
1017cdf0e10cSrcweir     {
1018cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1019cdf0e10cSrcweir         fprintf(grLog(), "AdjustLayout width %ld=>%ld\n", mnWidth, rArgs.mnLayoutWidth);
1020cdf0e10cSrcweir #endif
1021cdf0e10cSrcweir         expandOrCondense(rArgs);
1022cdf0e10cSrcweir     }
1023cdf0e10cSrcweir }
1024cdf0e10cSrcweir 
expandOrCondense(ImplLayoutArgs & rArgs)1025cdf0e10cSrcweir void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs)
1026cdf0e10cSrcweir {
1027cdf0e10cSrcweir     int nDeltaWidth = rArgs.mnLayoutWidth - mnWidth;
1028cdf0e10cSrcweir     if (nDeltaWidth > 0) // expand, just expand between clusters
1029cdf0e10cSrcweir     {
1030cdf0e10cSrcweir         int nClusterCount = 0;
1031cdf0e10cSrcweir         for (size_t j = 0; j < mvGlyphs.size(); j++)
1032cdf0e10cSrcweir         {
1033cdf0e10cSrcweir             if (mvGlyphs[j].IsClusterStart())
1034cdf0e10cSrcweir             {
1035cdf0e10cSrcweir                 ++nClusterCount;
1036cdf0e10cSrcweir             }
1037cdf0e10cSrcweir         }
1038cdf0e10cSrcweir         if (nClusterCount > 1)
1039cdf0e10cSrcweir         {
1040cdf0e10cSrcweir             float fExtraPerCluster = static_cast<float>(nDeltaWidth) / static_cast<float>(nClusterCount - 1);
1041cdf0e10cSrcweir             int nCluster = 0;
1042cdf0e10cSrcweir             int nOffset = 0;
1043cdf0e10cSrcweir             for (size_t i = 0; i < mvGlyphs.size(); i++)
1044cdf0e10cSrcweir             {
1045cdf0e10cSrcweir                 if (mvGlyphs[i].IsClusterStart())
1046cdf0e10cSrcweir                 {
1047cdf0e10cSrcweir                     nOffset = FRound( fExtraPerCluster * nCluster );
1048cdf0e10cSrcweir                     size_t nCharIndex = mvGlyph2Char[i];
1049cdf0e10cSrcweir                     mvCharDxs[nCharIndex] += nOffset;
1050cdf0e10cSrcweir                     // adjust char dxs for rest of characters in cluster
1051cdf0e10cSrcweir                     while (++nCharIndex < mvGlyph2Char.size())
1052cdf0e10cSrcweir                     {
1053cdf0e10cSrcweir                         int nChar2Base = (mvChar2BaseGlyph[nCharIndex] == -1)? -1 : (int)(mvChar2BaseGlyph[nCharIndex] & GLYPH_INDEX_MASK);
1054cdf0e10cSrcweir                         if (nChar2Base == -1 || nChar2Base == static_cast<int>(i))
1055cdf0e10cSrcweir                             mvCharDxs[nCharIndex] += nOffset;
1056cdf0e10cSrcweir                     }
1057cdf0e10cSrcweir                     ++nCluster;
1058cdf0e10cSrcweir                 }
1059cdf0e10cSrcweir                 mvGlyphs[i].maLinearPos.X() += nOffset;
1060cdf0e10cSrcweir             }
1061cdf0e10cSrcweir         }
1062cdf0e10cSrcweir     }
1063cdf0e10cSrcweir     else // condense - apply a factor to all glyph positions
1064cdf0e10cSrcweir     {
1065cdf0e10cSrcweir         if (mvGlyphs.size() == 0) return;
1066cdf0e10cSrcweir         Glyphs::iterator iLastGlyph = mvGlyphs.begin() + (mvGlyphs.size() - 1);
1067cdf0e10cSrcweir         // position last glyph using original width
1068cdf0e10cSrcweir         float fXFactor = static_cast<float>(rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth) / static_cast<float>(iLastGlyph->maLinearPos.X());
1069cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1070cdf0e10cSrcweir         fprintf(grLog(), "Condense by factor %f\n", fXFactor);
1071cdf0e10cSrcweir #endif
1072cdf0e10cSrcweir         iLastGlyph->maLinearPos.X() = rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth;
1073cdf0e10cSrcweir         Glyphs::iterator iGlyph = mvGlyphs.begin();
1074cdf0e10cSrcweir         while (iGlyph != iLastGlyph)
1075cdf0e10cSrcweir         {
1076cdf0e10cSrcweir             iGlyph->maLinearPos.X() = FRound( fXFactor * iGlyph->maLinearPos.X() );
1077cdf0e10cSrcweir             ++iGlyph;
1078cdf0e10cSrcweir         }
1079cdf0e10cSrcweir         for (size_t i = 0; i < mvCharDxs.size(); i++)
1080cdf0e10cSrcweir         {
1081cdf0e10cSrcweir             mvCharDxs[i] = FRound( fXFactor * mvCharDxs[i] );
1082cdf0e10cSrcweir         }
1083cdf0e10cSrcweir     }
1084cdf0e10cSrcweir     mnWidth = rArgs.mnLayoutWidth;
1085cdf0e10cSrcweir }
1086cdf0e10cSrcweir 
ApplyDXArray(ImplLayoutArgs & args,std::vector<int> & rDeltaWidth)1087cdf0e10cSrcweir void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDeltaWidth)
1088cdf0e10cSrcweir {
1089cdf0e10cSrcweir     const size_t nChars = args.mnEndCharPos - args.mnMinCharPos;
1090cdf0e10cSrcweir     if (nChars == 0) return;
1091cdf0e10cSrcweir 
1092cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1093cdf0e10cSrcweir     for (size_t iDx = 0; iDx < mvCharDxs.size(); iDx++)
1094cdf0e10cSrcweir          fprintf(grLog(),"%d,%d,%d ", (int)iDx, (int)mvCharDxs[iDx], args.mpDXArray[iDx]);
1095cdf0e10cSrcweir     fprintf(grLog(),"ApplyDx\n");
1096cdf0e10cSrcweir #endif
1097cdf0e10cSrcweir     bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
1098cdf0e10cSrcweir     int nXOffset = 0;
1099cdf0e10cSrcweir     if (bRtl)
1100cdf0e10cSrcweir     {
1101cdf0e10cSrcweir         nXOffset = args.mpDXArray[nChars - 1] - mvCharDxs[nChars - 1];
1102cdf0e10cSrcweir     }
1103cdf0e10cSrcweir     int nPrevClusterGlyph = (bRtl)? (signed)mvGlyphs.size() : -1;
1104cdf0e10cSrcweir     int nPrevClusterLastChar = -1;
1105cdf0e10cSrcweir     for (size_t i = 0; i < nChars; i++)
1106cdf0e10cSrcweir     {
1107cdf0e10cSrcweir         int nChar2Base = (mvChar2BaseGlyph[i] == -1)? -1 : (int)(mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK);
1108cdf0e10cSrcweir         if ((nChar2Base > -1) && (nChar2Base != nPrevClusterGlyph))
1109cdf0e10cSrcweir         {
1110cdf0e10cSrcweir             assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size()));
1111cdf0e10cSrcweir             GlyphItem & gi = mvGlyphs[nChar2Base];
1112cdf0e10cSrcweir             if (!gi.IsClusterStart())
1113cdf0e10cSrcweir                 continue;
1114cdf0e10cSrcweir 
1115cdf0e10cSrcweir             // find last glyph of this cluster
1116cdf0e10cSrcweir             size_t j = i + 1;
1117cdf0e10cSrcweir             int nLastChar = i;
1118cdf0e10cSrcweir             int nLastGlyph = nChar2Base;
1119cdf0e10cSrcweir             for (; j < nChars; j++)
1120cdf0e10cSrcweir             {
1121cdf0e10cSrcweir                 int nChar2BaseJ = (mvChar2BaseGlyph[j] == -1)? -1 : (int)(mvChar2BaseGlyph[j] & GLYPH_INDEX_MASK);
1122cdf0e10cSrcweir                 assert((nChar2BaseJ >= -1) && (nChar2BaseJ < (signed)mvGlyphs.size()));
1123cdf0e10cSrcweir                 if (nChar2BaseJ != -1 && mvGlyphs[nChar2BaseJ].IsClusterStart())
1124cdf0e10cSrcweir                 {
1125cdf0e10cSrcweir                     nLastGlyph = nChar2BaseJ + ((bRtl)? +1 : -1);
1126cdf0e10cSrcweir                     nLastChar = j - 1;
1127cdf0e10cSrcweir                     break;
1128cdf0e10cSrcweir                 }
1129cdf0e10cSrcweir             }
1130cdf0e10cSrcweir             if (nLastGlyph < 0)
1131cdf0e10cSrcweir             {
1132cdf0e10cSrcweir                 nLastGlyph = nChar2Base;
1133cdf0e10cSrcweir             }
1134cdf0e10cSrcweir             // Its harder to find the last glyph rtl, since the first of
1135cdf0e10cSrcweir             // cluster is still on the left so we need to search towards
1136cdf0e10cSrcweir             // the previous cluster to the right
1137cdf0e10cSrcweir             if (bRtl)
1138cdf0e10cSrcweir             {
1139cdf0e10cSrcweir                 nLastGlyph = nChar2Base;
1140cdf0e10cSrcweir                 while (nLastGlyph + 1 < (signed)mvGlyphs.size() &&
1141cdf0e10cSrcweir                        !mvGlyphs[nLastGlyph+1].IsClusterStart())
1142cdf0e10cSrcweir                 {
1143cdf0e10cSrcweir                     ++nLastGlyph;
1144cdf0e10cSrcweir                 }
1145cdf0e10cSrcweir             }
1146cdf0e10cSrcweir             if (j == nChars)
1147cdf0e10cSrcweir             {
1148cdf0e10cSrcweir                 nLastChar = nChars - 1;
1149cdf0e10cSrcweir                 if (!bRtl) nLastGlyph = mvGlyphs.size() - 1;
1150cdf0e10cSrcweir             }
1151cdf0e10cSrcweir             assert((nLastChar > -1) && (nLastChar < (signed)nChars));
1152cdf0e10cSrcweir             long nNewClusterWidth = args.mpDXArray[nLastChar];
1153cdf0e10cSrcweir             long nOrigClusterWidth = mvCharDxs[nLastChar];
1154cdf0e10cSrcweir             long nDGlyphOrigin = 0;
1155cdf0e10cSrcweir             if (nPrevClusterLastChar > - 1)
1156cdf0e10cSrcweir             {
1157cdf0e10cSrcweir                 assert(nPrevClusterLastChar < (signed)nChars);
1158cdf0e10cSrcweir                 nNewClusterWidth -= args.mpDXArray[nPrevClusterLastChar];
1159cdf0e10cSrcweir                 nOrigClusterWidth -= mvCharDxs[nPrevClusterLastChar];
1160cdf0e10cSrcweir                 nDGlyphOrigin = args.mpDXArray[nPrevClusterLastChar] - mvCharDxs[nPrevClusterLastChar];
1161cdf0e10cSrcweir             }
1162cdf0e10cSrcweir             long nDWidth = nNewClusterWidth - nOrigClusterWidth;
1163cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1164cdf0e10cSrcweir             fprintf(grLog(), "c%lu last glyph %d/%lu\n", i, nLastGlyph, mvGlyphs.size());
1165cdf0e10cSrcweir #endif
1166cdf0e10cSrcweir             assert((nLastGlyph > -1) && (nLastGlyph < (signed)mvGlyphs.size()));
1167cdf0e10cSrcweir             mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
1168248a599fSHerbert Dürr             if (gi.maGlyphId != GF_DROPPED)
1169cdf0e10cSrcweir                 mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
1170cdf0e10cSrcweir             else
1171cdf0e10cSrcweir                 nDGlyphOrigin += nDWidth;
1172cdf0e10cSrcweir             // update glyph positions
1173cdf0e10cSrcweir             if (bRtl)
1174cdf0e10cSrcweir             {
1175cdf0e10cSrcweir                 for (int n = nChar2Base; n <= nLastGlyph; n++)
1176cdf0e10cSrcweir                 {
1177cdf0e10cSrcweir                     assert((n > - 1) && (n < (signed)mvGlyphs.size()));
1178cdf0e10cSrcweir                     mvGlyphs[n].maLinearPos.X() += -nDGlyphOrigin + nXOffset;
1179cdf0e10cSrcweir                 }
1180cdf0e10cSrcweir             }
1181cdf0e10cSrcweir             else
1182cdf0e10cSrcweir             {
1183cdf0e10cSrcweir                 for (int n = nChar2Base; n <= nLastGlyph; n++)
1184cdf0e10cSrcweir                 {
1185cdf0e10cSrcweir                     assert((n > - 1) && (n < (signed)mvGlyphs.size()));
1186cdf0e10cSrcweir                     mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + nXOffset;
1187cdf0e10cSrcweir                 }
1188cdf0e10cSrcweir             }
1189cdf0e10cSrcweir             rDeltaWidth[nChar2Base] = nDWidth;
1190cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1191cdf0e10cSrcweir             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());
1192cdf0e10cSrcweir #endif
1193cdf0e10cSrcweir             nPrevClusterGlyph = nChar2Base;
1194cdf0e10cSrcweir             nPrevClusterLastChar = nLastChar;
1195cdf0e10cSrcweir             i = nLastChar;
1196cdf0e10cSrcweir         }
1197cdf0e10cSrcweir     }
1198cdf0e10cSrcweir     // Update the dx vector with the new values.
1199cdf0e10cSrcweir     std::copy(args.mpDXArray, args.mpDXArray + nChars,
1200cdf0e10cSrcweir       mvCharDxs.begin() + (args.mnMinCharPos - mnMinCharPos));
1201cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1202cdf0e10cSrcweir     fprintf(grLog(),"ApplyDx %d(%ld)\n", args.mpDXArray[nChars - 1], mnWidth);
1203cdf0e10cSrcweir #endif
1204cdf0e10cSrcweir     mnWidth = args.mpDXArray[nChars - 1];
1205cdf0e10cSrcweir }
1206cdf0e10cSrcweir 
kashidaJustify(std::vector<int> & rDeltaWidths,sal_GlyphId nKashidaIndex,int nKashidaWidth)1207cdf0e10cSrcweir void GraphiteLayout::kashidaJustify(std::vector<int>& rDeltaWidths, sal_GlyphId nKashidaIndex, int nKashidaWidth)
1208cdf0e10cSrcweir {
1209cdf0e10cSrcweir     // skip if the kashida glyph in the font looks suspicious
1210cdf0e10cSrcweir     if( nKashidaWidth <= 0 )
1211cdf0e10cSrcweir         return;
1212cdf0e10cSrcweir 
1213cdf0e10cSrcweir     // calculate max number of needed kashidas
1214cdf0e10cSrcweir     Glyphs::iterator i = mvGlyphs.begin();
1215cdf0e10cSrcweir     int nKashidaCount = 0;
1216cdf0e10cSrcweir     int nOrigGlyphIndex = -1;
1217cdf0e10cSrcweir     int nGlyphIndex = -1;
1218cdf0e10cSrcweir     while (i != mvGlyphs.end())
1219cdf0e10cSrcweir     {
1220cdf0e10cSrcweir         nOrigGlyphIndex++;
1221cdf0e10cSrcweir         nGlyphIndex++;
1222cdf0e10cSrcweir         // only inject kashidas in RTL contexts
1223cdf0e10cSrcweir         if( !(*i).IsRTLGlyph() )
1224cdf0e10cSrcweir         {
1225cdf0e10cSrcweir             ++i;
1226cdf0e10cSrcweir             continue;
1227cdf0e10cSrcweir         }
1228cdf0e10cSrcweir         // no kashida-injection for blank justified expansion either
1229248a599fSHerbert Dürr         if( IsSpacingGlyph( (*i).maGlyphId ) )
1230cdf0e10cSrcweir         {
1231cdf0e10cSrcweir             ++i;
1232cdf0e10cSrcweir             continue;
1233cdf0e10cSrcweir         }
1234cdf0e10cSrcweir         // calculate gap, ignore if too small
1235cdf0e10cSrcweir         int nGapWidth = rDeltaWidths[nOrigGlyphIndex];
1236cdf0e10cSrcweir         // worst case is one kashida even for mini-gaps
1237cdf0e10cSrcweir         if( 3 * nGapWidth < nKashidaWidth )
1238cdf0e10cSrcweir         {
1239cdf0e10cSrcweir             ++i;
1240cdf0e10cSrcweir             continue;
1241cdf0e10cSrcweir         }
1242cdf0e10cSrcweir         nKashidaCount = 1 + (nGapWidth / nKashidaWidth);
1243cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1244248a599fSHerbert Dürr         printf("inserting %d kashidas at %u\n", nKashidaCount, (*i).maGlyphId);
1245cdf0e10cSrcweir #endif
1246cdf0e10cSrcweir         GlyphItem glyphItem = *i;
1247cdf0e10cSrcweir         Point aPos(0, 0);
1248cdf0e10cSrcweir         aPos.X() = (*i).maLinearPos.X();
1249cdf0e10cSrcweir         GlyphItem newGi(glyphItem.mnCharPos, nKashidaIndex, aPos,
1250cdf0e10cSrcweir                 GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaWidth);
1251cdf0e10cSrcweir         mvGlyphs.reserve(mvGlyphs.size() + nKashidaCount);
1252cdf0e10cSrcweir         i = mvGlyphs.begin() + nGlyphIndex;
1253cdf0e10cSrcweir         mvGlyphs.insert(i, nKashidaCount, newGi);
1254cdf0e10cSrcweir         i = mvGlyphs.begin() + nGlyphIndex;
1255cdf0e10cSrcweir         nGlyphIndex += nKashidaCount;
1256cdf0e10cSrcweir         // now fix up the kashida positions
1257cdf0e10cSrcweir         for (int j = 0; j < nKashidaCount; j++)
1258cdf0e10cSrcweir         {
1259cdf0e10cSrcweir             (*(i)).maLinearPos.X() -= nGapWidth;
1260cdf0e10cSrcweir             nGapWidth -= nKashidaWidth;
1261cdf0e10cSrcweir             i++;
1262cdf0e10cSrcweir         }
1263cdf0e10cSrcweir 
1264cdf0e10cSrcweir         // fixup rightmost kashida for gap remainder
1265cdf0e10cSrcweir         if( nGapWidth < 0 )
1266cdf0e10cSrcweir         {
1267cdf0e10cSrcweir             if( nKashidaCount <= 1 )
1268cdf0e10cSrcweir                 nGapWidth /= 2;               // for small gap move kashida to middle
1269cdf0e10cSrcweir             (*(i-1)).mnNewWidth += nGapWidth;  // adjust kashida width to gap width
1270cdf0e10cSrcweir             (*(i-1)).maLinearPos.X() += nGapWidth;
1271cdf0e10cSrcweir         }
1272cdf0e10cSrcweir 
1273cdf0e10cSrcweir         (*i).mnNewWidth = (*i).mnOrigWidth;
1274cdf0e10cSrcweir         ++i;
1275cdf0e10cSrcweir     }
1276cdf0e10cSrcweir 
1277cdf0e10cSrcweir }
1278cdf0e10cSrcweir 
GetCaretPositions(int nArraySize,sal_Int32 * pCaretXArray) const1279cdf0e10cSrcweir void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const
1280cdf0e10cSrcweir {
1281cdf0e10cSrcweir     // For each character except the last discover the caret positions
1282cdf0e10cSrcweir     // immediatly before and after that character.
1283cdf0e10cSrcweir     // This is used for underlines in the GUI amongst other things.
1284cdf0e10cSrcweir     // It may be used from MultiSalLayout, in which case it must take into account
1285cdf0e10cSrcweir     // glyphs that have been moved.
1286cdf0e10cSrcweir     std::fill(pCaretXArray, pCaretXArray + nArraySize, -1);
1287cdf0e10cSrcweir     // the layout method doesn't modify the layout even though it isn't
1288cdf0e10cSrcweir     // const in the interface
1289cdf0e10cSrcweir     bool bRtl = const_cast<GraphiteLayout*>(this)->maLayout.rightToLeft();
1290cdf0e10cSrcweir     int prevBase = -1;
1291cdf0e10cSrcweir     long prevClusterWidth = 0;
1292cdf0e10cSrcweir     for (int i = 0, nCharSlot = 0; i < nArraySize && nCharSlot < static_cast<int>(mvCharDxs.size()); ++nCharSlot, i+=2)
1293cdf0e10cSrcweir     {
1294cdf0e10cSrcweir         if (mvChar2BaseGlyph[nCharSlot] != -1)
1295cdf0e10cSrcweir         {
1296cdf0e10cSrcweir             int nChar2Base = mvChar2BaseGlyph[nCharSlot] & GLYPH_INDEX_MASK;
1297cdf0e10cSrcweir             assert((mvChar2BaseGlyph[nCharSlot] > -1) && (nChar2Base < (signed)mvGlyphs.size()));
1298cdf0e10cSrcweir             GlyphItem gi = mvGlyphs[nChar2Base];
1299248a599fSHerbert Dürr             if (gi.maGlyphId == GF_DROPPED)
1300cdf0e10cSrcweir             {
1301cdf0e10cSrcweir                 continue;
1302cdf0e10cSrcweir             }
1303cdf0e10cSrcweir             int nCluster = nChar2Base;
1304cdf0e10cSrcweir             long origClusterWidth = gi.mnNewWidth;
1305cdf0e10cSrcweir             long nMin = gi.maLinearPos.X();
1306cdf0e10cSrcweir             long nMax = gi.maLinearPos.X() + gi.mnNewWidth;
1307cdf0e10cSrcweir             // attached glyphs are always stored after their base rtl or ltr
1308cdf0e10cSrcweir             while (++nCluster < static_cast<int>(mvGlyphs.size()) &&
1309cdf0e10cSrcweir                 !mvGlyphs[nCluster].IsClusterStart())
1310cdf0e10cSrcweir             {
1311cdf0e10cSrcweir                 origClusterWidth += mvGlyphs[nCluster].mnNewWidth;
1312cdf0e10cSrcweir                 if (mvGlyph2Char[nCluster] == nCharSlot)
1313cdf0e10cSrcweir                 {
1314cdf0e10cSrcweir                     nMin = std::min(nMin, mvGlyphs[nCluster].maLinearPos.X());
1315cdf0e10cSrcweir                     nMax = std::min(nMax, mvGlyphs[nCluster].maLinearPos.X() + mvGlyphs[nCluster].mnNewWidth);
1316cdf0e10cSrcweir                 }
1317cdf0e10cSrcweir             }
1318cdf0e10cSrcweir             if (bRtl)
1319cdf0e10cSrcweir             {
1320cdf0e10cSrcweir                 pCaretXArray[i+1] = nMin;
1321cdf0e10cSrcweir                 pCaretXArray[i] = nMax;
1322cdf0e10cSrcweir             }
1323cdf0e10cSrcweir             else
1324cdf0e10cSrcweir             {
1325cdf0e10cSrcweir                 pCaretXArray[i] = nMin;
1326cdf0e10cSrcweir                 pCaretXArray[i+1] = nMax;
1327cdf0e10cSrcweir             }
1328cdf0e10cSrcweir             prevBase = nChar2Base;
1329cdf0e10cSrcweir             prevClusterWidth = origClusterWidth;
1330cdf0e10cSrcweir         }
1331cdf0e10cSrcweir         else if (prevBase > -1)
1332cdf0e10cSrcweir         {
1333cdf0e10cSrcweir             // this could probably be improved
1334cdf0e10cSrcweir             assert((prevBase > -1) && (prevBase < (signed)mvGlyphs.size()));
1335cdf0e10cSrcweir             GlyphItem gi = mvGlyphs[prevBase];
1336cdf0e10cSrcweir             int nGlyph = prevBase + 1;
1337cdf0e10cSrcweir             // try to find a better match, otherwise default to complete cluster
1338cdf0e10cSrcweir             for (; nGlyph < static_cast<int>(mvGlyphs.size()) &&
1339cdf0e10cSrcweir                  !mvGlyphs[nGlyph].IsClusterStart(); nGlyph++)
1340cdf0e10cSrcweir             {
1341cdf0e10cSrcweir                 if (mvGlyph2Char[nGlyph] == nCharSlot)
1342cdf0e10cSrcweir                 {
1343cdf0e10cSrcweir                     gi = mvGlyphs[nGlyph];
1344cdf0e10cSrcweir                     break;
1345cdf0e10cSrcweir                 }
1346cdf0e10cSrcweir             }
1347cdf0e10cSrcweir             long nGWidth = gi.mnNewWidth;
1348cdf0e10cSrcweir             // if no match position at end of cluster
1349cdf0e10cSrcweir             if (nGlyph == static_cast<int>(mvGlyphs.size()) ||
1350cdf0e10cSrcweir                 mvGlyphs[nGlyph].IsClusterStart())
1351cdf0e10cSrcweir             {
1352cdf0e10cSrcweir                 nGWidth = prevClusterWidth;
1353cdf0e10cSrcweir                 if (bRtl)
1354cdf0e10cSrcweir                 {
1355cdf0e10cSrcweir                     pCaretXArray[i+1] = gi.maLinearPos.X();
1356cdf0e10cSrcweir                     pCaretXArray[i] = gi.maLinearPos.X();
1357cdf0e10cSrcweir                 }
1358cdf0e10cSrcweir                 else
1359cdf0e10cSrcweir                 {
1360cdf0e10cSrcweir                     pCaretXArray[i] = gi.maLinearPos.X() + prevClusterWidth;
1361cdf0e10cSrcweir                     pCaretXArray[i+1] = gi.maLinearPos.X() + prevClusterWidth;
1362cdf0e10cSrcweir                 }
1363cdf0e10cSrcweir             }
1364cdf0e10cSrcweir             else
1365cdf0e10cSrcweir             {
1366cdf0e10cSrcweir                 if (bRtl)
1367cdf0e10cSrcweir                 {
1368cdf0e10cSrcweir                     pCaretXArray[i+1] = gi.maLinearPos.X();
1369cdf0e10cSrcweir                     pCaretXArray[i] = gi.maLinearPos.X() + gi.mnNewWidth;
1370cdf0e10cSrcweir                 }
1371cdf0e10cSrcweir                 else
1372cdf0e10cSrcweir                 {
1373cdf0e10cSrcweir                     pCaretXArray[i] = gi.maLinearPos.X();
1374cdf0e10cSrcweir                     pCaretXArray[i+1] = gi.maLinearPos.X() + gi.mnNewWidth;
1375cdf0e10cSrcweir                 }
1376cdf0e10cSrcweir             }
1377cdf0e10cSrcweir         }
1378cdf0e10cSrcweir         else
1379cdf0e10cSrcweir         {
1380cdf0e10cSrcweir             pCaretXArray[i] = pCaretXArray[i+1] = 0;
1381cdf0e10cSrcweir         }
1382cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1383cdf0e10cSrcweir         fprintf(grLog(),"%d,%d-%d\t", nCharSlot, pCaretXArray[i], pCaretXArray[i+1]);
1384cdf0e10cSrcweir #endif
1385cdf0e10cSrcweir     }
1386cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1387cdf0e10cSrcweir     fprintf(grLog(),"\n");
1388cdf0e10cSrcweir #endif
1389cdf0e10cSrcweir }
1390cdf0e10cSrcweir 
1391cdf0e10cSrcweir 
1392cdf0e10cSrcweir // GetNextGlyphs returns a contiguous sequence of glyphs that can be
1393cdf0e10cSrcweir // rendered together. It should never return a dropped glyph.
1394cdf0e10cSrcweir // The glyph_slot returned should be the index of the next visible
1395cdf0e10cSrcweir // glyph after the last glyph returned by this call.
1396cdf0e10cSrcweir // The char_index array should be filled with the characters corresponding
1397cdf0e10cSrcweir // to each glyph returned.
1398cdf0e10cSrcweir // glyph_adv array should be a virtual width such that if successive
1399cdf0e10cSrcweir // glyphs returned by this method are added one after the other they
1400cdf0e10cSrcweir // have the correct spacing.
1401cdf0e10cSrcweir // The logic in this method must match that expected in MultiSalLayout which
1402cdf0e10cSrcweir // is used when glyph fallback is in operation.
GetNextGlyphs(int length,sal_GlyphId * glyph_out,::Point & aPosOut,int & glyph_slot,sal_Int32 * glyph_adv,int * char_index) const1403cdf0e10cSrcweir int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out,
1404cdf0e10cSrcweir         ::Point & aPosOut, int &glyph_slot, sal_Int32 * glyph_adv, int *char_index) const
1405cdf0e10cSrcweir {
1406cdf0e10cSrcweir   // Sanity check on the slot index.
1407cdf0e10cSrcweir   if (glyph_slot >= signed(mvGlyphs.size()))
1408cdf0e10cSrcweir   {
1409cdf0e10cSrcweir     glyph_slot = mvGlyphs.size();
1410cdf0e10cSrcweir     return 0;
1411cdf0e10cSrcweir   }
1412cdf0e10cSrcweir   assert(glyph_slot >= 0);
1413cdf0e10cSrcweir   // Find the first glyph in the substring.
1414cdf0e10cSrcweir   for (; glyph_slot < signed(mvGlyphs.size()) &&
1415248a599fSHerbert Dürr           ((mvGlyphs.begin() + glyph_slot)->maGlyphId == GF_DROPPED);
1416cdf0e10cSrcweir           ++glyph_slot) {};
1417cdf0e10cSrcweir 
1418cdf0e10cSrcweir   // Update the length
1419cdf0e10cSrcweir   const int nGlyphSlotEnd = std::min(size_t(glyph_slot + length), mvGlyphs.size());
1420cdf0e10cSrcweir 
1421cdf0e10cSrcweir   // We're all out of glyphs here.
1422cdf0e10cSrcweir   if (glyph_slot == nGlyphSlotEnd)
1423cdf0e10cSrcweir   {
1424cdf0e10cSrcweir     return 0;
1425cdf0e10cSrcweir   }
1426cdf0e10cSrcweir 
1427cdf0e10cSrcweir   // Find as many glyphs as we can which can be drawn in one go.
1428cdf0e10cSrcweir   Glyphs::const_iterator glyph_itr = mvGlyphs.begin() + glyph_slot;
1429cdf0e10cSrcweir   const int         glyph_slot_begin = glyph_slot;
1430cdf0e10cSrcweir   const int            initial_y_pos = glyph_itr->maLinearPos.Y();
1431cdf0e10cSrcweir 
1432cdf0e10cSrcweir   // Set the position to the position of the start glyph.
1433cdf0e10cSrcweir   ::Point aStartPos = glyph_itr->maLinearPos;
1434cdf0e10cSrcweir   //aPosOut = glyph_itr->maLinearPos;
1435cdf0e10cSrcweir   aPosOut = GetDrawPosition(aStartPos);
1436cdf0e10cSrcweir 
1437cdf0e10cSrcweir 
1438cdf0e10cSrcweir   for (;;)  // Forever
1439cdf0e10cSrcweir   {
1440cdf0e10cSrcweir      // last index of the range from glyph_to_chars does not include this glyph
1441cdf0e10cSrcweir      if (char_index)
1442cdf0e10cSrcweir      {
1443cdf0e10cSrcweir         assert((glyph_slot >= -1) && (glyph_slot < (signed)mvGlyph2Char.size()));
1444cdf0e10cSrcweir         if (mvGlyph2Char[glyph_slot] == -1)
1445cdf0e10cSrcweir             *char_index++ = mvCharDxs.size();
1446cdf0e10cSrcweir         else
1447cdf0e10cSrcweir             *char_index++ = mvGlyph2Char[glyph_slot];
1448cdf0e10cSrcweir      }
1449cdf0e10cSrcweir      // Copy out this glyphs data.
1450cdf0e10cSrcweir      ++glyph_slot;
1451248a599fSHerbert Dürr      *glyph_out++ = glyph_itr->maGlyphId;
1452cdf0e10cSrcweir 
1453cdf0e10cSrcweir      // Find the actual advance - this must be correct if called from
1454cdf0e10cSrcweir      // MultiSalLayout::AdjustLayout which requests one glyph at a time.
1455cdf0e10cSrcweir      const long nGlyphAdvance = (glyph_slot == static_cast<int>(mvGlyphs.size()))?
1456cdf0e10cSrcweir           glyph_itr->mnNewWidth :
1457cdf0e10cSrcweir           ((glyph_itr+1)->maLinearPos.X() - glyph_itr->maLinearPos.X());
1458cdf0e10cSrcweir 
1459cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1460cdf0e10cSrcweir     fprintf(grLog(),"GetNextGlyphs g%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", glyph_slot - 1,
1461cdf0e10cSrcweir             GLYPH_INDEX_MASK&mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance,
1462cdf0e10cSrcweir             aPosOut.X(), aPosOut.Y());
1463cdf0e10cSrcweir #endif
1464cdf0e10cSrcweir 
1465cdf0e10cSrcweir      if (glyph_adv)  // If we are returning advance store it.
1466cdf0e10cSrcweir        *glyph_adv++ = nGlyphAdvance;
1467cdf0e10cSrcweir      else // Stop when next advance is unexpected.
1468cdf0e10cSrcweir        if (glyph_itr->mnOrigWidth != nGlyphAdvance)  break;
1469cdf0e10cSrcweir 
1470cdf0e10cSrcweir      // Have fetched all the glyphs we need to
1471cdf0e10cSrcweir      if (glyph_slot == nGlyphSlotEnd)
1472cdf0e10cSrcweir          break;
1473cdf0e10cSrcweir 
1474cdf0e10cSrcweir      ++glyph_itr;
1475cdf0e10cSrcweir      // Stop when next y position is unexpected.
1476cdf0e10cSrcweir      if (initial_y_pos != glyph_itr->maLinearPos.Y())
1477cdf0e10cSrcweir        break;
1478cdf0e10cSrcweir 
1479cdf0e10cSrcweir      // Stop if glyph dropped
1480248a599fSHerbert Dürr      if (glyph_itr->maGlyphId == GF_DROPPED)
1481cdf0e10cSrcweir        break;
1482cdf0e10cSrcweir   }
1483cdf0e10cSrcweir   int numGlyphs = glyph_slot - glyph_slot_begin;
1484cdf0e10cSrcweir   // move the next glyph_slot to a glyph that hasn't been dropped
1485cdf0e10cSrcweir   while (glyph_slot < static_cast<int>(mvGlyphs.size()) &&
1486248a599fSHerbert Dürr          (mvGlyphs.begin() + glyph_slot)->maGlyphId == GF_DROPPED)
1487cdf0e10cSrcweir          ++glyph_slot;
1488cdf0e10cSrcweir   return numGlyphs;
1489cdf0e10cSrcweir }
1490cdf0e10cSrcweir 
1491cdf0e10cSrcweir 
MoveGlyph(int nGlyphIndex,long nNewPos)1492cdf0e10cSrcweir void GraphiteLayout::MoveGlyph( int nGlyphIndex, long nNewPos )
1493cdf0e10cSrcweir {
1494cdf0e10cSrcweir     // TODO it might be better to actualy implement simplify properly, but this
1495cdf0e10cSrcweir     // needs to be done carefully so the glyph/char maps are maintained
1496cdf0e10cSrcweir     // If a glyph has been dropped then it wasn't returned by GetNextGlyphs, so
1497cdf0e10cSrcweir     // the index here may be wrong
1498248a599fSHerbert Dürr     while ((mvGlyphs[nGlyphIndex].maGlyphId == GF_DROPPED) &&
1499cdf0e10cSrcweir            (nGlyphIndex < (signed)mvGlyphs.size()))
1500cdf0e10cSrcweir     {
1501cdf0e10cSrcweir         nGlyphIndex++;
1502cdf0e10cSrcweir     }
1503cdf0e10cSrcweir     const long dx = nNewPos - mvGlyphs[nGlyphIndex].maLinearPos.X();
1504cdf0e10cSrcweir 
1505cdf0e10cSrcweir     if (dx == 0)  return;
1506cdf0e10cSrcweir     // GenericSalLayout only changes maLinearPos, mvCharDxs doesn't change
1507cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1508cdf0e10cSrcweir     fprintf(grLog(),"Move %d (%ld,%ld) c%d by %ld\n", nGlyphIndex, mvGlyphs[nGlyphIndex].maLinearPos.X(), nNewPos, mvGlyph2Char[nGlyphIndex], dx);
1509cdf0e10cSrcweir #endif
1510cdf0e10cSrcweir     for (size_t gi = nGlyphIndex; gi < mvGlyphs.size(); gi++)
1511cdf0e10cSrcweir     {
1512cdf0e10cSrcweir         mvGlyphs[gi].maLinearPos.X() += dx;
1513cdf0e10cSrcweir     }
1514cdf0e10cSrcweir     // width does need to be updated for correct fallback
1515cdf0e10cSrcweir     mnWidth += dx;
1516cdf0e10cSrcweir }
1517cdf0e10cSrcweir 
1518cdf0e10cSrcweir 
DropGlyph(int nGlyphIndex)1519cdf0e10cSrcweir void GraphiteLayout::DropGlyph( int nGlyphIndex )
1520cdf0e10cSrcweir {
1521cdf0e10cSrcweir     if(nGlyphIndex >= signed(mvGlyphs.size()))
1522cdf0e10cSrcweir         return;
1523cdf0e10cSrcweir 
1524cdf0e10cSrcweir     GlyphItem & glyph = mvGlyphs[nGlyphIndex];
1525248a599fSHerbert Dürr     glyph.maGlyphId = GF_DROPPED;
1526cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1527cdf0e10cSrcweir     fprintf(grLog(),"Dropped %d\n", nGlyphIndex);
1528cdf0e10cSrcweir #endif
1529cdf0e10cSrcweir }
1530cdf0e10cSrcweir 
Simplify(bool isBaseLayout)1531cdf0e10cSrcweir void GraphiteLayout::Simplify( bool isBaseLayout )
1532cdf0e10cSrcweir {
1533cdf0e10cSrcweir   const sal_GlyphId dropMarker = isBaseLayout ? GF_DROPPED : 0;
1534cdf0e10cSrcweir 
1535cdf0e10cSrcweir   Glyphs::iterator gi = mvGlyphs.begin();
1536cdf0e10cSrcweir   // TODO check whether we need to adjust positions here
1537cdf0e10cSrcweir   // MultiSalLayout seems to move the glyphs itself, so it may not be needed.
1538cdf0e10cSrcweir   long deltaX = 0;
1539cdf0e10cSrcweir   while (gi != mvGlyphs.end())
1540cdf0e10cSrcweir   {
1541248a599fSHerbert Dürr       if (gi->maGlyphId == dropMarker)
1542cdf0e10cSrcweir       {
1543cdf0e10cSrcweir         deltaX += gi->mnNewWidth;
1544cdf0e10cSrcweir         gi->mnNewWidth = 0;
1545cdf0e10cSrcweir       }
1546cdf0e10cSrcweir       else
1547cdf0e10cSrcweir       {
1548cdf0e10cSrcweir         deltaX = 0;
1549cdf0e10cSrcweir       }
1550cdf0e10cSrcweir       //mvCharDxs[mvGlyph2Char[gi->mnCharPos]] -= deltaX;
1551cdf0e10cSrcweir       ++gi;
1552cdf0e10cSrcweir   }
1553cdf0e10cSrcweir #ifdef GRLAYOUT_DEBUG
1554cdf0e10cSrcweir   fprintf(grLog(),"Simplify base%d dx=%ld newW=%ld\n", isBaseLayout, deltaX, mnWidth - deltaX);
1555cdf0e10cSrcweir #endif
1556cdf0e10cSrcweir   // discard width from trailing dropped glyphs, but not those in the middle
1557cdf0e10cSrcweir   mnWidth -= deltaX;
1558cdf0e10cSrcweir }
1559