15569331642446be05292e3e1f8a51218827168cdclaireho/* 25569331642446be05292e3e1f8a51218827168cdclaireho * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 35569331642446be05292e3e1f8a51218827168cdclaireho * 45569331642446be05292e3e1f8a51218827168cdclaireho * This is part of HarfBuzz, an OpenType Layout engine library. 55569331642446be05292e3e1f8a51218827168cdclaireho * 65569331642446be05292e3e1f8a51218827168cdclaireho * Permission is hereby granted, without written agreement and without 75569331642446be05292e3e1f8a51218827168cdclaireho * license or royalty fees, to use, copy, modify, and distribute this 85569331642446be05292e3e1f8a51218827168cdclaireho * software and its documentation for any purpose, provided that the 95569331642446be05292e3e1f8a51218827168cdclaireho * above copyright notice and the following two paragraphs appear in 105569331642446be05292e3e1f8a51218827168cdclaireho * all copies of this software. 115569331642446be05292e3e1f8a51218827168cdclaireho * 125569331642446be05292e3e1f8a51218827168cdclaireho * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 135569331642446be05292e3e1f8a51218827168cdclaireho * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 145569331642446be05292e3e1f8a51218827168cdclaireho * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 155569331642446be05292e3e1f8a51218827168cdclaireho * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 165569331642446be05292e3e1f8a51218827168cdclaireho * DAMAGE. 175569331642446be05292e3e1f8a51218827168cdclaireho * 185569331642446be05292e3e1f8a51218827168cdclaireho * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 195569331642446be05292e3e1f8a51218827168cdclaireho * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 205569331642446be05292e3e1f8a51218827168cdclaireho * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 215569331642446be05292e3e1f8a51218827168cdclaireho * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 225569331642446be05292e3e1f8a51218827168cdclaireho * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 235569331642446be05292e3e1f8a51218827168cdclaireho */ 245569331642446be05292e3e1f8a51218827168cdclaireho 255569331642446be05292e3e1f8a51218827168cdclaireho#include "harfbuzz-shaper.h" 265569331642446be05292e3e1f8a51218827168cdclaireho#include "harfbuzz-shaper-private.h" 275569331642446be05292e3e1f8a51218827168cdclaireho 285569331642446be05292e3e1f8a51218827168cdclaireho#include <assert.h> 295569331642446be05292e3e1f8a51218827168cdclaireho 305569331642446be05292e3e1f8a51218827168cdclaireho/* 315569331642446be05292e3e1f8a51218827168cdclaireho// Hangul is a syllable based script. Unicode reserves a large range 325569331642446be05292e3e1f8a51218827168cdclaireho// for precomposed hangul, where syllables are already precomposed to 335569331642446be05292e3e1f8a51218827168cdclaireho// their final glyph shape. In addition, a so called jamo range is 345569331642446be05292e3e1f8a51218827168cdclaireho// defined, that can be used to express old Hangul. Modern hangul 355569331642446be05292e3e1f8a51218827168cdclaireho// syllables can also be expressed as jamo, and should be composed 365569331642446be05292e3e1f8a51218827168cdclaireho// into syllables. The operation is rather simple and mathematical. 375569331642446be05292e3e1f8a51218827168cdclaireho 385569331642446be05292e3e1f8a51218827168cdclaireho// Every hangul jamo is classified as being either a Leading consonant 395569331642446be05292e3e1f8a51218827168cdclaireho// (L), and intermediat Vowel (V) or a trailing consonant (T). Modern 405569331642446be05292e3e1f8a51218827168cdclaireho// hangul syllables (the ones in the precomposed area can be of type 415569331642446be05292e3e1f8a51218827168cdclaireho// LV or LVT. 425569331642446be05292e3e1f8a51218827168cdclaireho// 435569331642446be05292e3e1f8a51218827168cdclaireho// Syllable breaks do _not_ occur between: 445569331642446be05292e3e1f8a51218827168cdclaireho// 455569331642446be05292e3e1f8a51218827168cdclaireho// L L, V or precomposed 465569331642446be05292e3e1f8a51218827168cdclaireho// V, LV V, T 475569331642446be05292e3e1f8a51218827168cdclaireho// LVT, T T 485569331642446be05292e3e1f8a51218827168cdclaireho// 495569331642446be05292e3e1f8a51218827168cdclaireho// A standard syllable is of the form L+V+T*. The above rules allow 505569331642446be05292e3e1f8a51218827168cdclaireho// nonstandard syllables L*V*T*. To transform them into standard 515569331642446be05292e3e1f8a51218827168cdclaireho// syllables fill characters L_f and V_f can be inserted. 525569331642446be05292e3e1f8a51218827168cdclaireho*/ 535569331642446be05292e3e1f8a51218827168cdclaireho 545569331642446be05292e3e1f8a51218827168cdclairehoenum { 555569331642446be05292e3e1f8a51218827168cdclaireho Hangul_SBase = 0xac00, 565569331642446be05292e3e1f8a51218827168cdclaireho Hangul_LBase = 0x1100, 575569331642446be05292e3e1f8a51218827168cdclaireho Hangul_VBase = 0x1161, 585569331642446be05292e3e1f8a51218827168cdclaireho Hangul_TBase = 0x11a7, 595569331642446be05292e3e1f8a51218827168cdclaireho Hangul_SCount = 11172, 605569331642446be05292e3e1f8a51218827168cdclaireho Hangul_LCount = 19, 615569331642446be05292e3e1f8a51218827168cdclaireho Hangul_VCount = 21, 625569331642446be05292e3e1f8a51218827168cdclaireho Hangul_TCount = 28, 635569331642446be05292e3e1f8a51218827168cdclaireho Hangul_NCount = 21*28 645569331642446be05292e3e1f8a51218827168cdclaireho}; 655569331642446be05292e3e1f8a51218827168cdclaireho 665569331642446be05292e3e1f8a51218827168cdclaireho#define hangul_isPrecomposed(uc) \ 675569331642446be05292e3e1f8a51218827168cdclaireho (uc >= Hangul_SBase && uc < Hangul_SBase + Hangul_SCount) 685569331642446be05292e3e1f8a51218827168cdclaireho 695569331642446be05292e3e1f8a51218827168cdclaireho#define hangul_isLV(uc) \ 705569331642446be05292e3e1f8a51218827168cdclaireho ((uc - Hangul_SBase) % Hangul_TCount == 0) 715569331642446be05292e3e1f8a51218827168cdclaireho 725569331642446be05292e3e1f8a51218827168cdclairehotypedef enum { 735569331642446be05292e3e1f8a51218827168cdclaireho L, 745569331642446be05292e3e1f8a51218827168cdclaireho V, 755569331642446be05292e3e1f8a51218827168cdclaireho T, 765569331642446be05292e3e1f8a51218827168cdclaireho LV, 775569331642446be05292e3e1f8a51218827168cdclaireho LVT, 785569331642446be05292e3e1f8a51218827168cdclaireho X 795569331642446be05292e3e1f8a51218827168cdclaireho} HangulType; 805569331642446be05292e3e1f8a51218827168cdclaireho 815569331642446be05292e3e1f8a51218827168cdclairehostatic HangulType hangul_type(unsigned short uc) { 825569331642446be05292e3e1f8a51218827168cdclaireho if (uc > Hangul_SBase && uc < Hangul_SBase + Hangul_SCount) 835569331642446be05292e3e1f8a51218827168cdclaireho return hangul_isLV(uc) ? LV : LVT; 845569331642446be05292e3e1f8a51218827168cdclaireho if (uc < Hangul_LBase || uc > 0x11ff) 855569331642446be05292e3e1f8a51218827168cdclaireho return X; 865569331642446be05292e3e1f8a51218827168cdclaireho if (uc < Hangul_VBase) 875569331642446be05292e3e1f8a51218827168cdclaireho return L; 885569331642446be05292e3e1f8a51218827168cdclaireho if (uc < Hangul_TBase) 895569331642446be05292e3e1f8a51218827168cdclaireho return V; 905569331642446be05292e3e1f8a51218827168cdclaireho return T; 915569331642446be05292e3e1f8a51218827168cdclaireho} 925569331642446be05292e3e1f8a51218827168cdclaireho 935569331642446be05292e3e1f8a51218827168cdclairehostatic int hangul_nextSyllableBoundary(const HB_UChar16 *s, int start, int end) 945569331642446be05292e3e1f8a51218827168cdclaireho{ 955569331642446be05292e3e1f8a51218827168cdclaireho const HB_UChar16 *uc = s + start; 965569331642446be05292e3e1f8a51218827168cdclaireho 975569331642446be05292e3e1f8a51218827168cdclaireho HangulType state = hangul_type(*uc); 985569331642446be05292e3e1f8a51218827168cdclaireho int pos = 1; 995569331642446be05292e3e1f8a51218827168cdclaireho 1005569331642446be05292e3e1f8a51218827168cdclaireho while (pos < end - start) { 1015569331642446be05292e3e1f8a51218827168cdclaireho HangulType newState = hangul_type(uc[pos]); 1025569331642446be05292e3e1f8a51218827168cdclaireho switch(newState) { 1035569331642446be05292e3e1f8a51218827168cdclaireho case X: 1045569331642446be05292e3e1f8a51218827168cdclaireho goto finish; 1055569331642446be05292e3e1f8a51218827168cdclaireho case L: 1065569331642446be05292e3e1f8a51218827168cdclaireho case V: 1075569331642446be05292e3e1f8a51218827168cdclaireho case T: 1085569331642446be05292e3e1f8a51218827168cdclaireho if (state > newState) 1095569331642446be05292e3e1f8a51218827168cdclaireho goto finish; 1105569331642446be05292e3e1f8a51218827168cdclaireho state = newState; 1115569331642446be05292e3e1f8a51218827168cdclaireho break; 1125569331642446be05292e3e1f8a51218827168cdclaireho case LV: 1135569331642446be05292e3e1f8a51218827168cdclaireho if (state > L) 1145569331642446be05292e3e1f8a51218827168cdclaireho goto finish; 1155569331642446be05292e3e1f8a51218827168cdclaireho state = V; 1165569331642446be05292e3e1f8a51218827168cdclaireho break; 1175569331642446be05292e3e1f8a51218827168cdclaireho case LVT: 1185569331642446be05292e3e1f8a51218827168cdclaireho if (state > L) 1195569331642446be05292e3e1f8a51218827168cdclaireho goto finish; 1205569331642446be05292e3e1f8a51218827168cdclaireho state = T; 1215569331642446be05292e3e1f8a51218827168cdclaireho } 1225569331642446be05292e3e1f8a51218827168cdclaireho ++pos; 1235569331642446be05292e3e1f8a51218827168cdclaireho } 1245569331642446be05292e3e1f8a51218827168cdclaireho 1255569331642446be05292e3e1f8a51218827168cdclaireho finish: 1265569331642446be05292e3e1f8a51218827168cdclaireho return start+pos; 1275569331642446be05292e3e1f8a51218827168cdclaireho} 1285569331642446be05292e3e1f8a51218827168cdclaireho 1295569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE 1305569331642446be05292e3e1f8a51218827168cdclairehostatic const HB_OpenTypeFeature hangul_features [] = { 1315569331642446be05292e3e1f8a51218827168cdclaireho { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, 1325569331642446be05292e3e1f8a51218827168cdclaireho { HB_MAKE_TAG('l', 'j', 'm', 'o'), CcmpProperty }, 13357e6107a9d66a9a97b146def0ef38c010f954be6claireho { HB_MAKE_TAG('v', 'j', 'm', 'o'), CcmpProperty }, 1345569331642446be05292e3e1f8a51218827168cdclaireho { HB_MAKE_TAG('t', 'j', 'm', 'o'), CcmpProperty }, 1355569331642446be05292e3e1f8a51218827168cdclaireho { 0, 0 } 1365569331642446be05292e3e1f8a51218827168cdclaireho}; 1375569331642446be05292e3e1f8a51218827168cdclaireho#endif 1385569331642446be05292e3e1f8a51218827168cdclaireho 1395569331642446be05292e3e1f8a51218827168cdclairehostatic HB_Bool hangul_shape_syllable(HB_ShaperItem *item, HB_Bool openType) 1405569331642446be05292e3e1f8a51218827168cdclaireho{ 1415569331642446be05292e3e1f8a51218827168cdclaireho const HB_UChar16 *ch = item->string + item->item.pos; 1425569331642446be05292e3e1f8a51218827168cdclaireho int len = item->item.length; 1435569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE 1445569331642446be05292e3e1f8a51218827168cdclaireho const int availableGlyphs = item->num_glyphs; 1455569331642446be05292e3e1f8a51218827168cdclaireho#endif 1465569331642446be05292e3e1f8a51218827168cdclaireho 1475569331642446be05292e3e1f8a51218827168cdclaireho int i; 1485569331642446be05292e3e1f8a51218827168cdclaireho HB_UChar16 composed = 0; 1495569331642446be05292e3e1f8a51218827168cdclaireho /* see if we can compose the syllable into a modern hangul */ 1505569331642446be05292e3e1f8a51218827168cdclaireho if (item->item.length == 2) { 1515569331642446be05292e3e1f8a51218827168cdclaireho int LIndex = ch[0] - Hangul_LBase; 1525569331642446be05292e3e1f8a51218827168cdclaireho int VIndex = ch[1] - Hangul_VBase; 1535569331642446be05292e3e1f8a51218827168cdclaireho if (LIndex >= 0 && LIndex < Hangul_LCount && 1545569331642446be05292e3e1f8a51218827168cdclaireho VIndex >= 0 && VIndex < Hangul_VCount) 1555569331642446be05292e3e1f8a51218827168cdclaireho composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + Hangul_SBase; 1565569331642446be05292e3e1f8a51218827168cdclaireho } else if (item->item.length == 3) { 1575569331642446be05292e3e1f8a51218827168cdclaireho int LIndex = ch[0] - Hangul_LBase; 1585569331642446be05292e3e1f8a51218827168cdclaireho int VIndex = ch[1] - Hangul_VBase; 1595569331642446be05292e3e1f8a51218827168cdclaireho int TIndex = ch[2] - Hangul_TBase; 1605569331642446be05292e3e1f8a51218827168cdclaireho if (LIndex >= 0 && LIndex < Hangul_LCount && 1615569331642446be05292e3e1f8a51218827168cdclaireho VIndex >= 0 && VIndex < Hangul_VCount && 1625569331642446be05292e3e1f8a51218827168cdclaireho TIndex >= 0 && TIndex < Hangul_TCount) 1635569331642446be05292e3e1f8a51218827168cdclaireho composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + TIndex + Hangul_SBase; 1645569331642446be05292e3e1f8a51218827168cdclaireho } 1655569331642446be05292e3e1f8a51218827168cdclaireho 1665569331642446be05292e3e1f8a51218827168cdclaireho 1675569331642446be05292e3e1f8a51218827168cdclaireho 1685569331642446be05292e3e1f8a51218827168cdclaireho /* if we have a modern hangul use the composed form */ 1695569331642446be05292e3e1f8a51218827168cdclaireho if (composed) { 1705569331642446be05292e3e1f8a51218827168cdclaireho ch = &composed; 1715569331642446be05292e3e1f8a51218827168cdclaireho len = 1; 1725569331642446be05292e3e1f8a51218827168cdclaireho } 1735569331642446be05292e3e1f8a51218827168cdclaireho 1745569331642446be05292e3e1f8a51218827168cdclaireho if (!item->font->klass->convertStringToGlyphIndices(item->font, 1755569331642446be05292e3e1f8a51218827168cdclaireho ch, len, 1765569331642446be05292e3e1f8a51218827168cdclaireho item->glyphs, &item->num_glyphs, 1775569331642446be05292e3e1f8a51218827168cdclaireho item->item.bidiLevel % 2)) 1785569331642446be05292e3e1f8a51218827168cdclaireho return FALSE; 1795569331642446be05292e3e1f8a51218827168cdclaireho for (i = 0; i < len; i++) { 1805569331642446be05292e3e1f8a51218827168cdclaireho item->attributes[i].mark = FALSE; 1815569331642446be05292e3e1f8a51218827168cdclaireho item->attributes[i].clusterStart = FALSE; 1825569331642446be05292e3e1f8a51218827168cdclaireho item->attributes[i].justification = 0; 1835569331642446be05292e3e1f8a51218827168cdclaireho item->attributes[i].zeroWidth = FALSE; 1845569331642446be05292e3e1f8a51218827168cdclaireho /*IDEBUG(" %d: %4x", i, ch[i].unicode()); */ 1855569331642446be05292e3e1f8a51218827168cdclaireho } 1865569331642446be05292e3e1f8a51218827168cdclaireho 1875569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE 1885569331642446be05292e3e1f8a51218827168cdclaireho if (!composed && openType) { 1895569331642446be05292e3e1f8a51218827168cdclaireho HB_Bool positioned; 1905569331642446be05292e3e1f8a51218827168cdclaireho 1915569331642446be05292e3e1f8a51218827168cdclaireho HB_STACKARRAY(unsigned short, logClusters, len); 1925569331642446be05292e3e1f8a51218827168cdclaireho for (i = 0; i < len; ++i) 1935569331642446be05292e3e1f8a51218827168cdclaireho logClusters[i] = i; 1945569331642446be05292e3e1f8a51218827168cdclaireho item->log_clusters = logClusters; 1955569331642446be05292e3e1f8a51218827168cdclaireho 1965569331642446be05292e3e1f8a51218827168cdclaireho HB_OpenTypeShape(item, /*properties*/0); 1975569331642446be05292e3e1f8a51218827168cdclaireho 1985569331642446be05292e3e1f8a51218827168cdclaireho positioned = HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE); 1995569331642446be05292e3e1f8a51218827168cdclaireho 2005569331642446be05292e3e1f8a51218827168cdclaireho HB_FREE_STACKARRAY(logClusters); 2015569331642446be05292e3e1f8a51218827168cdclaireho 2025569331642446be05292e3e1f8a51218827168cdclaireho if (!positioned) 2035569331642446be05292e3e1f8a51218827168cdclaireho return FALSE; 2045569331642446be05292e3e1f8a51218827168cdclaireho } else { 2055569331642446be05292e3e1f8a51218827168cdclaireho HB_HeuristicPosition(item); 2065569331642446be05292e3e1f8a51218827168cdclaireho } 2075569331642446be05292e3e1f8a51218827168cdclaireho#endif 2085569331642446be05292e3e1f8a51218827168cdclaireho 2095569331642446be05292e3e1f8a51218827168cdclaireho item->attributes[0].clusterStart = TRUE; 2105569331642446be05292e3e1f8a51218827168cdclaireho return TRUE; 2115569331642446be05292e3e1f8a51218827168cdclaireho} 2125569331642446be05292e3e1f8a51218827168cdclaireho 2135569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_HangulShape(HB_ShaperItem *item) 2145569331642446be05292e3e1f8a51218827168cdclaireho{ 2155569331642446be05292e3e1f8a51218827168cdclaireho const HB_UChar16 *uc = item->string + item->item.pos; 2165569331642446be05292e3e1f8a51218827168cdclaireho HB_Bool allPrecomposed = TRUE; 2175569331642446be05292e3e1f8a51218827168cdclaireho int i; 2185569331642446be05292e3e1f8a51218827168cdclaireho 2195569331642446be05292e3e1f8a51218827168cdclaireho assert(item->item.script == HB_Script_Hangul); 2205569331642446be05292e3e1f8a51218827168cdclaireho 2215569331642446be05292e3e1f8a51218827168cdclaireho for (i = 0; i < (int)item->item.length; ++i) { 2225569331642446be05292e3e1f8a51218827168cdclaireho if (!hangul_isPrecomposed(uc[i])) { 2235569331642446be05292e3e1f8a51218827168cdclaireho allPrecomposed = FALSE; 2245569331642446be05292e3e1f8a51218827168cdclaireho break; 2255569331642446be05292e3e1f8a51218827168cdclaireho } 2265569331642446be05292e3e1f8a51218827168cdclaireho } 2275569331642446be05292e3e1f8a51218827168cdclaireho 2285569331642446be05292e3e1f8a51218827168cdclaireho if (!allPrecomposed) { 2295569331642446be05292e3e1f8a51218827168cdclaireho HB_Bool openType = FALSE; 2305569331642446be05292e3e1f8a51218827168cdclaireho unsigned short *logClusters = item->log_clusters; 2315569331642446be05292e3e1f8a51218827168cdclaireho HB_ShaperItem syllable; 2325569331642446be05292e3e1f8a51218827168cdclaireho int first_glyph = 0; 2335569331642446be05292e3e1f8a51218827168cdclaireho int sstart = item->item.pos; 2345569331642446be05292e3e1f8a51218827168cdclaireho int end = sstart + item->item.length; 2355569331642446be05292e3e1f8a51218827168cdclaireho 2365569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE 2375569331642446be05292e3e1f8a51218827168cdclaireho openType = HB_SelectScript(item, hangul_features); 2385569331642446be05292e3e1f8a51218827168cdclaireho#endif 2395569331642446be05292e3e1f8a51218827168cdclaireho syllable = *item; 2405569331642446be05292e3e1f8a51218827168cdclaireho 2415569331642446be05292e3e1f8a51218827168cdclaireho while (sstart < end) { 2425569331642446be05292e3e1f8a51218827168cdclaireho int send = hangul_nextSyllableBoundary(item->string, sstart, end); 2435569331642446be05292e3e1f8a51218827168cdclaireho 2445569331642446be05292e3e1f8a51218827168cdclaireho syllable.item.pos = sstart; 2455569331642446be05292e3e1f8a51218827168cdclaireho syllable.item.length = send-sstart; 2465569331642446be05292e3e1f8a51218827168cdclaireho syllable.glyphs = item->glyphs + first_glyph; 2475569331642446be05292e3e1f8a51218827168cdclaireho syllable.attributes = item->attributes + first_glyph; 2485569331642446be05292e3e1f8a51218827168cdclaireho syllable.offsets = item->offsets + first_glyph; 2495569331642446be05292e3e1f8a51218827168cdclaireho syllable.advances = item->advances + first_glyph; 2505569331642446be05292e3e1f8a51218827168cdclaireho syllable.num_glyphs = item->num_glyphs - first_glyph; 2515569331642446be05292e3e1f8a51218827168cdclaireho if (!hangul_shape_syllable(&syllable, openType)) { 2525569331642446be05292e3e1f8a51218827168cdclaireho item->num_glyphs += syllable.num_glyphs; 2535569331642446be05292e3e1f8a51218827168cdclaireho return FALSE; 2545569331642446be05292e3e1f8a51218827168cdclaireho } 2555569331642446be05292e3e1f8a51218827168cdclaireho /* fix logcluster array */ 2565569331642446be05292e3e1f8a51218827168cdclaireho for (i = sstart; i < send; ++i) 2575569331642446be05292e3e1f8a51218827168cdclaireho logClusters[i-item->item.pos] = first_glyph; 2585569331642446be05292e3e1f8a51218827168cdclaireho sstart = send; 2595569331642446be05292e3e1f8a51218827168cdclaireho first_glyph += syllable.num_glyphs; 2605569331642446be05292e3e1f8a51218827168cdclaireho } 2615569331642446be05292e3e1f8a51218827168cdclaireho item->num_glyphs = first_glyph; 2625569331642446be05292e3e1f8a51218827168cdclaireho return TRUE; 2635569331642446be05292e3e1f8a51218827168cdclaireho } 2645569331642446be05292e3e1f8a51218827168cdclaireho 2655569331642446be05292e3e1f8a51218827168cdclaireho return HB_BasicShape(item); 2665569331642446be05292e3e1f8a51218827168cdclaireho} 2675569331642446be05292e3e1f8a51218827168cdclaireho 2685569331642446be05292e3e1f8a51218827168cdclaireho 269