src/gui/text/qtextengine_mac.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qtextengine_p.h"
       
    43 
       
    44 QT_BEGIN_NAMESPACE
       
    45 
       
    46 // set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs
       
    47 // and no reordering.
       
    48 // also computes logClusters heuristically
       
    49 static void heuristicSetGlyphAttributes(const QChar *uc, int length, QGlyphLayout *glyphs, unsigned short *logClusters, int num_glyphs)
       
    50 {
       
    51     // ### zeroWidth and justification are missing here!!!!!
       
    52 
       
    53     Q_UNUSED(num_glyphs);
       
    54 
       
    55 //     qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item->num_glyphs);
       
    56 
       
    57     const bool symbolFont = false; // ####
       
    58     glyphs->attributes[0].mark = false;
       
    59     glyphs->attributes[0].clusterStart = true;
       
    60     glyphs->attributes[0].dontPrint = (!symbolFont && uc[0].unicode() == 0x00ad) || qIsControlChar(uc[0].unicode());
       
    61 
       
    62     int pos = 0;
       
    63     int lastCat = QChar::category(uc[0].unicode());
       
    64     for (int i = 1; i < length; ++i) {
       
    65         if (logClusters[i] == pos)
       
    66             // same glyph
       
    67             continue;
       
    68         ++pos;
       
    69         while (pos < logClusters[i]) {
       
    70             ++pos;
       
    71         }
       
    72         // hide soft-hyphens by default
       
    73         if ((!symbolFont && uc[i].unicode() == 0x00ad) || qIsControlChar(uc[i].unicode()))
       
    74             glyphs->attributes[pos].dontPrint = true;
       
    75         const QUnicodeTables::Properties *prop = QUnicodeTables::properties(uc[i].unicode());
       
    76         int cat = prop->category;
       
    77 
       
    78         // one gets an inter character justification point if the current char is not a non spacing mark.
       
    79         // as then the current char belongs to the last one and one gets a space justification point
       
    80         // after the space char.
       
    81         if (lastCat == QChar::Separator_Space)
       
    82             glyphs->attributes[pos-1].justification = HB_Space;
       
    83         else if (cat != QChar::Mark_NonSpacing)
       
    84             glyphs->attributes[pos-1].justification = HB_Character;
       
    85         else
       
    86             glyphs->attributes[pos-1].justification = HB_NoJustification;
       
    87 
       
    88         lastCat = cat;
       
    89     }
       
    90     pos = logClusters[length-1];
       
    91     if (lastCat == QChar::Separator_Space)
       
    92         glyphs->attributes[pos].justification = HB_Space;
       
    93     else
       
    94         glyphs->attributes[pos].justification = HB_Character;
       
    95 }
       
    96 
       
    97 struct QArabicProperties {
       
    98     unsigned char shape;
       
    99     unsigned char justification;
       
   100 };
       
   101 Q_DECLARE_TYPEINFO(QArabicProperties, Q_PRIMITIVE_TYPE);
       
   102 
       
   103 enum QArabicShape {
       
   104     XIsolated,
       
   105     XFinal,
       
   106     XInitial,
       
   107     XMedial,
       
   108     // intermediate state
       
   109     XCausing
       
   110 };
       
   111 
       
   112 
       
   113 // these groups correspond to the groups defined in the Unicode standard.
       
   114 // Some of these groups are equal with regards to both joining and line breaking behaviour,
       
   115 // and thus have the same enum value
       
   116 //
       
   117 // I'm not sure the mapping of syriac to arabic enums is correct with regards to justification, but as
       
   118 // I couldn't find any better document I'll hope for the best.
       
   119 enum ArabicGroup {
       
   120     // NonJoining
       
   121     ArabicNone,
       
   122     ArabicSpace,
       
   123     // Transparent
       
   124     Transparent,
       
   125     // Causing
       
   126     Center,
       
   127     Kashida,
       
   128 
       
   129     // Arabic
       
   130     // Dual
       
   131     Beh,
       
   132     Noon,
       
   133     Meem = Noon,
       
   134     Heh = Noon,
       
   135     KnottedHeh = Noon,
       
   136     HehGoal = Noon,
       
   137     SwashKaf = Noon,
       
   138     Yeh,
       
   139     Hah,
       
   140     Seen,
       
   141     Sad = Seen,
       
   142     Tah,
       
   143     Kaf = Tah,
       
   144     Gaf = Tah,
       
   145     Lam = Tah,
       
   146     Ain,
       
   147     Feh = Ain,
       
   148     Qaf = Ain,
       
   149     // Right
       
   150     Alef,
       
   151     Waw,
       
   152     Dal,
       
   153     TehMarbuta = Dal,
       
   154     Reh,
       
   155     HamzaOnHehGoal,
       
   156     YehWithTail = HamzaOnHehGoal,
       
   157     YehBarre = HamzaOnHehGoal,
       
   158 
       
   159     // Syriac
       
   160     // Dual
       
   161     Beth = Beh,
       
   162     Gamal = Ain,
       
   163     Heth = Noon,
       
   164     Teth = Hah,
       
   165     Yudh = Noon,
       
   166     Kaph = Noon,
       
   167     Lamadh = Lam,
       
   168     Mim = Noon,
       
   169     Nun = Noon,
       
   170     Semakh = Noon,
       
   171     FinalSemakh = Noon,
       
   172     SyriacE = Ain,
       
   173     Pe = Ain,
       
   174     ReversedPe = Hah,
       
   175     Qaph = Noon,
       
   176     Shin = Noon,
       
   177     Fe = Ain,
       
   178 
       
   179     // Right
       
   180     Alaph = Alef,
       
   181     Dalath = Dal,
       
   182     He = Dal,
       
   183     SyriacWaw = Waw,
       
   184     Zain = Alef,
       
   185     YudhHe = Waw,
       
   186     Sadhe = HamzaOnHehGoal,
       
   187     Taw = Dal,
       
   188 
       
   189     // Compiler bug? Otherwise ArabicGroupsEnd would be equal to Dal + 1.
       
   190     Dummy = HamzaOnHehGoal,
       
   191     ArabicGroupsEnd
       
   192 };
       
   193 
       
   194 static const unsigned char arabic_group[0x150] = {
       
   195     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   196     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   197     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   198     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   199 
       
   200     Transparent, Transparent, Transparent, Transparent,
       
   201     Transparent, Transparent, ArabicNone, ArabicNone,
       
   202     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   203     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   204 
       
   205     ArabicNone, ArabicNone, Alef, Alef,
       
   206     Waw, Alef, Yeh, Alef,
       
   207     Beh, TehMarbuta, Beh, Beh,
       
   208     Hah, Hah, Hah, Dal,
       
   209 
       
   210     Dal, Reh, Reh, Seen,
       
   211     Seen, Sad, Sad, Tah,
       
   212     Tah, Ain, Ain, ArabicNone,
       
   213     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   214 
       
   215     // 0x640
       
   216     Kashida, Feh, Qaf, Kaf,
       
   217     Lam, Meem, Noon, Heh,
       
   218     Waw, Yeh, Yeh, Transparent,
       
   219     Transparent, Transparent, Transparent, Transparent,
       
   220 
       
   221     Transparent, Transparent, Transparent, Transparent,
       
   222     Transparent, Transparent, Transparent, Transparent,
       
   223     Transparent, ArabicNone, ArabicNone, ArabicNone,
       
   224     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   225 
       
   226     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   227     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   228     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   229     ArabicNone, ArabicNone, Beh, Qaf,
       
   230 
       
   231     Transparent, Alef, Alef, Alef,
       
   232     ArabicNone, Alef, Waw, Waw,
       
   233     Yeh, Beh, Beh, Beh,
       
   234     Beh, Beh, Beh, Beh,
       
   235 
       
   236     // 0x680
       
   237     Beh, Hah, Hah, Hah,
       
   238     Hah, Hah, Hah, Hah,
       
   239     Dal, Dal, Dal, Dal,
       
   240     Dal, Dal, Dal, Dal,
       
   241 
       
   242     Dal, Reh, Reh, Reh,
       
   243     Reh, Reh, Reh, Reh,
       
   244     Reh, Reh, Seen, Seen,
       
   245     Seen, Sad, Sad, Tah,
       
   246 
       
   247     Ain, Feh, Feh, Feh,
       
   248     Feh, Feh, Feh, Qaf,
       
   249     Qaf, Gaf, SwashKaf, Gaf,
       
   250     Kaf, Kaf, Kaf, Gaf,
       
   251 
       
   252     Gaf, Gaf, Gaf, Gaf,
       
   253     Gaf, Lam, Lam, Lam,
       
   254     Lam, Noon, Noon, Noon,
       
   255     Noon, Noon, KnottedHeh, Hah,
       
   256 
       
   257     // 0x6c0
       
   258     TehMarbuta, HehGoal, HamzaOnHehGoal, HamzaOnHehGoal,
       
   259     Waw, Waw, Waw, Waw,
       
   260     Waw, Waw, Waw, Waw,
       
   261     Yeh, YehWithTail, Yeh, Waw,
       
   262 
       
   263     Yeh, Yeh, YehBarre, YehBarre,
       
   264     ArabicNone, TehMarbuta, Transparent, Transparent,
       
   265     Transparent, Transparent, Transparent, Transparent,
       
   266     Transparent, ArabicNone, ArabicNone, Transparent,
       
   267 
       
   268     Transparent, Transparent, Transparent, Transparent,
       
   269     Transparent, ArabicNone, ArabicNone, Transparent,
       
   270     Transparent, ArabicNone, Transparent, Transparent,
       
   271     Transparent, Transparent, Dal, Reh,
       
   272 
       
   273     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   274     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   275     ArabicNone, ArabicNone, Seen, Sad,
       
   276     Ain, ArabicNone, ArabicNone, KnottedHeh,
       
   277 
       
   278     // 0x700
       
   279     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   280     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   281     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   282     ArabicNone, ArabicNone, ArabicNone, ArabicNone,
       
   283 
       
   284     Alaph, Transparent, Beth, Gamal,
       
   285     Gamal, Dalath, Dalath, He,
       
   286     SyriacWaw, Zain, Heth, Teth,
       
   287     Teth, Yudh, YudhHe, Kaph,
       
   288 
       
   289     Lamadh, Mim, Nun, Semakh,
       
   290     FinalSemakh, SyriacE, Pe, ReversedPe,
       
   291     Sadhe, Qaph, Dalath, Shin,
       
   292     Taw, Beth, Gamal, Dalath,
       
   293 
       
   294     Transparent, Transparent, Transparent, Transparent,
       
   295     Transparent, Transparent, Transparent, Transparent,
       
   296     Transparent, Transparent, Transparent, Transparent,
       
   297     Transparent, Transparent, Transparent, Transparent,
       
   298 
       
   299     Transparent, Transparent, Transparent, Transparent,
       
   300     Transparent, Transparent, Transparent, Transparent,
       
   301     Transparent, Transparent, Transparent, ArabicNone,
       
   302     ArabicNone, Zain, Kaph, Fe,
       
   303 };
       
   304 
       
   305 static inline ArabicGroup arabicGroup(unsigned short uc)
       
   306 {
       
   307     if (uc >= 0x0600 && uc < 0x750)
       
   308         return (ArabicGroup) arabic_group[uc-0x600];
       
   309     else if (uc == 0x200d)
       
   310         return Center;
       
   311     else if (QChar::category(uc) == QChar::Separator_Space)
       
   312         return ArabicSpace;
       
   313     else
       
   314         return ArabicNone;
       
   315 }
       
   316 
       
   317 
       
   318 /*
       
   319    Arabic shaping obeys a number of rules according to the joining classes (see Unicode book, section on
       
   320    arabic).
       
   321 
       
   322    Each unicode char has a joining class (right, dual (left&right), center (joincausing) or transparent).
       
   323    transparent joining is not encoded in QChar::joining(), but applies to all combining marks and format marks.
       
   324 
       
   325    Right join-causing: dual + center
       
   326    Left join-causing: dual + right + center
       
   327 
       
   328    Rules are as follows (for a string already in visual order, as we have it here):
       
   329 
       
   330    R1 Transparent characters do not affect joining behaviour.
       
   331    R2 A right joining character, that has a right join-causing char on the right will get form XRight
       
   332    (R3 A left joining character, that has a left join-causing char on the left will get form XLeft)
       
   333    Note: the above rule is meaningless, as there are no pure left joining characters defined in Unicode
       
   334    R4 A dual joining character, that has a left join-causing char on the left and a right join-causing char on
       
   335              the right will get form XMedial
       
   336    R5  A dual joining character, that has a right join causing char on the right, and no left join causing char on the left
       
   337          will get form XRight
       
   338    R6 A dual joining character, that has a  left join causing char on the left, and no right join causing char on the right
       
   339          will get form XLeft
       
   340    R7 Otherwise the character will get form XIsolated
       
   341 
       
   342    Additionally we have to do the minimal ligature support for lam-alef ligatures:
       
   343 
       
   344    L1 Transparent characters do not affect ligature behaviour.
       
   345    L2 Any sequence of Alef(XRight) + Lam(XMedial) will form the ligature Alef.Lam(XLeft)
       
   346    L3 Any sequence of Alef(XRight) + Lam(XLeft) will form the ligature Alef.Lam(XIsolated)
       
   347 
       
   348    The state table below handles rules R1-R7.
       
   349 */
       
   350 
       
   351 enum Joining {
       
   352     JNone,
       
   353     JCausing,
       
   354     JDual,
       
   355     JRight,
       
   356     JTransparent
       
   357 };
       
   358 
       
   359 static const Joining joining_for_group[ArabicGroupsEnd] = {
       
   360     // NonJoining
       
   361     JNone, // ArabicNone
       
   362     JNone, // ArabicSpace
       
   363     // Transparent
       
   364     JTransparent, // Transparent
       
   365     // Causing
       
   366     JCausing, // Center
       
   367     JCausing, // Kashida
       
   368     // Dual
       
   369     JDual, // Beh
       
   370     JDual, // Noon
       
   371     JDual, // Yeh
       
   372     JDual, // Hah
       
   373     JDual, // Seen
       
   374     JDual, // Tah
       
   375     JDual, // Ain
       
   376     // Right
       
   377     JRight, // Alef
       
   378     JRight, // Waw
       
   379     JRight, // Dal
       
   380     JRight, // Reh
       
   381     JRight  // HamzaOnHehGoal
       
   382 };
       
   383 
       
   384 
       
   385 struct JoiningPair {
       
   386     QArabicShape form1;
       
   387     QArabicShape form2;
       
   388 };
       
   389 
       
   390 static const JoiningPair joining_table[5][4] =
       
   391 // None, Causing, Dual, Right
       
   392 {
       
   393     { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XInitial }, { XIsolated, XIsolated } }, // XIsolated
       
   394     { { XFinal, XIsolated }, { XFinal, XCausing }, { XFinal, XInitial }, { XFinal, XIsolated } }, // XFinal
       
   395     { { XIsolated, XIsolated }, { XInitial, XCausing }, { XInitial, XMedial }, { XInitial, XFinal } }, // XInitial
       
   396     { { XFinal, XIsolated }, { XMedial, XCausing }, { XMedial, XMedial }, { XMedial, XFinal } }, // XMedial
       
   397     { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XMedial }, { XIsolated, XFinal } }, // XCausing
       
   398 };
       
   399 
       
   400 
       
   401 /*
       
   402 According to http://www.microsoft.com/middleeast/Arabicdev/IE6/KBase.asp
       
   403 
       
   404 1. Find the priority of the connecting opportunities in each word
       
   405 2. Add expansion at the highest priority connection opportunity
       
   406 3. If more than one connection opportunity have the same highest value,
       
   407    use the opportunity closest to the end of the word.
       
   408 
       
   409 Following is a chart that provides the priority for connection
       
   410 opportunities and where expansion occurs. The character group names
       
   411 are those in table 6.6 of the UNICODE 2.0 book.
       
   412 
       
   413 
       
   414 PrioritY        Glyph                   Condition                                       Kashida Location
       
   415 
       
   416 Arabic_Kashida        User inserted Kashida   The user entered a Kashida in a position.       After the user
       
   417                 (Shift+j or Shift+[E with hat])    Thus, it is the highest priority to insert an   inserted kashida
       
   418                                         automatic kashida.
       
   419 
       
   420 Arabic_Seen        Seen, Sad               Connecting to the next character.               After the character.
       
   421                                         (Initial or medial form).
       
   422 
       
   423 Arabic_HaaDal        Teh Marbutah, Haa, Dal  Connecting to previous character.               Before the final form
       
   424                                                                                         of these characters.
       
   425 
       
   426 Arabic_Alef     Alef, Tah, Lam,         Connecting to previous character.               Before the final form
       
   427                 Kaf and Gaf                                                             of these characters.
       
   428 
       
   429 Arabic_BaRa     Reh, Yeh                Connected to medial Beh                         Before preceding medial Baa
       
   430 
       
   431 Arabic_Waw        Waw, Ain, Qaf, Feh      Connecting to previous character.               Before the final form of
       
   432                                                                                         these characters.
       
   433 
       
   434 Arabic_Normal   Other connecting        Connecting to previous character.               Before the final form
       
   435                 characters                                                              of these characters.
       
   436 
       
   437 
       
   438 
       
   439 This seems to imply that we have at most one kashida point per arabic word.
       
   440 
       
   441 */
       
   442 
       
   443 void qt_getArabicProperties(const unsigned short *chars, int len, QArabicProperties *properties)
       
   444 {
       
   445 //     qDebug("arabicSyriacOpenTypeShape: properties:");
       
   446     int lastPos = 0;
       
   447     int lastGroup = ArabicNone;
       
   448 
       
   449     ArabicGroup group = arabicGroup(chars[0]);
       
   450     Joining j = joining_for_group[group];
       
   451     QArabicShape shape = joining_table[XIsolated][j].form2;
       
   452     properties[0].justification = HB_NoJustification;
       
   453 
       
   454     for (int i = 1; i < len; ++i) {
       
   455         // #### fix handling for spaces and punktuation
       
   456         properties[i].justification = HB_NoJustification;
       
   457 
       
   458         group = arabicGroup(chars[i]);
       
   459         j = joining_for_group[group];
       
   460 
       
   461         if (j == JTransparent) {
       
   462             properties[i].shape = XIsolated;
       
   463             continue;
       
   464         }
       
   465 
       
   466         properties[lastPos].shape = joining_table[shape][j].form1;
       
   467         shape = joining_table[shape][j].form2;
       
   468 
       
   469         switch(lastGroup) {
       
   470         case Seen:
       
   471             if (properties[lastPos].shape == XInitial || properties[lastPos].shape == XMedial)
       
   472                 properties[i-1].justification = HB_Arabic_Seen;
       
   473             break;
       
   474         case Hah:
       
   475             if (properties[lastPos].shape == XFinal)
       
   476                 properties[lastPos-1].justification = HB_Arabic_HaaDal;
       
   477             break;
       
   478         case Alef:
       
   479             if (properties[lastPos].shape == XFinal)
       
   480                 properties[lastPos-1].justification = HB_Arabic_Alef;
       
   481             break;
       
   482         case Ain:
       
   483             if (properties[lastPos].shape == XFinal)
       
   484                 properties[lastPos-1].justification = HB_Arabic_Waw;
       
   485             break;
       
   486         case Noon:
       
   487             if (properties[lastPos].shape == XFinal)
       
   488                 properties[lastPos-1].justification = HB_Arabic_Normal;
       
   489             break;
       
   490         case ArabicNone:
       
   491             break;
       
   492 
       
   493         default:
       
   494             Q_ASSERT(false);
       
   495         }
       
   496 
       
   497         lastGroup = ArabicNone;
       
   498 
       
   499         switch(group) {
       
   500         case ArabicNone:
       
   501         case Transparent:
       
   502         // ### Center should probably be treated as transparent when it comes to justification.
       
   503         case Center:
       
   504             break;
       
   505         case ArabicSpace:
       
   506             properties[i].justification = HB_Arabic_Space;
       
   507             break;
       
   508         case Kashida:
       
   509             properties[i].justification = HB_Arabic_Kashida;
       
   510             break;
       
   511         case Seen:
       
   512             lastGroup = Seen;
       
   513             break;
       
   514 
       
   515         case Hah:
       
   516         case Dal:
       
   517             lastGroup = Hah;
       
   518             break;
       
   519 
       
   520         case Alef:
       
   521         case Tah:
       
   522             lastGroup = Alef;
       
   523             break;
       
   524 
       
   525         case Yeh:
       
   526         case Reh:
       
   527             if (properties[lastPos].shape == XMedial && arabicGroup(chars[lastPos]) == Beh)
       
   528                 properties[lastPos-1].justification = HB_Arabic_BaRa;
       
   529             break;
       
   530 
       
   531         case Ain:
       
   532         case Waw:
       
   533             lastGroup = Ain;
       
   534             break;
       
   535 
       
   536         case Noon:
       
   537         case Beh:
       
   538         case HamzaOnHehGoal:
       
   539             lastGroup = Noon;
       
   540             break;
       
   541         case ArabicGroupsEnd:
       
   542             Q_ASSERT(false);
       
   543         }
       
   544 
       
   545         lastPos = i;
       
   546     }
       
   547     properties[lastPos].shape = joining_table[shape][JNone].form1;
       
   548 
       
   549 
       
   550 //     for (int i = 0; i < len; ++i)
       
   551 //         qDebug("arabic properties(%d): uc=%x shape=%d, justification=%d", i, chars[i], properties[i].shape, properties[i].justification);
       
   552 }
       
   553 
       
   554 void QTextEngine::shapeTextMac(int item) const
       
   555 {
       
   556     QScriptItem &si = layoutData->items[item];
       
   557 
       
   558     si.glyph_data_offset = layoutData->used;
       
   559 
       
   560     QFontEngine *font = fontEngine(si, &si.ascent, &si.descent);
       
   561     if (font->type() != QFontEngine::Multi) {
       
   562         shapeTextWithHarfbuzz(item);
       
   563         return;
       
   564     }
       
   565     
       
   566 #ifndef QT_MAC_USE_COCOA
       
   567     QFontEngineMacMulti *fe = static_cast<QFontEngineMacMulti *>(font);
       
   568 #else
       
   569     QCoreTextFontEngineMulti *fe = static_cast<QCoreTextFontEngineMulti *>(font);
       
   570 #endif
       
   571     QTextEngine::ShaperFlags flags;
       
   572     if (si.analysis.bidiLevel % 2)
       
   573         flags |= RightToLeft;
       
   574     if (option.useDesignMetrics())
       
   575 	flags |= DesignMetrics;
       
   576 
       
   577     attributes(); // pre-initialize char attributes
       
   578 
       
   579     const int len = length(item);
       
   580     int num_glyphs = length(item);
       
   581     const QChar *str = layoutData->string.unicode() + si.position;
       
   582     ushort upperCased[256];
       
   583     if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
       
   584             || si.analysis.flags == QScriptAnalysis::Lowercase) {
       
   585         ushort *uc = upperCased;
       
   586         if (len > 256)
       
   587             uc = new ushort[len];
       
   588         for (int i = 0; i < len; ++i) {
       
   589             if(si.analysis.flags == QScriptAnalysis::Lowercase)
       
   590                 uc[i] = str[i].toLower().unicode();
       
   591             else
       
   592                 uc[i] = str[i].toUpper().unicode();
       
   593         }
       
   594         str = reinterpret_cast<const QChar *>(uc);
       
   595     }
       
   596 
       
   597     while (true) {
       
   598         ensureSpace(num_glyphs);
       
   599         num_glyphs = layoutData->glyphLayout.numGlyphs - layoutData->used;
       
   600 
       
   601         QGlyphLayout g = availableGlyphs(&si);
       
   602         g.numGlyphs = num_glyphs;
       
   603         unsigned short *log_clusters = logClusters(&si);
       
   604 
       
   605         if (fe->stringToCMap(str,
       
   606                              len,
       
   607                              &g,
       
   608                              &num_glyphs,
       
   609                              flags,
       
   610                              log_clusters,
       
   611                              attributes())) {
       
   612 
       
   613             heuristicSetGlyphAttributes(str, len, &g, log_clusters, num_glyphs);
       
   614             break;
       
   615         }
       
   616     }
       
   617 
       
   618     si.num_glyphs = num_glyphs;
       
   619 
       
   620     layoutData->used += si.num_glyphs;
       
   621 
       
   622     QGlyphLayout g = shapedGlyphs(&si);
       
   623 
       
   624     if (si.analysis.script == QUnicodeTables::Arabic) {
       
   625         QVarLengthArray<QArabicProperties> props(len + 2);
       
   626         QArabicProperties *properties = props.data();
       
   627         int f = si.position;
       
   628         int l = len;
       
   629         if (f > 0) {
       
   630             --f;
       
   631             ++l;
       
   632             ++properties;
       
   633         }
       
   634         if (f + l < layoutData->string.length()) {
       
   635             ++l;
       
   636         }
       
   637         qt_getArabicProperties((const unsigned short *)(layoutData->string.unicode()+f), l, props.data());
       
   638 
       
   639         unsigned short *log_clusters = logClusters(&si);
       
   640 
       
   641         for (int i = 0; i < len; ++i) {
       
   642             int gpos = log_clusters[i];
       
   643             g.attributes[gpos].justification = properties[i].justification;
       
   644         }
       
   645     }
       
   646 
       
   647     const ushort *uc = reinterpret_cast<const ushort *>(str);
       
   648 
       
   649     if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
       
   650          || si.analysis.flags == QScriptAnalysis::Lowercase)
       
   651         && uc != upperCased)
       
   652         delete [] uc;
       
   653 }
       
   654 
       
   655 QT_END_NAMESPACE