LCOV - code coverage report
Current view: top level - vcl/source/glyphs - graphite_layout.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 604 0.0 %
Date: 2012-08-25 Functions: 0 31 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 740 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : // Description: An implementation of the SalLayout interface that uses the
      30                 :            : //              Graphite engine.
      31                 :            : 
      32                 :            : 
      33                 :            : // We need this to enable namespace support in libgrengine headers.
      34                 :            : #define GR_NAMESPACE
      35                 :            : 
      36                 :            : // Enable lots of debug info
      37                 :            : #if OSL_DEBUG_LEVEL > 1
      38                 :            : #include <cstdio>
      39                 :            : #define GRLAYOUT_DEBUG 1
      40                 :            : #undef NDEBUG
      41                 :            : #endif
      42                 :            : 
      43                 :            : // #define GRLAYOUT_DEBUG 1
      44                 :            : 
      45                 :            : // Header files
      46                 :            : //
      47                 :            : // Standard Library
      48                 :            : #include <algorithm>
      49                 :            : #include <cassert>
      50                 :            : #include <functional>
      51                 :            : #include <limits>
      52                 :            : #include <numeric>
      53                 :            : #include <deque>
      54                 :            : 
      55                 :            : // Platform
      56                 :            : #include <svsys.h>
      57                 :            : 
      58                 :            : #include <salgdi.hxx>
      59                 :            : 
      60                 :            : #include <unicode/uchar.h>
      61                 :            : #include <unicode/ubidi.h>
      62                 :            : #include <unicode/uscript.h>
      63                 :            : 
      64                 :            : // Graphite Libraries (must be after vcl headers on windows)
      65                 :            : #include <graphite2/Segment.h>
      66                 :            : 
      67                 :            : #include <graphite_layout.hxx>
      68                 :            : #include <graphite_features.hxx>
      69                 :            : 
      70                 :            : // Module private type definitions and forward declarations.
      71                 :            : //
      72                 :            : // Module private names.
      73                 :            : //
      74                 :            : 
      75                 :            : #ifdef GRLAYOUT_DEBUG
      76                 :            : static FILE * grLog()
      77                 :            : {
      78                 :            : #ifdef WNT
      79                 :            :     static FILE * grLogFile = NULL;
      80                 :            :     if (grLogFile == NULL)
      81                 :            :     {
      82                 :            :         std::string logFileName(getenv("TEMP"));
      83                 :            :         logFileName.append("/graphitelayout.log");
      84                 :            :         grLogFile = fopen(logFileName.c_str(),"w");
      85                 :            :     }
      86                 :            :     else
      87                 :            :         fflush(grLogFile);
      88                 :            :     return grLogFile;
      89                 :            : #else
      90                 :            :     fflush(stdout);
      91                 :            :     return stdout;
      92                 :            : #endif
      93                 :            : }
      94                 :            : #endif
      95                 :            : 
      96                 :            : namespace
      97                 :            : {
      98                 :          0 :     inline long round(const float n) {
      99         [ #  # ]:          0 :         return long(n + (n < 0 ? -0.5 : 0.5));
     100                 :            :     }
     101                 :            : 
     102                 :            :     template<typename T>
     103                 :          0 :     inline bool in_range(const T i, const T b, const T e) {
     104 [ #  # ][ #  # ]:          0 :         return !(b > i) && i < e;
     105                 :            :     }
     106                 :            : 
     107                 :            :     template<typename T>
     108                 :            :     inline bool is_subrange(const T sb, const T se, const T b, const T e) {
     109                 :            :         return !(b > sb || se > e);
     110                 :            :     }
     111                 :            : 
     112                 :            :     template<typename T>
     113                 :            :     inline bool is_subrange(const std::pair<T, T> &s, const T b, const T e) {
     114                 :            :         return is_subrange(s.first, s.second, b, e);
     115                 :            :     }
     116                 :            : 
     117                 :          0 :     int findSameDirLimit(const xub_Unicode* buffer, int charCount, bool rtl)
     118                 :            :     {
     119                 :          0 :         UErrorCode status = U_ZERO_ERROR;
     120         [ #  # ]:          0 :         UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
     121                 :          0 :         int limit = 0;
     122                 :            :         ubidi_setPara(ubidi, reinterpret_cast<const UChar *>(buffer), charCount,
     123 [ #  # ][ #  # ]:          0 :             (rtl)?UBIDI_DEFAULT_RTL:UBIDI_DEFAULT_LTR, NULL, &status);
     124                 :          0 :         UBiDiLevel level = 0;
     125         [ #  # ]:          0 :         ubidi_getLogicalRun(ubidi, 0, &limit, &level);
     126         [ #  # ]:          0 :         ubidi_close(ubidi);
     127 [ #  # ][ #  # ]:          0 :         if ((rtl && !(level & 1)) || (!rtl && (level & 1)))
         [ #  # ][ #  # ]
     128                 :            :         {
     129                 :          0 :             limit = 0;
     130                 :            :         }
     131                 :          0 :         return limit;
     132                 :            :     }
     133                 :            : 
     134                 :            :     template <typename T>
     135                 :          0 :     T maximum(T a, T b)
     136                 :            :     {
     137 [ #  # ][ #  # ]:          0 :         return (a > b)? a : b;
                 [ #  # ]
     138                 :            :     }
     139                 :            :     template <typename T>
     140                 :          0 :     T minimum(T a, T b)
     141                 :            :     {
     142 [ #  # ][ #  # ]:          0 :         return (a < b)? a : b;
         [ #  # ][ #  # ]
     143                 :            :     }
     144                 :            : 
     145                 :            : } // namespace
     146                 :            : 
     147                 :            : // Impementation of the GraphiteLayout::Glyphs container class.
     148                 :            : //    This is an extended vector class with methods added to enable
     149                 :            : //        o Correctly filling with glyphs.
     150                 :            : //        o Querying clustering relationships.
     151                 :            : //        o manipulations that affect neighouring glyphs.
     152                 :            : 
     153                 :            : const int GraphiteLayout::EXTRA_CONTEXT_LENGTH = 10;
     154                 :            : 
     155                 :            : // find first slot of cluster and first slot of subsequent cluster
     156                 :          0 : static void findFirstClusterSlot(const gr_slot* base, gr_slot const** first, gr_slot const** after, int * firstChar, int * lastChar, bool bRtl)
     157                 :            : {
     158         [ #  # ]:          0 :     if (gr_slot_attached_to(base) == NULL)
     159                 :            :     {
     160                 :          0 :         *first = base;
     161                 :            :         *after = (bRtl)? gr_slot_prev_in_segment(base) :
     162         [ #  # ]:          0 :             gr_slot_next_in_segment(base);
     163                 :          0 :         *firstChar = gr_slot_before(base);
     164                 :          0 :         *lastChar = gr_slot_after(base);
     165                 :            :     }
     166                 :          0 :     const gr_slot * attachment = gr_slot_first_attachment(base);
     167         [ #  # ]:          0 :     while (attachment)
     168                 :            :     {
     169         [ #  # ]:          0 :         if (gr_slot_origin_X(*first) > gr_slot_origin_X(attachment))
     170                 :          0 :             *first = attachment;
     171                 :            :         const gr_slot* attachmentNext = (bRtl)?
     172         [ #  # ]:          0 :             gr_slot_prev_in_segment(attachment) : gr_slot_next_in_segment(attachment);
     173         [ #  # ]:          0 :         if (attachmentNext)
     174                 :            :         {
     175 [ #  # ][ #  # ]:          0 :             if (*after && (gr_slot_origin_X(*after) < gr_slot_origin_X(attachmentNext)))
                 [ #  # ]
     176                 :          0 :                 *after = attachmentNext;
     177                 :            :         }
     178                 :            :         else
     179                 :            :         {
     180                 :          0 :             *after = NULL;
     181                 :            :         }
     182         [ #  # ]:          0 :         if (gr_slot_before(attachment) < *firstChar)
     183                 :          0 :             *firstChar = gr_slot_before(attachment);
     184         [ #  # ]:          0 :         if (gr_slot_after(attachment) > *lastChar)
     185                 :          0 :             *lastChar = gr_slot_after(attachment);
     186         [ #  # ]:          0 :         if (gr_slot_first_attachment(attachment))
     187                 :          0 :             findFirstClusterSlot(attachment, first, after, firstChar, lastChar, bRtl);
     188                 :          0 :         attachment = gr_slot_next_sibling_attachment(attachment);
     189                 :            :     }
     190                 :          0 : }
     191                 :            : 
     192                 :            : // The Graphite glyph stream is really a sequence of glyph attachment trees
     193                 :            : //  each rooted at a non-attached base glyph.  fill_from walks the glyph stream,
     194                 :            : //  finds each non-attached base glyph and calls append to record them as a
     195                 :            : //  sequence of clusters.
     196                 :            : void
     197                 :          0 : GraphiteLayout::fillFrom(gr_segment * pSegment, ImplLayoutArgs &rArgs, float fScaling)
     198                 :            : {
     199                 :          0 :     bool bRtl = (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL);
     200                 :          0 :     int nCharRequested = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
     201         [ #  # ]:          0 :     int nChar = gr_seg_n_cinfo(pSegment);
     202         [ #  # ]:          0 :     float fMinX = gr_seg_advance_X(pSegment);
     203                 :          0 :     float fMaxX = 0.0f;
     204                 :          0 :     long nDxOffset = 0; // from dropped glyphs
     205                 :          0 :     int nFirstCharInCluster = 0;
     206                 :          0 :     int nLastCharInCluster = 0;
     207         [ #  # ]:          0 :     unsigned int nGlyphs = gr_seg_n_slots(pSegment);
     208         [ #  # ]:          0 :     mvGlyph2Char.assign(nGlyphs, -1);
     209         [ #  # ]:          0 :     mvGlyphs.reserve(nGlyphs);
     210                 :            : 
     211         [ #  # ]:          0 :     if (bRtl)
     212                 :            :     {
     213         [ #  # ]:          0 :         const gr_slot* baseSlot = gr_seg_last_slot(pSegment);
     214                 :            :         // find first base
     215 [ #  # ][ #  # ]:          0 :         while (baseSlot && (gr_slot_attached_to(baseSlot) != NULL))
         [ #  # ][ #  # ]
     216         [ #  # ]:          0 :             baseSlot = gr_slot_prev_in_segment(baseSlot);
     217                 :          0 :         int iChar = nChar - 1;
     218                 :          0 :         int iNextChar = nChar - 1;
     219                 :          0 :         bool reordered = false;
     220                 :          0 :         int nBaseGlyphIndex = 0;
     221                 :            :         // now loop over bases
     222         [ #  # ]:          0 :         while (baseSlot)
     223                 :            :         {
     224                 :          0 :             bool bCluster = !reordered;
     225                 :          0 :             const gr_slot * clusterFirst = NULL;
     226                 :          0 :             const gr_slot * clusterAfter = NULL;
     227                 :          0 :             int firstChar = -1;
     228                 :          0 :             int lastChar = -1;
     229         [ #  # ]:          0 :             findFirstClusterSlot(baseSlot, &clusterFirst, &clusterAfter, &firstChar, &lastChar, bRtl);
     230                 :          0 :             iNextChar = minimum<int>(firstChar, iNextChar);
     231         [ #  # ]:          0 :             if (bCluster)
     232                 :            :             {
     233                 :          0 :                 nBaseGlyphIndex = mvGlyphs.size();
     234         [ #  # ]:          0 :                 mvGlyph2Char[nBaseGlyphIndex] = iChar + mnSegCharOffset;
     235                 :          0 :                 nFirstCharInCluster = firstChar;
     236                 :          0 :                 nLastCharInCluster = lastChar;
     237                 :            :             }
     238                 :            :             else
     239                 :            :             {
     240         [ #  # ]:          0 :                 mvGlyph2Char[mvGlyphs.size()] = firstChar + mnSegCharOffset;
     241                 :          0 :                 nFirstCharInCluster = minimum<int>(firstChar, nFirstCharInCluster);
     242                 :          0 :                 nLastCharInCluster = maximum<int>(firstChar, nLastCharInCluster);
     243                 :            :             }
     244         [ #  # ]:          0 :             float leftBoundary = gr_slot_origin_X(clusterFirst);
     245                 :            :             float rightBoundary = (clusterAfter)?
     246 [ #  # ][ #  # ]:          0 :                 gr_slot_origin_X(clusterAfter) : gr_seg_advance_X(pSegment);
                 [ #  # ]
     247 [ #  # ][ #  # ]:          0 :             if (
                 [ #  # ]
     248                 :            :                 lastChar < iChar &&
     249 [ #  # ][ #  # ]:          0 :                  (gr_cinfo_after(gr_seg_cinfo(pSegment, iChar)) >
     250         [ #  # ]:          0 :                  static_cast<int>(gr_slot_index(clusterAfter)))
     251                 :            :                )
     252                 :            :             {
     253                 :          0 :                 reordered = true;
     254                 :            :             }
     255                 :            :             else
     256                 :            :             {
     257                 :          0 :                 reordered = false;
     258                 :          0 :                 iChar = iNextChar - 1;
     259                 :            :             }
     260 [ #  # ][ #  # ]:          0 :             if (mnSegCharOffset + nFirstCharInCluster >= mnMinCharPos &&
     261                 :            :                 mnSegCharOffset + nFirstCharInCluster < mnEndCharPos)
     262                 :            :             {
     263                 :          0 :                 fMinX = minimum<float>(fMinX, leftBoundary);
     264                 :          0 :                 fMaxX = maximum<float>(fMaxX, rightBoundary);
     265         [ #  # ]:          0 :                 if (!reordered)
     266                 :            :                 {
     267         [ #  # ]:          0 :                     for (int i = nFirstCharInCluster; i <= nLastCharInCluster; i++)
     268                 :            :                     {
     269         [ #  # ]:          0 :                         if (mnSegCharOffset + i >= mnEndCharPos)
     270                 :          0 :                             break;
     271                 :            :                         // from the point of view of the dx array, the xpos is
     272                 :            :                         // the origin of the first glyph of the cluster rtl
     273         [ #  # ]:          0 :                         mvCharDxs[mnSegCharOffset + i - mnMinCharPos] =
     274                 :          0 :                             static_cast<int>(leftBoundary * fScaling) + nDxOffset;
     275 [ #  # ][ #  # ]:          0 :                         mvCharBreaks[mnSegCharOffset + i - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSegment, i));
                 [ #  # ]
     276                 :            :                     }
     277         [ #  # ]:          0 :                     mvChar2BaseGlyph[mnSegCharOffset + nFirstCharInCluster - mnMinCharPos] = nBaseGlyphIndex;
     278                 :            :                 }
     279                 :            :                 append(pSegment, rArgs, baseSlot, gr_slot_origin_X(baseSlot), rightBoundary, fScaling,
     280 [ #  # ][ #  # ]:          0 :                        nDxOffset, bCluster, mnSegCharOffset + firstChar);
     281                 :            :             }
     282         [ #  # ]:          0 :             if (mnSegCharOffset + nLastCharInCluster < mnMinCharPos)
     283                 :            :                 break;
     284         [ #  # ]:          0 :             baseSlot = gr_slot_next_sibling_attachment(baseSlot);
     285                 :            :         }
     286                 :            :     }
     287                 :            :     else
     288                 :            :     {
     289         [ #  # ]:          0 :         const gr_slot* baseSlot = gr_seg_first_slot(pSegment);
     290                 :            :         // find first base
     291 [ #  # ][ #  # ]:          0 :         while (baseSlot && (gr_slot_attached_to(baseSlot) != NULL))
         [ #  # ][ #  # ]
     292         [ #  # ]:          0 :             baseSlot = gr_slot_next_in_segment(baseSlot);
     293                 :          0 :         int iChar = 0; // relative to segment
     294                 :          0 :         int iNextChar = 0;
     295                 :          0 :         bool reordered = false;
     296                 :          0 :         int nBaseGlyphIndex = 0;
     297                 :            :         // now loop over bases
     298         [ #  # ]:          0 :         while (baseSlot)
     299                 :            :         {
     300                 :          0 :             bool bCluster = !reordered;
     301                 :          0 :             const gr_slot * clusterFirst = NULL;
     302                 :          0 :             const gr_slot * clusterAfter = NULL;
     303                 :          0 :             int firstChar = -1;
     304                 :          0 :             int lastChar = -1;
     305         [ #  # ]:          0 :             findFirstClusterSlot(baseSlot, &clusterFirst, &clusterAfter, &firstChar, &lastChar, bRtl);
     306                 :          0 :             iNextChar = maximum<int>(lastChar, iNextChar);
     307         [ #  # ]:          0 :             if (bCluster)
     308                 :            :             {
     309                 :          0 :                 nBaseGlyphIndex = mvGlyphs.size();
     310         [ #  # ]:          0 :                 mvGlyph2Char[nBaseGlyphIndex] = iChar + mnSegCharOffset;
     311                 :          0 :                 nFirstCharInCluster = firstChar;
     312                 :          0 :                 nLastCharInCluster = lastChar;
     313                 :            :             }
     314                 :            :             else
     315                 :            :             {
     316         [ #  # ]:          0 :                 mvGlyph2Char[mvGlyphs.size()] = firstChar + mnSegCharOffset;
     317                 :          0 :                 nFirstCharInCluster = minimum<int>(firstChar, nFirstCharInCluster);
     318                 :          0 :                 nLastCharInCluster = maximum<int>(lastChar, nLastCharInCluster);
     319                 :            :             }
     320 [ #  # ][ #  # ]:          0 :             if (
                 [ #  # ]
     321                 :            :                 firstChar > iChar &&
     322 [ #  # ][ #  # ]:          0 :                  (gr_cinfo_before(gr_seg_cinfo(pSegment, iChar)) >
     323         [ #  # ]:          0 :                  static_cast<int>(gr_slot_index(clusterFirst)))
     324                 :            :                )
     325                 :            :             {
     326                 :          0 :                 reordered = true;
     327                 :            :             }
     328                 :            :             else
     329                 :            :             {
     330                 :          0 :                 reordered = false;
     331                 :          0 :                 iChar = iNextChar + 1;
     332                 :            :             }
     333         [ #  # ]:          0 :             float leftBoundary = gr_slot_origin_X(clusterFirst);
     334                 :            :             float rightBoundary = (clusterAfter)?
     335 [ #  # ][ #  # ]:          0 :                 gr_slot_origin_X(clusterAfter) : gr_seg_advance_X(pSegment);
                 [ #  # ]
     336 [ #  # ][ #  # ]:          0 :             int bFirstChar = gr_cinfo_base(gr_seg_cinfo(pSegment, nFirstCharInCluster));
     337 [ #  # ][ #  # ]:          0 :             if (mnSegCharOffset + bFirstChar >= mnMinCharPos &&
     338                 :            :                 mnSegCharOffset + bFirstChar < mnEndCharPos)
     339                 :            :             {
     340                 :          0 :                 fMinX = minimum<float>(fMinX, leftBoundary);
     341                 :          0 :                 fMaxX = maximum<float>(fMaxX, rightBoundary);
     342         [ #  # ]:          0 :                 if (!reordered)
     343                 :            :                 {
     344         [ #  # ]:          0 :                     for (int i = nFirstCharInCluster; i <= nLastCharInCluster; i++)
     345                 :            :                     {
     346 [ #  # ][ #  # ]:          0 :                         int ibase = gr_cinfo_base(gr_seg_cinfo(pSegment, i));
     347         [ #  # ]:          0 :                         if (mnSegCharOffset + ibase >= mnEndCharPos)
     348                 :          0 :                             break;
     349                 :            :                         // from the point of view of the dx array, the xpos is
     350                 :            :                         // the origin of the first glyph of the next cluster ltr
     351         [ #  # ]:          0 :                         mvCharDxs[mnSegCharOffset + ibase - mnMinCharPos] =
     352                 :          0 :                             static_cast<int>(rightBoundary * fScaling) + nDxOffset;
     353 [ #  # ][ #  # ]:          0 :                         mvCharBreaks[mnSegCharOffset + ibase - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSegment, i));
                 [ #  # ]
     354                 :            :                     }
     355                 :            :                     // only set mvChar2BaseGlyph for first character of cluster
     356         [ #  # ]:          0 :                     mvChar2BaseGlyph[mnSegCharOffset + bFirstChar - mnMinCharPos] = nBaseGlyphIndex;
     357                 :            :                 }
     358                 :            :                 append(pSegment, rArgs, baseSlot, gr_slot_origin_X(baseSlot), rightBoundary, fScaling,
     359 [ #  # ][ #  # ]:          0 :                        nDxOffset, true, mnSegCharOffset + firstChar);
     360                 :            :             }
     361         [ #  # ]:          0 :             if (mnSegCharOffset + bFirstChar >= mnEndCharPos)
     362                 :            :                 break;
     363         [ #  # ]:          0 :             baseSlot = gr_slot_next_sibling_attachment(baseSlot);
     364                 :            :         }
     365                 :            :     }
     366                 :          0 :     long nXOffset = round(fMinX * fScaling);
     367                 :          0 :     mnWidth = round(fMaxX * fScaling) - nXOffset + nDxOffset;
     368         [ #  # ]:          0 :     if (mnWidth < 0)
     369                 :            :     {
     370                 :            :         // This can happen when there was no base inside the range
     371                 :          0 :         mnWidth = 0;
     372                 :            :     }
     373                 :            :     // fill up non-base char dx with cluster widths from previous base glyph
     374         [ #  # ]:          0 :     if (bRtl)
     375                 :            :     {
     376 [ #  # ][ #  # ]:          0 :         if (mvCharDxs[nCharRequested-1] == -1)
     377         [ #  # ]:          0 :             mvCharDxs[nCharRequested-1] = 0;
     378                 :            :         else
     379         [ #  # ]:          0 :             mvCharDxs[nCharRequested-1] -= nXOffset;
     380         [ #  # ]:          0 :         for (int i = nCharRequested - 2; i >= 0; i--)
     381                 :            :         {
     382 [ #  # ][ #  # ]:          0 :             if (mvCharDxs[i] == -1) mvCharDxs[i] = mvCharDxs[i+1];
         [ #  # ][ #  # ]
     383         [ #  # ]:          0 :             else mvCharDxs[i] -= nXOffset;
     384                 :            :         }
     385                 :            :     }
     386                 :            :     else
     387                 :            :     {
     388 [ #  # ][ #  # ]:          0 :         if (mvCharDxs[0] == -1)
     389         [ #  # ]:          0 :             mvCharDxs[0] = 0;
     390                 :            :         else
     391         [ #  # ]:          0 :             mvCharDxs[0] -= nXOffset;
     392         [ #  # ]:          0 :         for (int i = 1; i < nCharRequested; i++)
     393                 :            :         {
     394 [ #  # ][ #  # ]:          0 :             if (mvCharDxs[i] == -1) mvCharDxs[i] = mvCharDxs[i-1];
         [ #  # ][ #  # ]
     395         [ #  # ]:          0 :             else mvCharDxs[i] -= nXOffset;
     396                 :            : #ifdef GRLAYOUT_DEBUG
     397                 :            :             fprintf(grLog(),"%d,%d ", (int)i, (int)mvCharDxs[i]);
     398                 :            : #endif
     399                 :            :         }
     400                 :            :     }
     401                 :            :     // remove offset due to context if there is one
     402         [ #  # ]:          0 :     if (nXOffset != 0)
     403                 :            :     {
     404         [ #  # ]:          0 :         for (size_t i = 0; i < mvGlyphs.size(); i++)
     405                 :          0 :             mvGlyphs[i].maLinearPos.X() -= nXOffset;
     406                 :            :     }
     407                 :            : #ifdef GRLAYOUT_DEBUG
     408                 :            :     fprintf(grLog(), "fillFrom %" SAL_PRI_SIZET "u glyphs offset %ld width %ld\n", mvGlyphs.size(), nXOffset, mnWidth);
     409                 :            : #endif
     410                 :          0 : }
     411                 :            : 
     412                 :            : // append walks an attachment tree, flattening it, and converting it into a
     413                 :            : // sequence of GlyphItem objects which we can later manipulate.
     414                 :            : float
     415                 :          0 : GraphiteLayout::append(gr_segment *pSeg, ImplLayoutArgs &rArgs,
     416                 :            :     const gr_slot * gi, float gOrigin, float nextGlyphOrigin, float scaling, long & rDXOffset,
     417                 :            :     bool bIsBase, int baseChar)
     418                 :            : {
     419                 :          0 :     bool bRtl = (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL);
     420                 :            :     float nextOrigin;
     421                 :            :     assert(gi);
     422                 :            :     assert(gr_slot_before(gi) <= gr_slot_after(gi));
     423         [ #  # ]:          0 :     int firstChar = gr_slot_before(gi) + mnSegCharOffset;
     424                 :            :     assert(mvGlyphs.size() < mvGlyph2Char.size());
     425 [ #  # ][ #  # ]:          0 :     if (!bIsBase) mvGlyph2Char[mvGlyphs.size()] = baseChar;//firstChar;
     426                 :            :     // is the next glyph attached or in the next cluster?
     427                 :            :     //glyph_set_range_t iAttached = gi.attachedClusterGlyphs();
     428         [ #  # ]:          0 :     const gr_slot * pFirstAttached = gr_slot_first_attachment(gi);
     429         [ #  # ]:          0 :     const gr_slot * pNextSibling = gr_slot_next_sibling_attachment(gi);
     430         [ #  # ]:          0 :     if (pFirstAttached)
     431         [ #  # ]:          0 :         nextOrigin = gr_slot_origin_X(pFirstAttached);
     432 [ #  # ][ #  # ]:          0 :     else if (!bIsBase && pNextSibling)
     433         [ #  # ]:          0 :         nextOrigin = gr_slot_origin_X(pNextSibling);
     434                 :            :     else
     435                 :          0 :         nextOrigin = nextGlyphOrigin;
     436         [ #  # ]:          0 :     long glyphId = gr_slot_gid(gi);
     437                 :          0 :     long deltaOffset = 0;
     438         [ #  # ]:          0 :     int scaledGlyphPos = round(gr_slot_origin_X(gi) * scaling);
     439                 :          0 :     int glyphWidth = round((nextOrigin - gOrigin) * scaling);
     440                 :            : //    if (glyphWidth < 0)
     441                 :            : //    {
     442                 :            : //        nextOrigin = gOrigin;
     443                 :            : //        glyphWidth = 0;
     444                 :            : //    }
     445                 :            : #ifdef GRLAYOUT_DEBUG
     446                 :            :     fprintf(grLog(),"c%d g%ld,X%d W%d nX%f ", firstChar, glyphId,
     447                 :            :         (int)(gr_slot_origin_X(gi) * scaling), glyphWidth, nextOrigin * scaling);
     448                 :            : #endif
     449         [ #  # ]:          0 :     if (glyphId == 0)
     450                 :            :     {
     451         [ #  # ]:          0 :         rArgs.NeedFallback(firstChar, bRtl);
     452         [ #  # ]:          0 :         if( (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags ))
     453                 :            :         {
     454                 :          0 :             glyphId = GF_DROPPED;
     455                 :          0 :             deltaOffset -= glyphWidth;
     456                 :          0 :             glyphWidth = 0;
     457                 :            :         }
     458                 :            :     }
     459         [ #  # ]:          0 :     else if(rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK)
     460                 :            :     {
     461                 :            : #ifdef GRLAYOUT_DEBUG
     462                 :            :         fprintf(grLog(),"fallback c%d %x in run %d\n", firstChar, rArgs.mpStr[firstChar],
     463                 :            :             rArgs.maRuns.PosIsInAnyRun(firstChar));
     464                 :            : #endif
     465                 :            :         // glyphs that aren't requested for fallback will be taken from base
     466                 :            :         // layout, so mark them as dropped (should this wait until Simplify(false) is called?)
     467         [ #  # ]:          0 :         if (!rArgs.maRuns.PosIsInAnyRun(firstChar) &&
           [ #  #  #  # ]
                 [ #  # ]
     468                 :          0 :             in_range(firstChar, rArgs.mnMinCharPos, rArgs.mnEndCharPos))
     469                 :            :         {
     470                 :          0 :             glyphId = GF_DROPPED;
     471                 :          0 :             deltaOffset -= glyphWidth;
     472                 :          0 :             glyphWidth = 0;
     473                 :            :         }
     474                 :            :     }
     475                 :            :     // append this glyph. Set the cluster flag if this glyph is attached to another
     476         [ #  # ]:          0 :     long nGlyphFlags = bIsBase ? 0 : GlyphItem::IS_IN_CLUSTER;
     477         [ #  # ]:          0 :     nGlyphFlags |= (bRtl)? GlyphItem::IS_RTL_GLYPH : 0;
     478                 :          0 :     GlyphItem aGlyphItem(mvGlyphs.size(),
     479                 :            :         glyphId,
     480                 :            :         Point(scaledGlyphPos + rDXOffset,
     481         [ #  # ]:          0 :             round((-gr_slot_origin_Y(gi) * scaling))),
     482                 :            :         nGlyphFlags,
     483                 :          0 :         glyphWidth);
     484         [ #  # ]:          0 :     if (glyphId != static_cast<long>(GF_DROPPED))
     485         [ #  # ]:          0 :         aGlyphItem.mnOrigWidth = round(gr_slot_advance_X(gi, mpFace, mpFont) * scaling);
     486         [ #  # ]:          0 :     mvGlyphs.push_back(aGlyphItem);
     487                 :            : 
     488                 :            :     // update the offset if this glyph was dropped
     489                 :          0 :     rDXOffset += deltaOffset;
     490                 :            : 
     491                 :            :     // Recursively append all the attached glyphs.
     492                 :          0 :     float cOrigin = nextOrigin;
     493 [ #  # ][ #  # ]:          0 :     for (const gr_slot * agi = gr_slot_first_attachment(gi); agi != NULL; agi = gr_slot_next_sibling_attachment(agi))
                 [ #  # ]
     494         [ #  # ]:          0 :         cOrigin = append(pSeg, rArgs, agi, cOrigin, nextGlyphOrigin, scaling, rDXOffset, false, baseChar);
     495                 :            : 
     496                 :          0 :     return cOrigin;
     497                 :            : }
     498                 :            : 
     499                 :            : //
     500                 :            : // An implementation of the SalLayout interface to enable Graphite enabled fonts to be used.
     501                 :            : //
     502                 :          0 : GraphiteLayout::GraphiteLayout(const gr_face * face, gr_font * font,
     503                 :            :                                const grutils::GrFeatureParser * pFeatures) throw()
     504                 :            :   : mpFace(face),
     505                 :            :     mpFont(font),
     506                 :            :     mnWidth(0),
     507                 :            :     mfScaling(1.0),
     508 [ #  # ][ #  # ]:          0 :     mpFeatures(pFeatures)
         [ #  # ][ #  # ]
                 [ #  # ]
     509                 :            : {
     510                 :            : 
     511                 :          0 : }
     512                 :            : 
     513                 :          0 : GraphiteLayout::~GraphiteLayout() throw()
     514                 :            : {
     515         [ #  # ]:          0 :     clear();
     516                 :            :     // the features and font are owned by the platform layers
     517                 :          0 :     mpFeatures = NULL;
     518                 :          0 :     mpFont = NULL;
     519         [ #  # ]:          0 : }
     520                 :            : 
     521                 :          0 : void GraphiteLayout::clear()
     522                 :            : {
     523                 :            :     // Destroy the segment and text source from any previous invocation of
     524                 :            :     // LayoutText
     525                 :          0 :     mvGlyphs.clear();
     526                 :          0 :     mvCharDxs.clear();
     527                 :          0 :     mvChar2BaseGlyph.clear();
     528                 :          0 :     mvGlyph2Char.clear();
     529                 :            : 
     530                 :            :     // Reset the state to the empty state.
     531                 :          0 :     mnWidth = 0;
     532                 :            :     // Don't reset the scaling, because it is set before LayoutText
     533                 :          0 : }
     534                 :            : 
     535                 :            : // This method shouldn't be called on windows, since it needs the dc reset
     536                 :          0 : bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs)
     537                 :            : {
     538                 :          0 :     gr_segment * pSegment = NULL;
     539                 :          0 :     bool success = true;
     540         [ #  # ]:          0 :     if (rArgs.mnMinCharPos < rArgs.mnEndCharPos)
     541                 :            :     {
     542                 :          0 :         pSegment = CreateSegment(rArgs);
     543         [ #  # ]:          0 :         if (!pSegment)
     544                 :          0 :             return false;
     545                 :          0 :         success = LayoutGlyphs(rArgs, pSegment);
     546         [ #  # ]:          0 :         if (pSegment)
     547                 :            :         {
     548                 :          0 :             gr_seg_destroy(pSegment);
     549                 :          0 :             pSegment = NULL;
     550                 :            :         }
     551                 :            :     }
     552                 :            :     else
     553                 :            :     {
     554                 :          0 :         clear();
     555                 :            :     }
     556                 :          0 :     return success;
     557                 :            : }
     558                 :            : 
     559                 :            : 
     560                 :          0 : gr_segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs)
     561                 :            : {
     562                 :            :     assert(rArgs.mnLength >= 0);
     563                 :            : 
     564                 :          0 :     gr_segment * pSegment = NULL;
     565                 :            : 
     566                 :            :     // Set the SalLayouts values to be the inital ones.
     567                 :          0 :     SalLayout::AdjustLayout(rArgs);
     568                 :            :     // TODO check if this is needed
     569         [ #  # ]:          0 :     if (mnUnitsPerPixel > 1)
     570                 :          0 :         mfScaling = 1.0f / mnUnitsPerPixel;
     571                 :            : 
     572                 :            :     // Clear out any previous buffers
     573                 :          0 :     clear();
     574                 :          0 :     bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
     575                 :            :     try
     576                 :            :     {
     577                 :            :         // Don't set RTL if font doesn't support it otherwise it forces rtl on
     578                 :            :         // everything
     579                 :            :         //if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl))
     580                 :            :         //    maLayout.setRightToLeft(bRtl);
     581                 :            : 
     582                 :            :         // Context is often needed beyond the specified end, however, we don't
     583                 :            :         // want it if there has been a direction change, since it is hard
     584                 :            :         // to tell between reordering within one direction and multi-directional
     585                 :            :         // text. Extra context, can also cause problems with ligatures stradling
     586                 :            :         // a hyphenation point, so disable if CTL is disabled.
     587                 :          0 :         mnSegCharOffset = rArgs.mnMinCharPos;
     588                 :          0 :         int limit = rArgs.mnEndCharPos;
     589         [ #  # ]:          0 :         if (!(SAL_LAYOUT_COMPLEX_DISABLED & rArgs.mnFlags))
     590                 :            :         {
     591                 :          0 :             const int nSegCharMin = maximum<int>(0, mnMinCharPos - EXTRA_CONTEXT_LENGTH);
     592                 :          0 :             const int nSegCharLimit = minimum(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH);
     593         [ #  # ]:          0 :             if (nSegCharMin < mnSegCharOffset)
     594                 :            :             {
     595                 :            :                 int sameDirEnd = findSameDirLimit(rArgs.mpStr + nSegCharMin,
     596         [ #  # ]:          0 :                     rArgs.mnEndCharPos - nSegCharMin, bRtl);
     597         [ #  # ]:          0 :                 if (sameDirEnd == rArgs.mnEndCharPos)
     598                 :          0 :                     mnSegCharOffset = nSegCharMin;
     599                 :            :             }
     600         [ #  # ]:          0 :             if (nSegCharLimit > limit)
     601                 :            :             {
     602                 :            :                 limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos,
     603         [ #  # ]:          0 :                     nSegCharLimit - rArgs.mnEndCharPos, bRtl);
     604                 :            :             }
     605                 :            :         }
     606                 :          0 :         size_t numchars = gr_count_unicode_characters(gr_utf16, rArgs.mpStr + mnSegCharOffset,
     607         [ #  # ]:          0 :                 rArgs.mpStr + (rArgs.mnLength > limit + 64 ? limit + 64 : rArgs.mnLength), NULL);
     608         [ #  # ]:          0 :         if (mpFeatures)
     609                 :          0 :             pSegment = gr_make_seg(mpFont, mpFace, 0, mpFeatures->values(), gr_utf16,
     610         [ #  # ]:          0 :                                         rArgs.mpStr + mnSegCharOffset, numchars, bRtl);
     611                 :            :         else
     612                 :            :             pSegment = gr_make_seg(mpFont, mpFace, 0, NULL, gr_utf16,
     613         [ #  # ]:          0 :                                         rArgs.mpStr + mnSegCharOffset, numchars, bRtl);
     614                 :            : 
     615                 :            :         //pSegment = new gr::RangeSegment((gr::Font *)&mrFont, mpTextSrc, &maLayout, mnMinCharPos, limit);
     616         [ #  # ]:          0 :         if (pSegment != NULL)
     617                 :            :         {
     618                 :            : #ifdef GRLAYOUT_DEBUG
     619                 :            :             fprintf(grLog(),"Gr::LayoutText %d-%d, context %d, len %d, numchars %" SAL_PRI_SIZET "u, rtl %d scaling %f:", rArgs.mnMinCharPos,
     620                 :            :                rArgs.mnEndCharPos, limit, rArgs.mnLength, numchars, bRtl, mfScaling);
     621                 :            :             for (int i = mnSegCharOffset; i < limit; ++i)
     622                 :            :                 fprintf(grLog(), " %04X", rArgs.mpStr[i]);
     623                 :            :             fprintf(grLog(), "\n");
     624                 :            : #endif
     625                 :            :         }
     626                 :            :         else
     627                 :            :         {
     628                 :            : #ifdef GRLAYOUT_DEBUG
     629                 :            :             fprintf(grLog(), "Gr::LayoutText failed: ");
     630                 :            :             for (int i = mnMinCharPos; i < limit; i++)
     631                 :            :             {
     632                 :            :                 fprintf(grLog(), "%04x ", rArgs.mpStr[i]);
     633                 :            :             }
     634                 :            :             fprintf(grLog(), "\n");
     635                 :            : #endif
     636         [ #  # ]:          0 :             clear();
     637                 :          0 :             return NULL;
     638                 :            :         }
     639                 :            :     }
     640                 :          0 :     catch (...)
     641                 :            :     {
     642         [ #  # ]:          0 :         clear();  // destroy the text source and any partially built segments.
     643                 :          0 :         return NULL;
     644                 :            :     }
     645                 :          0 :     return pSegment;
     646                 :            : }
     647                 :            : 
     648                 :          0 : bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr_segment * pSegment)
     649                 :            : {
     650                 :            :     // Calculate the initial character dxs.
     651                 :          0 :     mvCharDxs.assign(mnEndCharPos - mnMinCharPos, -1);
     652                 :          0 :     mvChar2BaseGlyph.assign(mnEndCharPos - mnMinCharPos, -1);
     653                 :          0 :     mvCharBreaks.assign(mnEndCharPos - mnMinCharPos, 0);
     654                 :          0 :     mnWidth = 0;
     655         [ #  # ]:          0 :     if (mvCharDxs.size() > 0)
     656                 :            :     {
     657                 :            :         // Discover all the clusters.
     658                 :            :         try
     659                 :            :         {
     660                 :          0 :             bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
     661         [ #  # ]:          0 :             fillFrom(pSegment, rArgs, mfScaling);
     662                 :            : 
     663         [ #  # ]:          0 :             if (bRtl)
     664                 :            :             {
     665                 :            :                 // not needed for adjacent differences, but for mouse clicks to char
     666                 :            :                 std::transform(mvCharDxs.begin(), mvCharDxs.end(), mvCharDxs.begin(),
     667         [ #  # ]:          0 :                     std::bind1st(std::minus<long>(), mnWidth));
           [ #  #  #  # ]
     668                 :            :                 // fixup last dx to ensure it always equals the width
     669         [ #  # ]:          0 :                 mvCharDxs[mvCharDxs.size() - 1] = mnWidth;
     670                 :            :             }
     671                 :            :         }
     672                 :          0 :         catch (const std::exception &e)
     673                 :            :         {
     674                 :            : #ifdef GRLAYOUT_DEBUG
     675                 :            :             fprintf(grLog(),"LayoutGlyphs failed %s\n", e.what());
     676                 :            : #else
     677                 :            :             (void)e;
     678                 :            : #endif
     679                 :          0 :             return false;
     680                 :            :         }
     681                 :          0 :         catch (...)
     682                 :            :         {
     683                 :            : #ifdef GRLAYOUT_DEBUG
     684                 :            :             fprintf(grLog(),"LayoutGlyphs failed with exception");
     685                 :            : #endif
     686                 :          0 :             return false;
     687                 :            :         }
     688                 :            :     }
     689                 :            :     else
     690                 :            :     {
     691                 :          0 :         mnWidth = 0;
     692                 :            :     }
     693                 :          0 :     return true;
     694                 :            : }
     695                 :            : 
     696                 :          0 : int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) const
     697                 :            : {
     698                 :            : #ifdef GRLAYOUT_DEBUG
     699                 :            :     fprintf(grLog(),"Gr::GetTextBreak c[%d-%d) maxWidth %ld char extra %ld factor %d\n",
     700                 :            :         mnMinCharPos, mnEndCharPos, maxmnWidth, char_extra, factor);
     701                 :            : #endif
     702                 :            : 
     703                 :            :     // return quickly if this segment is narrower than the target width
     704         [ #  # ]:          0 :     if (maxmnWidth > mnWidth * factor + char_extra * (mnEndCharPos - mnMinCharPos - 1))
     705                 :          0 :         return STRING_LEN;
     706                 :            : 
     707                 :          0 :     long nWidth = mvCharDxs[0] * factor;
     708                 :          0 :     long wLastBreak = 0;
     709                 :          0 :     int nLastBreak = -1;
     710                 :          0 :     int nEmergency = -1;
     711         [ #  # ]:          0 :     for (size_t i = 1; i < mvCharDxs.size(); i++)
     712                 :            :     {
     713                 :          0 :         nWidth += char_extra;
     714         [ #  # ]:          0 :         if (nWidth > maxmnWidth) break;
     715         [ #  # ]:          0 :         if (mvChar2BaseGlyph[i] != -1)
     716                 :            :         {
     717 [ #  # ][ #  #  :          0 :             if (
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     718                 :          0 :                 (mvCharBreaks[i] > -35 || (mvCharBreaks[i-1] > 0 && mvCharBreaks[i-1] < 35)) &&
     719                 :          0 :                 (mvCharBreaks[i-1] < 35 || (mvCharBreaks[i] < 0 && mvCharBreaks[i] > -35))
     720                 :            :                )
     721                 :            :             {
     722                 :          0 :                 nLastBreak = static_cast<int>(i);
     723                 :          0 :                 wLastBreak = nWidth;
     724                 :            :             }
     725                 :          0 :             nEmergency = static_cast<int>(i);
     726                 :            :         }
     727                 :          0 :         nWidth += (mvCharDxs[i] - mvCharDxs[i-1]) * factor;
     728                 :            :     }
     729                 :          0 :     int nBreak = mnMinCharPos;
     730         [ #  # ]:          0 :     if (wLastBreak > 9 * maxmnWidth / 10)
     731                 :          0 :         nBreak += nLastBreak;
     732                 :            :     else
     733         [ #  # ]:          0 :         if (nEmergency > -1)
     734                 :          0 :             nBreak += nEmergency;
     735                 :            : 
     736                 :            : #ifdef GRLAYOUT_DEBUG
     737                 :            :     fprintf(grLog(), "Gr::GetTextBreak break after %d, weights(%d, %d)\n", nBreak - mnMinCharPos, mvCharBreaks[nBreak - mnMinCharPos], mvCharBreaks[nBreak - mnMinCharPos - 1]);
     738                 :            : #endif
     739                 :            : 
     740         [ #  # ]:          0 :     if (nBreak > mnEndCharPos) nBreak = STRING_LEN;
     741         [ #  # ]:          0 :     else if (nBreak < mnMinCharPos) nBreak = mnMinCharPos;
     742                 :          0 :     return nBreak;
     743                 :            : }
     744                 :            : 
     745                 :          0 : long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const
     746                 :            : {
     747         [ #  # ]:          0 :     if (mnEndCharPos == mnMinCharPos)
     748                 :            :         // Then we must be zero width!
     749                 :          0 :         return 0;
     750                 :            : 
     751         [ #  # ]:          0 :     if (pDXArray)
     752                 :            :     {
     753         [ #  # ]:          0 :         for (size_t i = 0; i < mvCharDxs.size(); i++)
     754                 :            :         {
     755                 :            :             assert( (mvChar2BaseGlyph[i] == -1) ||
     756                 :            :                 ((signed)(mvChar2BaseGlyph[i]) < (signed)mvGlyphs.size()));
     757   [ #  #  #  # ]:          0 :             if (mvChar2BaseGlyph[i] != -1 &&
                 [ #  # ]
     758                 :          0 :                 mvGlyphs[mvChar2BaseGlyph[i]].mnGlyphIndex == GF_DROPPED)
     759                 :            :             {
     760                 :            :                 // when used in MultiSalLayout::GetTextBreak dropped glyphs
     761                 :            :                 // must have zero width
     762                 :          0 :                 pDXArray[i] = 0;
     763                 :            :             }
     764                 :            :             else
     765                 :            :             {
     766                 :          0 :                 pDXArray[i] = mvCharDxs[i];
     767         [ #  # ]:          0 :                 if (i > 0) pDXArray[i] -= mvCharDxs[i-1];
     768                 :            :             }
     769                 :            : #ifdef GRLAYOUT_DEBUG
     770                 :            :             fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
     771                 :            : #endif
     772                 :            :         }
     773                 :            :         //std::adjacent_difference(mvCharDxs.begin(), mvCharDxs.end(), pDXArray);
     774                 :            :         //for (size_t i = 0; i < mvCharDxs.size(); i++)
     775                 :            :         //    fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
     776                 :            :         //fprintf(grLog(),"FillDX %ld,%d\n", mnWidth, std::accumulate(pDXArray, pDXArray + mvCharDxs.size(), 0));
     777                 :            :     }
     778                 :            : #ifdef GRLAYOUT_DEBUG
     779                 :            :     fprintf(grLog(),"FillDXArray %d-%d=%ld\n", mnMinCharPos, mnEndCharPos, mnWidth);
     780                 :            : #endif
     781                 :          0 :     return mnWidth;
     782                 :            : }
     783                 :            : 
     784                 :          0 : void  GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs)
     785                 :            : {
     786                 :          0 :     SalLayout::AdjustLayout(rArgs);
     787         [ #  # ]:          0 :     if(rArgs.mpDXArray)
     788                 :            :     {
     789         [ #  # ]:          0 :         std::vector<int> vDeltaWidths(mvGlyphs.size(), 0);
     790         [ #  # ]:          0 :         ApplyDXArray(rArgs, vDeltaWidths);
     791                 :            : 
     792 [ #  # ][ #  # ]:          0 :         if( (mnLayoutFlags & SAL_LAYOUT_BIDI_RTL) &&
     793                 :          0 :            !(rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
     794                 :            :         {
     795                 :            :             // check if this is a kashida script
     796                 :          0 :             bool bKashidaScript = false;
     797         [ #  # ]:          0 :             for (int i = rArgs.mnMinCharPos; i < rArgs.mnEndCharPos; i++)
     798                 :            :             {
     799                 :          0 :                 UErrorCode aStatus = U_ZERO_ERROR;
     800         [ #  # ]:          0 :                 UScriptCode scriptCode = uscript_getScript(rArgs.mpStr[i], &aStatus);
     801 [ #  # ][ #  # ]:          0 :                 if (scriptCode == USCRIPT_ARABIC || scriptCode == USCRIPT_SYRIAC)
     802                 :            :                 {
     803                 :          0 :                     bKashidaScript = true;
     804                 :            :                     break;
     805                 :            :                 }
     806                 :            :             }
     807                 :          0 :             int nKashidaWidth = 0;
     808         [ #  # ]:          0 :             int nKashidaIndex = getKashidaGlyph(nKashidaWidth);
     809 [ #  # ][ #  # ]:          0 :             if( nKashidaIndex != 0 && bKashidaScript)
     810                 :            :             {
     811         [ #  # ]:          0 :                 kashidaJustify( vDeltaWidths, nKashidaIndex, nKashidaWidth );
     812                 :            :             }
     813                 :          0 :         }
     814                 :            :     }
     815         [ #  # ]:          0 :     else if (rArgs.mnLayoutWidth > 0)
     816                 :            :     {
     817                 :            : #ifdef GRLAYOUT_DEBUG
     818                 :            :         fprintf(grLog(), "AdjustLayout width %ld=>%ld\n", mnWidth, rArgs.mnLayoutWidth);
     819                 :            : #endif
     820                 :          0 :         expandOrCondense(rArgs);
     821                 :            :     }
     822                 :          0 : }
     823                 :            : 
     824                 :          0 : void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs)
     825                 :            : {
     826                 :          0 :     int nDeltaWidth = rArgs.mnLayoutWidth - mnWidth;
     827         [ #  # ]:          0 :     if (nDeltaWidth > 0) // expand, just expand between clusters
     828                 :            :     {
     829                 :            :         // NOTE: for expansion we can use base glyphs (which have IsClusterStart set)
     830                 :            :         // even though they may have been reordered in which case they will have
     831                 :            :         // been placed in a bigger cluster for other purposes.
     832                 :          0 :         int nClusterCount = 0;
     833         [ #  # ]:          0 :         for (size_t j = 0; j < mvGlyphs.size(); j++)
     834                 :            :         {
     835         [ #  # ]:          0 :             if (mvGlyphs[j].IsClusterStart())
     836                 :            :             {
     837                 :          0 :                 ++nClusterCount;
     838                 :            :             }
     839                 :            :         }
     840         [ #  # ]:          0 :         if (nClusterCount > 1)
     841                 :            :         {
     842                 :          0 :             float fExtraPerCluster = static_cast<float>(nDeltaWidth) / static_cast<float>(nClusterCount - 1);
     843                 :          0 :             int nCluster = 0;
     844                 :          0 :             int nOffset = 0;
     845         [ #  # ]:          0 :             for (size_t i = 0; i < mvGlyphs.size(); i++)
     846                 :            :             {
     847         [ #  # ]:          0 :                 if (mvGlyphs[i].IsClusterStart())
     848                 :            :                 {
     849                 :          0 :                     nOffset = static_cast<int>(fExtraPerCluster * nCluster);
     850                 :          0 :                     int nCharIndex = mvGlyph2Char[i];
     851                 :            :                     assert(nCharIndex > -1);
     852         [ #  # ]:          0 :                     if (nCharIndex < mnMinCharPos ||
           [ #  #  #  # ]
     853                 :            :                         static_cast<size_t>(nCharIndex-mnMinCharPos)
     854                 :          0 :                             >= mvCharDxs.size())
     855                 :            :                     {
     856                 :          0 :                         continue;
     857                 :            :                     }
     858                 :          0 :                     mvCharDxs[nCharIndex-mnMinCharPos] += nOffset;
     859                 :            :                     // adjust char dxs for rest of characters in cluster
     860         [ #  # ]:          0 :                     while (++nCharIndex - mnMinCharPos < static_cast<int>(mvChar2BaseGlyph.size()))
     861                 :            :                     {
     862                 :          0 :                         int nChar2Base = mvChar2BaseGlyph[nCharIndex-mnMinCharPos];
     863 [ #  # ][ #  # ]:          0 :                         if (nChar2Base == -1 || nChar2Base == static_cast<int>(i))
     864                 :          0 :                             mvCharDxs[nCharIndex-mnMinCharPos] += nOffset;
     865                 :            :                         else
     866                 :          0 :                             break;
     867                 :            :                     }
     868                 :          0 :                     ++nCluster;
     869                 :            :                 }
     870                 :          0 :                 mvGlyphs[i].maLinearPos.X() += nOffset;
     871                 :            :             }
     872                 :            :         }
     873                 :            :     }
     874         [ #  # ]:          0 :     else if (nDeltaWidth < 0)// condense - apply a factor to all glyph positions
     875                 :            :     {
     876         [ #  # ]:          0 :         if (mvGlyphs.empty()) return;
     877         [ #  # ]:          0 :         Glyphs::iterator iLastGlyph = mvGlyphs.begin() + (mvGlyphs.size() - 1);
     878                 :            :         // position last glyph using original width
     879                 :          0 :         float fXFactor = static_cast<float>(rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth) / static_cast<float>(iLastGlyph->maLinearPos.X());
     880                 :            : #ifdef GRLAYOUT_DEBUG
     881                 :            :         fprintf(grLog(), "Condense by factor %f last x%ld\n", fXFactor, iLastGlyph->maLinearPos.X());
     882                 :            : #endif
     883         [ #  # ]:          0 :         if (fXFactor < 0)
     884                 :            :             return; // probably a bad mnOrigWidth value
     885                 :          0 :         iLastGlyph->maLinearPos.X() = rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth;
     886                 :          0 :         Glyphs::iterator iGlyph = mvGlyphs.begin();
     887 [ #  # ][ #  # ]:          0 :         while (iGlyph != iLastGlyph)
     888                 :            :         {
     889                 :          0 :             iGlyph->maLinearPos.X() = static_cast<int>(static_cast<float>(iGlyph->maLinearPos.X()) * fXFactor);
     890                 :          0 :             ++iGlyph;
     891                 :            :         }
     892         [ #  # ]:          0 :         for (size_t i = 0; i < mvCharDxs.size(); i++)
     893                 :            :         {
     894 [ #  # ][ #  # ]:          0 :             mvCharDxs[i] = static_cast<int>(fXFactor * static_cast<float>(mvCharDxs[i]));
     895                 :            :         }
     896                 :            :     }
     897                 :          0 :     mnWidth = rArgs.mnLayoutWidth;
     898                 :            : }
     899                 :            : 
     900                 :          0 : void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDeltaWidth)
     901                 :            : {
     902                 :          0 :     const size_t nChars = args.mnEndCharPos - args.mnMinCharPos;
     903         [ #  # ]:          0 :     if (nChars == 0) return;
     904                 :            : 
     905                 :            : #ifdef GRLAYOUT_DEBUG
     906                 :            :     for (size_t iDx = 0; iDx < mvCharDxs.size(); iDx++)
     907                 :            :          fprintf(grLog(),"%d,%d,%d ", (int)iDx, (int)mvCharDxs[iDx], args.mpDXArray[iDx]);
     908                 :            :     fprintf(grLog(),"ApplyDx\n");
     909                 :            : #endif
     910                 :          0 :     bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
     911                 :          0 :     int nXOffset = 0;
     912         [ #  # ]:          0 :     if (bRtl)
     913                 :            :     {
     914                 :          0 :         nXOffset = args.mpDXArray[nChars - 1] - mvCharDxs[nChars - 1];
     915                 :            :     }
     916         [ #  # ]:          0 :     int nPrevClusterGlyph = (bRtl)? (signed)mvGlyphs.size() : -1;
     917                 :          0 :     int nPrevClusterLastChar = -1;
     918         [ #  # ]:          0 :     for (size_t i = 0; i < nChars; i++)
     919                 :            :     {
     920                 :          0 :         int nChar2Base = mvChar2BaseGlyph[i];
     921 [ #  # ][ #  # ]:          0 :         if ((nChar2Base > -1) && (nChar2Base != nPrevClusterGlyph))
     922                 :            :         {
     923                 :            :             assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size()));
     924                 :          0 :             GlyphItem & gi = mvGlyphs[nChar2Base];
     925         [ #  # ]:          0 :             if (!gi.IsClusterStart())
     926                 :          0 :                 continue;
     927                 :            : 
     928                 :            :             // find last glyph of this cluster
     929                 :          0 :             size_t j = i + 1;
     930                 :          0 :             int nLastChar = i;
     931                 :          0 :             int nLastGlyph = nChar2Base;
     932                 :          0 :             int nChar2BaseJ = -1;
     933         [ #  # ]:          0 :             for (; j < nChars; j++)
     934                 :            :             {
     935                 :          0 :                 nChar2BaseJ = mvChar2BaseGlyph[j];
     936                 :            :                 assert((nChar2BaseJ >= -1) && (nChar2BaseJ < (signed)mvGlyphs.size()));
     937         [ #  # ]:          0 :                 if (nChar2BaseJ != -1 )
     938                 :            :                 {
     939         [ #  # ]:          0 :                     nLastGlyph = nChar2BaseJ + ((bRtl)? +1 : -1);
     940                 :          0 :                     nLastChar = j - 1;
     941                 :          0 :                     break;
     942                 :            :                 }
     943                 :            :             }
     944         [ #  # ]:          0 :             if (nLastGlyph < 0)
     945                 :            :             {
     946                 :          0 :                 nLastGlyph = nChar2Base;
     947                 :            :             }
     948                 :            :             // Its harder to find the last glyph rtl, since the first of
     949                 :            :             // cluster is still on the left so we need to search towards
     950                 :            :             // the previous cluster to the right
     951         [ #  # ]:          0 :             if (bRtl)
     952                 :            :             {
     953                 :          0 :                 nLastGlyph = nChar2Base;
     954   [ #  #  #  # ]:          0 :                 while (nLastGlyph + 1 < (signed)mvGlyphs.size() &&
                 [ #  # ]
     955                 :          0 :                        !mvGlyphs[nLastGlyph+1].IsClusterStart())
     956                 :            :                 {
     957                 :          0 :                     ++nLastGlyph;
     958                 :            :                 }
     959                 :            :             }
     960         [ #  # ]:          0 :             if (j == nChars)
     961                 :            :             {
     962                 :          0 :                 nLastChar = nChars - 1;
     963         [ #  # ]:          0 :                 if (!bRtl) nLastGlyph = mvGlyphs.size() - 1;
     964                 :            :             }
     965                 :          0 :             int nBaseCount = 0;
     966                 :            :             // count bases within cluster - may be more than 1 with reordering
     967         [ #  # ]:          0 :             for (int k = nChar2Base; k <= nLastGlyph; k++)
     968                 :            :             {
     969         [ #  # ]:          0 :                 if (mvGlyphs[k].IsClusterStart()) ++nBaseCount;
     970                 :            :             }
     971                 :            :             assert((nLastChar > -1) && (nLastChar < (signed)nChars));
     972                 :          0 :             long nNewClusterWidth = args.mpDXArray[nLastChar];
     973                 :          0 :             long nOrigClusterWidth = mvCharDxs[nLastChar];
     974                 :          0 :             long nDGlyphOrigin = 0;
     975         [ #  # ]:          0 :             if (nPrevClusterLastChar > - 1)
     976                 :            :             {
     977                 :            :                 assert(nPrevClusterLastChar < (signed)nChars);
     978                 :          0 :                 nNewClusterWidth -= args.mpDXArray[nPrevClusterLastChar];
     979                 :          0 :                 nOrigClusterWidth -= mvCharDxs[nPrevClusterLastChar];
     980                 :          0 :                 nDGlyphOrigin = args.mpDXArray[nPrevClusterLastChar] - mvCharDxs[nPrevClusterLastChar];
     981                 :            :             }
     982                 :          0 :             long nDWidth = nNewClusterWidth - nOrigClusterWidth;
     983                 :            : #ifdef GRLAYOUT_DEBUG
     984                 :            :             fprintf(grLog(), "c%lu last glyph %d/%lu\n", i, nLastGlyph, mvGlyphs.size());
     985                 :            : #endif
     986                 :            :             assert((nLastGlyph > -1) && (nLastGlyph < (signed)mvGlyphs.size()));
     987                 :          0 :             mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
     988         [ #  # ]:          0 :             if (gi.mnGlyphIndex != GF_DROPPED)
     989                 :          0 :                 mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
     990                 :            :             else
     991                 :          0 :                 nDGlyphOrigin += nDWidth;
     992         [ #  # ]:          0 :             long nDOriginPerBase = (nBaseCount > 0)? nDWidth / nBaseCount : 0;
     993                 :          0 :             nBaseCount = -1;
     994                 :            :             // update glyph positions
     995         [ #  # ]:          0 :             if (bRtl)
     996                 :            :             {
     997         [ #  # ]:          0 :                 for (int n = nChar2Base; n <= nLastGlyph; n++)
     998                 :            :                 {
     999         [ #  # ]:          0 :                     if (mvGlyphs[n].IsClusterStart()) ++nBaseCount;
    1000                 :            :                     assert((n > - 1) && (n < (signed)mvGlyphs.size()));
    1001                 :          0 :                     mvGlyphs[n].maLinearPos.X() += -(nDGlyphOrigin + nDOriginPerBase * nBaseCount) + nXOffset;
    1002                 :            :                 }
    1003                 :            :             }
    1004                 :            :             else
    1005                 :            :             {
    1006         [ #  # ]:          0 :                 for (int n = nChar2Base; n <= nLastGlyph; n++)
    1007                 :            :                 {
    1008         [ #  # ]:          0 :                     if (mvGlyphs[n].IsClusterStart()) ++nBaseCount;
    1009                 :            :                     assert((n > - 1) && (n < (signed)mvGlyphs.size()));
    1010                 :          0 :                     mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + (nDOriginPerBase * nBaseCount) + nXOffset;
    1011                 :            :                 }
    1012                 :            :             }
    1013                 :          0 :             rDeltaWidth[nChar2Base] = nDWidth;
    1014                 :            : #ifdef GRLAYOUT_DEBUG
    1015                 :            :             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());
    1016                 :            : #endif
    1017                 :          0 :             nPrevClusterGlyph = nChar2Base;
    1018                 :          0 :             nPrevClusterLastChar = nLastChar;
    1019                 :          0 :             i = nLastChar;
    1020                 :            :         }
    1021                 :            :     }
    1022                 :            :     // Update the dx vector with the new values.
    1023                 :            :     std::copy(args.mpDXArray, args.mpDXArray + nChars,
    1024 [ #  # ][ #  # ]:          0 :       mvCharDxs.begin() + (args.mnMinCharPos - mnMinCharPos));
    1025                 :            : #ifdef GRLAYOUT_DEBUG
    1026                 :            :     fprintf(grLog(),"ApplyDx %d(%ld)\n", args.mpDXArray[nChars - 1], mnWidth);
    1027                 :            : #endif
    1028                 :          0 :     mnWidth = args.mpDXArray[nChars - 1];
    1029                 :            : }
    1030                 :            : 
    1031                 :          0 : void GraphiteLayout::kashidaJustify(std::vector<int>& rDeltaWidths, sal_GlyphId nKashidaIndex, int nKashidaWidth)
    1032                 :            : {
    1033                 :            :     // skip if the kashida glyph in the font looks suspicious
    1034         [ #  # ]:          0 :     if( nKashidaWidth <= 0 )
    1035                 :          0 :         return;
    1036                 :            : 
    1037                 :            :     // calculate max number of needed kashidas
    1038                 :          0 :     Glyphs::iterator i = mvGlyphs.begin();
    1039                 :          0 :     int nKashidaCount = 0;
    1040                 :          0 :     int nOrigGlyphIndex = -1;
    1041                 :          0 :     int nGlyphIndex = -1;
    1042 [ #  # ][ #  # ]:          0 :     while (i != mvGlyphs.end())
    1043                 :            :     {
    1044                 :          0 :         nOrigGlyphIndex++;
    1045                 :          0 :         nGlyphIndex++;
    1046                 :            :         // only inject kashidas in RTL contexts
    1047         [ #  # ]:          0 :         if( !(*i).IsRTLGlyph() )
    1048                 :            :         {
    1049                 :          0 :             ++i;
    1050                 :          0 :             continue;
    1051                 :            :         }
    1052                 :            :         // no kashida-injection for blank justified expansion either
    1053 [ #  # ][ #  # ]:          0 :         if( IsSpacingGlyph( (*i).mnGlyphIndex ) )
    1054                 :            :         {
    1055                 :          0 :             ++i;
    1056                 :          0 :             continue;
    1057                 :            :         }
    1058                 :            :         // calculate gap, ignore if too small
    1059         [ #  # ]:          0 :         int nGapWidth = rDeltaWidths[nOrigGlyphIndex];
    1060                 :            :         // worst case is one kashida even for mini-gaps
    1061         [ #  # ]:          0 :         if( 3 * nGapWidth < nKashidaWidth )
    1062                 :            :         {
    1063                 :          0 :             ++i;
    1064                 :          0 :             continue;
    1065                 :            :         }
    1066                 :          0 :         nKashidaCount = 1 + (nGapWidth / nKashidaWidth);
    1067                 :            : #ifdef GRLAYOUT_DEBUG
    1068                 :            :         printf("inserting %d kashidas at %u\n", nKashidaCount, (*i).mnGlyphIndex);
    1069                 :            : #endif
    1070                 :          0 :         GlyphItem glyphItem = *i;
    1071                 :          0 :         Point aPos(0, 0);
    1072                 :          0 :         aPos.X() = (*i).maLinearPos.X();
    1073                 :            :         GlyphItem newGi(glyphItem.mnCharPos, nKashidaIndex, aPos,
    1074                 :          0 :                 GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaWidth);
    1075         [ #  # ]:          0 :         mvGlyphs.reserve(mvGlyphs.size() + nKashidaCount);
    1076         [ #  # ]:          0 :         i = mvGlyphs.begin() + nGlyphIndex;
    1077         [ #  # ]:          0 :         mvGlyphs.insert(i, nKashidaCount, newGi);
    1078         [ #  # ]:          0 :         i = mvGlyphs.begin() + nGlyphIndex;
    1079                 :          0 :         nGlyphIndex += nKashidaCount;
    1080                 :            :         // now fix up the kashida positions
    1081         [ #  # ]:          0 :         for (int j = 0; j < nKashidaCount; j++)
    1082                 :            :         {
    1083                 :          0 :             (*(i)).maLinearPos.X() -= nGapWidth;
    1084                 :          0 :             nGapWidth -= nKashidaWidth;
    1085                 :          0 :             ++i;
    1086                 :            :         }
    1087                 :            : 
    1088                 :            :         // fixup rightmost kashida for gap remainder
    1089         [ #  # ]:          0 :         if( nGapWidth < 0 )
    1090                 :            :         {
    1091         [ #  # ]:          0 :             if( nKashidaCount <= 1 )
    1092                 :          0 :                 nGapWidth /= 2;               // for small gap move kashida to middle
    1093         [ #  # ]:          0 :             (*(i-1)).mnNewWidth += nGapWidth;  // adjust kashida width to gap width
    1094         [ #  # ]:          0 :             (*(i-1)).maLinearPos.X() += nGapWidth;
    1095                 :            :         }
    1096                 :            : 
    1097                 :          0 :         (*i).mnNewWidth = (*i).mnOrigWidth;
    1098                 :          0 :         ++i;
    1099                 :            :     }
    1100                 :            : 
    1101                 :            : }
    1102                 :            : 
    1103                 :          0 : void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const
    1104                 :            : {
    1105                 :            :     // For each character except the last discover the caret positions
    1106                 :            :     // immediatly before and after that character.
    1107                 :            :     // This is used for underlines in the GUI amongst other things.
    1108                 :            :     // It may be used from MultiSalLayout, in which case it must take into account
    1109                 :            :     // glyphs that have been moved.
    1110         [ #  # ]:          0 :     std::fill(pCaretXArray, pCaretXArray + nArraySize, -1);
    1111                 :            :     // the layout method doesn't modify the layout even though it isn't
    1112                 :            :     // const in the interface
    1113                 :          0 :     bool bRtl = (mnLayoutFlags & SAL_LAYOUT_BIDI_RTL);//const_cast<GraphiteLayout*>(this)->maLayout.rightToLeft();
    1114                 :          0 :     int prevBase = -1;
    1115                 :          0 :     long prevClusterWidth = 0;
    1116 [ #  # ][ #  # ]:          0 :     for (int i = 0, nCharSlot = 0; i < nArraySize && nCharSlot < static_cast<int>(mvCharDxs.size()); ++nCharSlot, i+=2)
                 [ #  # ]
    1117                 :            :     {
    1118         [ #  # ]:          0 :         if (mvChar2BaseGlyph[nCharSlot] != -1)
    1119                 :            :         {
    1120         [ #  # ]:          0 :             int nChar2Base = mvChar2BaseGlyph[nCharSlot];
    1121                 :            :             assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size()));
    1122                 :          0 :             GlyphItem gi = mvGlyphs[nChar2Base];
    1123         [ #  # ]:          0 :             if (gi.mnGlyphIndex == GF_DROPPED)
    1124                 :            :             {
    1125                 :          0 :                 continue;
    1126                 :            :             }
    1127                 :          0 :             int nCluster = nChar2Base;
    1128                 :          0 :             long origClusterWidth = gi.mnNewWidth;
    1129                 :          0 :             long nMin = gi.maLinearPos.X();
    1130                 :          0 :             long nMax = gi.maLinearPos.X() + gi.mnNewWidth;
    1131                 :            :             // attached glyphs are always stored after their base rtl or ltr
    1132   [ #  #  #  # ]:          0 :             while (++nCluster < static_cast<int>(mvGlyphs.size()) &&
                 [ #  # ]
    1133                 :          0 :                 !mvGlyphs[nCluster].IsClusterStart())
    1134                 :            :             {
    1135                 :          0 :                 origClusterWidth += mvGlyphs[nCluster].mnNewWidth;
    1136 [ #  # ][ #  # ]:          0 :                 if (mvGlyph2Char[nCluster] == nCharSlot)
    1137                 :            :                 {
    1138                 :          0 :                     nMin = minimum(nMin, mvGlyphs[nCluster].maLinearPos.X());
    1139                 :          0 :                     nMax = maximum(nMax, mvGlyphs[nCluster].maLinearPos.X() + mvGlyphs[nCluster].mnNewWidth);
    1140                 :            :                 }
    1141                 :            :             }
    1142         [ #  # ]:          0 :             if (bRtl)
    1143                 :            :             {
    1144                 :          0 :                 pCaretXArray[i+1] = nMin;
    1145                 :          0 :                 pCaretXArray[i] = nMax;
    1146                 :            :             }
    1147                 :            :             else
    1148                 :            :             {
    1149                 :          0 :                 pCaretXArray[i] = nMin;
    1150                 :          0 :                 pCaretXArray[i+1] = nMax;
    1151                 :            :             }
    1152                 :          0 :             prevBase = nChar2Base;
    1153                 :          0 :             prevClusterWidth = origClusterWidth;
    1154                 :            :         }
    1155         [ #  # ]:          0 :         else if (prevBase > -1)
    1156                 :            :         {
    1157                 :            :             // this could probably be improved
    1158                 :            :             assert((prevBase > -1) && (prevBase < (signed)mvGlyphs.size()));
    1159                 :          0 :             GlyphItem gi = mvGlyphs[prevBase];
    1160                 :          0 :             int nGlyph = prevBase + 1;
    1161                 :            :             // try to find a better match, otherwise default to complete cluster
    1162   [ #  #  #  # ]:          0 :             for (; nGlyph < static_cast<int>(mvGlyphs.size()) &&
                 [ #  # ]
    1163                 :          0 :                  !mvGlyphs[nGlyph].IsClusterStart(); nGlyph++)
    1164                 :            :             {
    1165 [ #  # ][ #  # ]:          0 :                 if (mvGlyph2Char[nGlyph] == nCharSlot)
    1166                 :            :                 {
    1167                 :          0 :                     gi = mvGlyphs[nGlyph];
    1168                 :          0 :                     break;
    1169                 :            :                 }
    1170                 :            :             }
    1171                 :            :             // if no match position at end of cluster
    1172   [ #  #  #  # ]:          0 :             if (nGlyph == static_cast<int>(mvGlyphs.size()) ||
                 [ #  # ]
    1173                 :          0 :                 mvGlyphs[nGlyph].IsClusterStart())
    1174                 :            :             {
    1175         [ #  # ]:          0 :                 if (bRtl)
    1176                 :            :                 {
    1177                 :          0 :                     pCaretXArray[i+1] = gi.maLinearPos.X();
    1178                 :          0 :                     pCaretXArray[i] = gi.maLinearPos.X();
    1179                 :            :                 }
    1180                 :            :                 else
    1181                 :            :                 {
    1182                 :          0 :                     pCaretXArray[i] = gi.maLinearPos.X() + prevClusterWidth;
    1183                 :          0 :                     pCaretXArray[i+1] = gi.maLinearPos.X() + prevClusterWidth;
    1184                 :            :                 }
    1185                 :            :             }
    1186                 :            :             else
    1187                 :            :             {
    1188         [ #  # ]:          0 :                 if (bRtl)
    1189                 :            :                 {
    1190                 :          0 :                     pCaretXArray[i+1] = gi.maLinearPos.X();
    1191                 :          0 :                     pCaretXArray[i] = gi.maLinearPos.X() + gi.mnNewWidth;
    1192                 :            :                 }
    1193                 :            :                 else
    1194                 :            :                 {
    1195                 :          0 :                     pCaretXArray[i] = gi.maLinearPos.X();
    1196                 :          0 :                     pCaretXArray[i+1] = gi.maLinearPos.X() + gi.mnNewWidth;
    1197                 :            :                 }
    1198                 :            :             }
    1199                 :            :         }
    1200                 :            :         else
    1201                 :            :         {
    1202                 :          0 :             pCaretXArray[i] = pCaretXArray[i+1] = 0;
    1203                 :            :         }
    1204                 :            : #ifdef GRLAYOUT_DEBUG
    1205                 :            :         fprintf(grLog(),"%d,%d-%d\t", nCharSlot, pCaretXArray[i], pCaretXArray[i+1]);
    1206                 :            : #endif
    1207                 :            :     }
    1208                 :            : #ifdef GRLAYOUT_DEBUG
    1209                 :            :     fprintf(grLog(),"\n");
    1210                 :            : #endif
    1211                 :          0 : }
    1212                 :            : 
    1213                 :            : // GetNextGlyphs returns a contiguous sequence of glyphs that can be
    1214                 :            : // rendered together. It should never return a dropped glyph.
    1215                 :            : // The glyph_slot returned should be the index of the next visible
    1216                 :            : // glyph after the last glyph returned by this call.
    1217                 :            : // The char_index array should be filled with the characters corresponding
    1218                 :            : // to each glyph returned.
    1219                 :            : // glyph_adv array should be a virtual width such that if successive
    1220                 :            : // glyphs returned by this method are added one after the other they
    1221                 :            : // have the correct spacing.
    1222                 :            : // The logic in this method must match that expected in MultiSalLayout which
    1223                 :            : // is used when glyph fallback is in operation.
    1224                 :          0 : int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out,
    1225                 :            :         ::Point & aPosOut, int &glyph_slot, sal_Int32 * glyph_adv, int *char_index) const
    1226                 :            : {
    1227                 :            :   // Sanity check on the slot index.
    1228         [ #  # ]:          0 :   if (glyph_slot >= signed(mvGlyphs.size()))
    1229                 :            :   {
    1230                 :          0 :     glyph_slot = mvGlyphs.size();
    1231                 :          0 :     return 0;
    1232                 :            :   }
    1233                 :            :   assert(glyph_slot >= 0);
    1234                 :            :   // Find the first glyph in the substring.
    1235   [ #  #  #  # ]:          0 :   for (; glyph_slot < signed(mvGlyphs.size()) &&
                 [ #  # ]
    1236 [ #  # ][ #  # ]:          0 :           ((mvGlyphs.begin() + glyph_slot)->mnGlyphIndex == GF_DROPPED);
                 [ #  # ]
           [ #  #  #  # ]
    1237                 :            :           ++glyph_slot) {};
    1238                 :            : 
    1239                 :            :   // Update the length
    1240                 :          0 :   const int nGlyphSlotEnd = minimum(size_t(glyph_slot + length), mvGlyphs.size());
    1241                 :            : 
    1242                 :            :   // We're all out of glyphs here.
    1243         [ #  # ]:          0 :   if (glyph_slot == nGlyphSlotEnd)
    1244                 :            :   {
    1245                 :          0 :     return 0;
    1246                 :            :   }
    1247                 :            : 
    1248                 :            :   // Find as many glyphs as we can which can be drawn in one go.
    1249 [ #  # ][ #  # ]:          0 :   Glyphs::const_iterator glyph_itr = mvGlyphs.begin() + glyph_slot;
    1250                 :          0 :   const int         glyph_slot_begin = glyph_slot;
    1251                 :          0 :   const int            initial_y_pos = glyph_itr->maLinearPos.Y();
    1252                 :            : 
    1253                 :            :   // Set the position to the position of the start glyph.
    1254                 :          0 :   ::Point aStartPos = glyph_itr->maLinearPos;
    1255                 :            :   //aPosOut = glyph_itr->maLinearPos;
    1256         [ #  # ]:          0 :   aPosOut = GetDrawPosition(aStartPos);
    1257                 :            : 
    1258                 :          0 :   for (;;)  // Forever
    1259                 :            :   {
    1260                 :            :      // last index of the range from glyph_to_chars does not include this glyph
    1261         [ #  # ]:          0 :      if (char_index)
    1262                 :            :      {
    1263         [ #  # ]:          0 :          if (glyph_slot >= (signed)mvGlyph2Char.size())
    1264                 :            :          {
    1265                 :          0 :             *char_index++ = mnMinCharPos + mvCharDxs.size();
    1266                 :            :          }
    1267                 :            :          else
    1268                 :            :          {
    1269                 :            :             assert(glyph_slot > -1);
    1270 [ #  # ][ #  # ]:          0 :             if (mvGlyph2Char[glyph_slot] == -1)
    1271                 :          0 :                 *char_index++ = mnMinCharPos + mvCharDxs.size();
    1272                 :            :             else
    1273         [ #  # ]:          0 :                 *char_index++ = mvGlyph2Char[glyph_slot];
    1274                 :            :          }
    1275                 :            :      }
    1276                 :            :      // Copy out this glyphs data.
    1277                 :          0 :      ++glyph_slot;
    1278                 :          0 :      *glyph_out++ = glyph_itr->mnGlyphIndex;
    1279                 :            : 
    1280                 :            :      // Find the actual advance - this must be correct if called from
    1281                 :            :      // MultiSalLayout::AdjustLayout which requests one glyph at a time.
    1282                 :          0 :      const long nGlyphAdvance = (glyph_slot == static_cast<int>(mvGlyphs.size()))?
    1283                 :          0 :           glyph_itr->mnNewWidth :
    1284 [ #  # ][ #  # ]:          0 :           ((glyph_itr+1)->maLinearPos.X() - glyph_itr->maLinearPos.X());
                 [ #  # ]
           [ #  #  #  # ]
                 [ #  # ]
    1285                 :            : 
    1286                 :            : #ifdef GRLAYOUT_DEBUG
    1287                 :            :     fprintf(grLog(),"GetNextGlyphs g%d gid%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n",
    1288                 :            :             glyph_slot - 1, glyph_itr->mnGlyphIndex,
    1289                 :            :             mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance,
    1290                 :            :             aPosOut.X(), aPosOut.Y());
    1291                 :            : #endif
    1292                 :            : 
    1293         [ #  # ]:          0 :      if (glyph_adv)  // If we are returning advance store it.
    1294                 :          0 :        *glyph_adv++ = nGlyphAdvance;
    1295                 :            :      else // Stop when next advance is unexpected.
    1296         [ #  # ]:          0 :        if (glyph_itr->mnOrigWidth != nGlyphAdvance)  break;
    1297                 :            : 
    1298                 :            :      // Have fetched all the glyphs we need to
    1299         [ #  # ]:          0 :      if (glyph_slot == nGlyphSlotEnd)
    1300                 :          0 :          break;
    1301                 :            : 
    1302                 :          0 :      ++glyph_itr;
    1303                 :            :      // Stop when next y position is unexpected.
    1304         [ #  # ]:          0 :      if (initial_y_pos != glyph_itr->maLinearPos.Y())
    1305                 :          0 :        break;
    1306                 :            : 
    1307                 :            :      // Stop if glyph dropped
    1308         [ #  # ]:          0 :      if (glyph_itr->mnGlyphIndex == GF_DROPPED)
    1309                 :          0 :        break;
    1310                 :            :   }
    1311                 :          0 :   int numGlyphs = glyph_slot - glyph_slot_begin;
    1312                 :            :   // move the next glyph_slot to a glyph that hasn't been dropped
    1313   [ #  #  #  # ]:          0 :   while (glyph_slot < static_cast<int>(mvGlyphs.size()) &&
                 [ #  # ]
    1314 [ #  # ][ #  # ]:          0 :          (mvGlyphs.begin() + glyph_slot)->mnGlyphIndex == GF_DROPPED)
                 [ #  # ]
           [ #  #  #  # ]
    1315                 :          0 :          ++glyph_slot;
    1316                 :          0 :   return numGlyphs;
    1317                 :            : }
    1318                 :            : 
    1319                 :          0 : void GraphiteLayout::MoveGlyph( int nGlyphIndex, long nNewPos )
    1320                 :            : {
    1321                 :            :     // TODO it might be better to actualy implement simplify properly, but this
    1322                 :            :     // needs to be done carefully so the glyph/char maps are maintained
    1323                 :            :     // If a glyph has been dropped then it wasn't returned by GetNextGlyphs, so
    1324                 :            :     // the index here may be wrong
    1325   [ #  #  #  # ]:          0 :     while ((mvGlyphs[nGlyphIndex].mnGlyphIndex == GF_DROPPED) &&
                 [ #  # ]
    1326                 :          0 :            (nGlyphIndex < (signed)mvGlyphs.size()))
    1327                 :            :     {
    1328                 :          0 :         nGlyphIndex++;
    1329                 :            :     }
    1330                 :          0 :     const long dx = nNewPos - mvGlyphs[nGlyphIndex].maLinearPos.X();
    1331                 :            : 
    1332         [ #  # ]:          0 :     if (dx == 0)  return;
    1333                 :            :     // GenericSalLayout only changes maLinearPos, mvCharDxs doesn't change
    1334                 :            : #ifdef GRLAYOUT_DEBUG
    1335                 :            :     fprintf(grLog(),"Move %d (%ld,%ld) c%d by %ld\n", nGlyphIndex, mvGlyphs[nGlyphIndex].maLinearPos.X(), nNewPos, mvGlyph2Char[nGlyphIndex], dx);
    1336                 :            : #endif
    1337         [ #  # ]:          0 :     for (size_t gi = nGlyphIndex; gi < mvGlyphs.size(); gi++)
    1338                 :            :     {
    1339                 :          0 :         mvGlyphs[gi].maLinearPos.X() += dx;
    1340                 :            :     }
    1341                 :            :     // width does need to be updated for correct fallback
    1342                 :          0 :     mnWidth += dx;
    1343                 :            : }
    1344                 :            : 
    1345                 :          0 : void GraphiteLayout::DropGlyph( int nGlyphIndex )
    1346                 :            : {
    1347         [ #  # ]:          0 :     if(nGlyphIndex >= signed(mvGlyphs.size()))
    1348                 :          0 :         return;
    1349                 :            : 
    1350                 :          0 :     GlyphItem & glyph = mvGlyphs[nGlyphIndex];
    1351                 :          0 :     glyph.mnGlyphIndex = GF_DROPPED;
    1352                 :            : #ifdef GRLAYOUT_DEBUG
    1353                 :            :     fprintf(grLog(),"Dropped %d\n", nGlyphIndex);
    1354                 :            : #endif
    1355                 :            : }
    1356                 :            : 
    1357                 :          0 : void GraphiteLayout::Simplify( bool isBaseLayout )
    1358                 :            : {
    1359         [ #  # ]:          0 :   const sal_GlyphId dropMarker = isBaseLayout ? GF_DROPPED : 0;
    1360                 :            : 
    1361                 :          0 :   Glyphs::iterator gi = mvGlyphs.begin();
    1362                 :            :   // TODO check whether we need to adjust positions here
    1363                 :            :   // MultiSalLayout seems to move the glyphs itself, so it may not be needed.
    1364                 :          0 :   long deltaX = 0;
    1365 [ #  # ][ #  # ]:          0 :   while (gi != mvGlyphs.end())
    1366                 :            :   {
    1367         [ #  # ]:          0 :       if (gi->mnGlyphIndex == dropMarker)
    1368                 :            :       {
    1369                 :          0 :         deltaX += gi->mnNewWidth;
    1370                 :          0 :         gi->mnNewWidth = 0;
    1371                 :            :       }
    1372                 :            :       else
    1373                 :            :       {
    1374                 :          0 :         deltaX = 0;
    1375                 :            :       }
    1376                 :          0 :       ++gi;
    1377                 :            :   }
    1378                 :            : #ifdef GRLAYOUT_DEBUG
    1379                 :            :   fprintf(grLog(),"Simplify base%d dx=%ld newW=%ld\n", isBaseLayout, deltaX, mnWidth - deltaX);
    1380                 :            : #endif
    1381                 :            :   // discard width from trailing dropped glyphs, but not those in the middle
    1382                 :          0 :   mnWidth -= deltaX;
    1383                 :          0 : }
    1384                 :            : 
    1385                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10