HB_Bool HB_HangulShape(HB_ShaperItem *item) { const HB_UChar16 *uc = item->string + item->item.pos; HB_Bool allPrecomposed = TRUE; int i; assert(item->item.script == HB_Script_Hangul); for (i = 0; i < (int)item->item.length; ++i) { if (!hangul_isPrecomposed(uc[i])) { allPrecomposed = FALSE; break; } } if (!allPrecomposed) { HB_Bool openType = FALSE; unsigned short *logClusters = item->log_clusters; HB_ShaperItem syllable; int first_glyph = 0; int sstart = item->item.pos; int end = sstart + item->item.length; #ifndef NO_OPENTYPE openType = HB_SelectScript(item, hangul_features); #endif syllable = *item; while (sstart < end) { int send = hangul_nextSyllableBoundary(item->string, sstart, end); syllable.item.pos = sstart; syllable.item.length = send-sstart; syllable.glyphs = item->glyphs + first_glyph; syllable.attributes = item->attributes + first_glyph; syllable.offsets = item->offsets + first_glyph; syllable.advances = item->advances + first_glyph; syllable.num_glyphs = item->num_glyphs - first_glyph; if (!hangul_shape_syllable(&syllable, openType)) { item->num_glyphs += syllable.num_glyphs; return FALSE; } /* fix logcluster array */ for (i = sstart; i < send; ++i) logClusters[i-item->item.pos] = first_glyph; sstart = send; first_glyph += syllable.num_glyphs; } item->num_glyphs = first_glyph; return TRUE; } return HB_BasicShape(item); }
/* * convert to the correct display level of THAI vowels and marks. */ static HB_Bool HB_ThaiConvertStringToGlyphIndices (HB_ShaperItem *item) { char s[128]; char *cstr = s; const HB_UChar16 *string = item->string + item->item.pos; const hb_uint32 len = item->item.length; unsigned short *logClusters = item->log_clusters; hb_uint32 i = 0, slen = 0; if (!init_libthai()) return HB_BasicShape (item); if (len >= 128) cstr = (char *)malloc(len*sizeof(char) + 1); if (!cstr) return HB_BasicShape (item); to_tis620(string, len, cstr); /* Get font type */ static ThaiFontType font_type; static HB_Font itemFont; if (itemFont != item->font) { font_type = getThaiFontType (item); itemFont = item->font; } /* allocate temporary glyphs buffers */ HB_STACKARRAY (HB_UChar16, glyphString, (item->item.length * 2)); while (i < item->item.length) { struct thcell_t tis_cell; unsigned char rglyphs[4]; int cell_length; int lgn = 0; HB_Bool haveSaraAm = false; cell_length = th_next_cell ((const unsigned char *)cstr + i, len - i, &tis_cell, true); /* !item->fixedPitch); */ haveSaraAm = (cstr[i + cell_length - 1] == (char)0xd3); /* set shaper item's log_clusters */ logClusters[i] = slen; for (int j = 1; j < cell_length; j++) { logClusters[i + j] = logClusters[i]; } /* Find Logical Glyphs by font type */ switch (font_type) { case TIS: lgn = th_render_cell_tis (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break; case WIN: lgn = th_render_cell_mac (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break; case MAC: lgn = th_render_cell_win (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break; } /* Add glyphs to glyphs string and setting some attributes */ for (int lgi = 0; lgi < lgn; lgi++) { if ( rglyphs[lgi] == 0xdd/*TH_BLANK_BASE_GLYPH*/ ) { glyphString[slen++] = C_DOTTED_CIRCLE; } else if ((unsigned char)cstr[i] == (unsigned char)~0) { // The only glyphs that should be passed to this function that cannot be mapped to // tis620 are the ones of type Inherited class. Pass these glyphs untouched. glyphString[slen++] = string[i]; if (string[i] == 0x200D || string[i] == 0x200C) { // Check that we do not run out of bounds when setting item->attributes. If we do // run out of bounds then this function will return false, the necessary amount of // memory is reallocated, and this function will then be called again. if (slen <= item->num_glyphs) item->attributes[slen-1].dontPrint = true; // Hide ZWJ and ZWNJ characters } } else { glyphString[slen++] = (HB_UChar16) thai_get_glyph_index (font_type, rglyphs[lgi]); } } /* Special case to handle U+0E33 (SARA AM, āļģ): SARA AM is normally written at the end of a * word with a base character and an optional top character before it. For example, U+0E0B * (base), U+0E49 (top), U+0E33 (SARA AM). The sequence should be converted to 4 glyphs: * base, hilo (the little circle in the top left part of SARA AM, NIKHAHIT), top, then the * right part of SARA AM (SARA AA). * * The painting process finds out the starting glyph and ending glyph of a character * sequence by checking the logClusters array. In this case, logClusters array should * ideally be [ 0, 1, 3 ] so that glyphsStart = 0 and glyphsEnd = 3 (slen - 1) to paint out * all the glyphs generated. * * A special case in this special case is when we have no base character. When an isolated * SARA AM is processed (cell_length = 1), libthai will produce 3 glyphs: dotted circle * (indicates that the base is empty), NIKHAHIT then SARA AA. If logClusters[0] = 1, it will * paint from the second glyph in the glyphs array. So in this case logClusters[0] should * point to the first glyph it produces, aka. the dotted circle. */ if (haveSaraAm) { logClusters[i + cell_length - 1] = cell_length == 1 ? slen - 3 : slen - 1; if (tis_cell.top != 0) { if (cell_length > 1) { /* set the logClusters[top character] to slen - 2 as it points to the second to * lastglyph (slen - 2) */ logClusters[i + cell_length - 2] = slen - 2; } } /* check for overflow */ if (logClusters[i + cell_length - 1] > slen) logClusters[i + cell_length - 1] = 0; } i += cell_length; } glyphString[slen] = (HB_UChar16) '\0'; /* for check, should reallocate space or not */ HB_Bool spaceOK = (item->num_glyphs >= slen); /* Convert to Glyph indices */ HB_Bool haveGlyphs = item->font->klass->convertStringToGlyphIndices ( item->font, glyphString, slen, item->glyphs, &item->num_glyphs, item->shaperFlags); HB_FREE_STACKARRAY (glyphString); if (len >= 128) free(cstr); return (haveGlyphs && spaceOK); }
/* * convert to the correct display level of THAI vowels and marks. */ static HB_Bool HB_ThaiConvertStringToGlyphIndices (HB_ShaperItem *item) { char s[128]; char *cstr = s; const HB_UChar16 *string = item->string + item->item.pos; const hb_uint32 len = item->item.length; unsigned short *logClusters = item->log_clusters; hb_uint32 i = 0, slen = 0; if (!init_libthai()) return HB_BasicShape (item); if (len >= 128) cstr = (char *)malloc(len*sizeof(char) + 1); if (!cstr) return HB_BasicShape (item); to_tis620(string, len, cstr); /* Get font type */ static ThaiFontType font_type; static HB_Font itemFont; if (itemFont != item->font) { font_type = getThaiFontType (item); itemFont = item->font; } /* allocate temporary glyphs buffers */ HB_STACKARRAY (HB_UChar16, glyphString, (item->item.length * 2)); while (i < item->item.length) { struct thcell_t tis_cell; unsigned char rglyphs[4]; int cell_length; int lgn = 0; HB_Bool haveSaraAm = false; cell_length = th_next_cell ((const unsigned char *)cstr + i, len - i, &tis_cell, true); /* !item->fixedPitch); */ haveSaraAm = (cstr[i + cell_length - 1] == (char)0xd3); /* set shaper item's log_clusters */ logClusters[i] = slen; for (int j = 1; j < cell_length; j++) { logClusters[i + j] = logClusters[i]; } /* Find Logical Glyphs by font type */ switch (font_type) { case TIS: lgn = th_render_cell_tis (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break; case WIN: lgn = th_render_cell_mac (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break; case MAC: lgn = th_render_cell_win (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break; } /* Add glyphs to glyphs string and setting some attributes */ for (int lgi = 0; lgi < lgn; lgi++) { if ( rglyphs[lgi] == 0xdd/*TH_BLANK_BASE_GLYPH*/ ) { //if ( !item->fixedPitch ) { glyphString[slen++] = C_DOTTED_CIRCLE; item->attributes[slen-1].dontPrint = true; // FIXME this will hide all dotted circle //} } else { glyphString[slen++] = (HB_UChar16) thai_get_glyph_index (font_type, rglyphs[lgi]); } } if (haveSaraAm) { logClusters[i + cell_length - 1] = slen - 1; // Set logClusters before NIKAHIT if (tis_cell.top != 0) logClusters[i + cell_length - 2] = slen - 2; // Set logClusters before NIKAHIT when tis_cell has top if (logClusters[i + cell_length - 1] > slen) logClusters[i + cell_length - 1] = 0; } i += cell_length; } glyphString[slen] = (HB_UChar16) '\0'; /* for check, should reallocate space or not */ HB_Bool spaceOK = (item->num_glyphs >= slen); /* Convert to Glyph indices */ HB_Bool haveGlyphs = item->font->klass->convertStringToGlyphIndices ( item->font, glyphString, slen, item->glyphs, &item->num_glyphs, item->shaperFlags); HB_FREE_STACKARRAY (glyphString); if (len >= 128) free(cstr); return (haveGlyphs && spaceOK); }
HB_Bool HB_ThaiShape(HB_ShaperItem *item) { HB_Bool openType = FALSE; unsigned short *logClusters = item->log_clusters; int i; int clusterIndex; int cStart, cEnd; int fristGlyphIndex; int prevOutputIndex; int outputClusterLength; HB_ShaperItem shapedItem = *item; THDEBUG("item->item.pos: %d, item->item.length: %d", item->item.pos, item->item.length); ThaiShapeCategory glyphSet = thaiCheckShapeCategory(item); HB_UChar16 * output = (HB_UChar16 *)malloc(sizeof(HB_UChar16) * (item->item.length << 1)); hb_int32 *charIndex = (hb_int32 *)malloc(sizeof(hb_int32) * (item->item.length << 1)); hb_int32 *clusterStart = (hb_int32 *)malloc(sizeof(hb_int32) * (item->item.length << 1)); int clusterCount = 0; hb_int32 strLen = thaiCompose(item->string, item->item.pos, item->item.length, glyphSet, CH_DOTTED_CIRCLE, output, charIndex, &clusterCount, clusterStart); THDEBUG("reordered strLen: %d", strLen); #ifdef THAI_DEBUG THDEBUG("clusterCount: %d", clusterCount); for (i = 0; i < strLen; ++i) { THDEBUG("charIndex[%d]: %d, clusterStart[%d]: %d", i, charIndex[i], i, clusterStart[i]); } #endif shapedItem.string = output; shapedItem.stringLength = strLen; fristGlyphIndex = 0; prevOutputIndex = 0; for (clusterIndex = 0; clusterIndex < clusterCount; ++clusterIndex) { cStart = clusterStart[clusterIndex]; if (clusterIndex == clusterCount - 1) { cEnd = item->item.length; } else { cEnd = clusterStart[clusterIndex + 1]; } outputClusterLength = 0; for (i = prevOutputIndex; i < strLen && charIndex[i] < cEnd; ++i) { ++outputClusterLength; } THDEBUG(" outputClusterLength %d", outputClusterLength); shapedItem.item.pos = prevOutputIndex; shapedItem.item.length = outputClusterLength; shapedItem.glyphs = item->glyphs + fristGlyphIndex; shapedItem.attributes = item->attributes + fristGlyphIndex; shapedItem.advances = item->advances + fristGlyphIndex; shapedItem.offsets = item->offsets + fristGlyphIndex; shapedItem.num_glyphs = item->num_glyphs - fristGlyphIndex; shapedItem.log_clusters = item->log_clusters + cStart; HB_BasicShape(&shapedItem); for (i = cStart; i < cEnd; ++i) { item->log_clusters[i] = fristGlyphIndex; } prevOutputIndex += outputClusterLength; fristGlyphIndex += shapedItem.num_glyphs; } for (i = item->item.length; i < prevOutputIndex; ++i) { item->log_clusters[i] = 0; } item->num_glyphs = fristGlyphIndex; THDEBUG("shapedItem.num_glyphs: %d", item->num_glyphs); free(clusterStart); free(charIndex); free(output); return TRUE; }