- int hash_idx, *hashp;
- unsigned char *buf;
- int embedded_rule; /* 1 if composition rule is embedded. */
- int chars; /* number of components. */
- int i;
- struct cmpchar_info *cmpcharp;
-
- /* The second byte 0xFF means COMPOSITION rule is embedded. */
- embedded_rule = (str[1] == 0xFF);
-
- /* At first, get the actual length of the composite character. */
- {
- const unsigned char *p, *endp = str + 1, *lastp = str + len;
- int bytes;
-
- while (endp < lastp && ! CHAR_HEAD_P (*endp)) endp++;
- if (endp - str < 5)
- /* Any composite char have at least 5-byte length. */
- return -1;
-
- chars = 0;
- p = str + 1;
- while (p < endp)
- {
- if (embedded_rule)
- {
- p++;
- if (p >= endp)
- return -1;
- }
- /* No need of checking if *P is 0xA0 because
- BYTES_BY_CHAR_HEAD (0x80) surely returns 2. */
- p += BYTES_BY_CHAR_HEAD (*p - 0x20);
- chars++;
- }
- if (p > endp || chars < 2 || chars > MAX_COMPONENT_COUNT)
- /* Invalid components. */
- return -1;
- len = p - str;
- }
- hash_idx = hash_string (str, len) % CMPCHAR_HASH_TABLE_SIZE;
- hashp = cmpchar_hash_table[hash_idx];
-
- /* Then, look into the hash table. */
- if (hashp != NULL)
- /* Find the correct one among composite characters of the same
- hash value. */
- for (i = 2; i < CMPCHAR_HASH_USED (hashp); i++)
- {
- cmpcharp = cmpchar_table[CMPCHAR_HASH_CMPCHAR_ID (hashp, i)];
- if (len == cmpcharp->len
- && ! bcmp (str, cmpcharp->data, len))
- return CMPCHAR_HASH_CMPCHAR_ID (hashp, i);
- }
-
- /* We have to register the composite character in cmpchar_table. */
- if (n_cmpchars >= (CHAR_FIELD2_MASK | CHAR_FIELD3_MASK))
- /* No, we have no more room for a new composite character. */
- return -1;
-
- /* Make the entry in hash table. */
- if (hashp == NULL)
- {
- /* Make a table for 8 composite characters initially. */
- hashp = (cmpchar_hash_table[hash_idx]
- = (int *) xmalloc (sizeof (int) * (2 + 8)));
- CMPCHAR_HASH_SIZE (hashp) = 10;
- CMPCHAR_HASH_USED (hashp) = 2;
- }
- else if (CMPCHAR_HASH_USED (hashp) >= CMPCHAR_HASH_SIZE (hashp))
- {
- CMPCHAR_HASH_SIZE (hashp) += 8;
- hashp = (cmpchar_hash_table[hash_idx]
- = (int *) xrealloc (hashp,
- sizeof (int) * CMPCHAR_HASH_SIZE (hashp)));
- }
- CMPCHAR_HASH_CMPCHAR_ID (hashp, CMPCHAR_HASH_USED (hashp)) = n_cmpchars;
- CMPCHAR_HASH_USED (hashp)++;
-
- /* Set information of the composite character in cmpchar_table. */
- if (cmpchar_table_size == 0)
- {
- /* This is the first composite character to be registered. */
- cmpchar_table_size = 256;
- cmpchar_table
- = (struct cmpchar_info **) xmalloc (sizeof (cmpchar_table[0])
- * cmpchar_table_size);
- }
- else if (cmpchar_table_size <= n_cmpchars)
- {
- cmpchar_table_size += 256;
- cmpchar_table
- = (struct cmpchar_info **) xrealloc (cmpchar_table,
- sizeof (cmpchar_table[0])
- * cmpchar_table_size);
- }
-
- cmpcharp = (struct cmpchar_info *) xmalloc (sizeof (struct cmpchar_info));
-
- cmpcharp->len = len;
- cmpcharp->data = (unsigned char *) xmalloc (len + 1);
- bcopy (str, cmpcharp->data, len);
- cmpcharp->data[len] = 0;
- cmpcharp->glyph_len = chars;
- cmpcharp->glyph = (GLYPH *) xmalloc (sizeof (GLYPH) * chars);
- if (embedded_rule)
- {
- cmpcharp->cmp_rule = (unsigned char *) xmalloc (chars);
- cmpcharp->col_offset = (float *) xmalloc (sizeof (float) * chars);
- }
- else
- {
- cmpcharp->cmp_rule = NULL;
- cmpcharp->col_offset = NULL;
- }
-
- /* Setup GLYPH data and composition rules (if any) so as not to make
- them every time on displaying. */
- {
- unsigned char *bufp;
- int width;
- float leftmost = 0.0, rightmost = 1.0;
-
- if (embedded_rule)
- /* At first, col_offset[N] is set to relative to col_offset[0]. */
- cmpcharp->col_offset[0] = 0;
-
- for (i = 0, bufp = cmpcharp->data + 1; i < chars; i++)
- {
- if (embedded_rule)
- cmpcharp->cmp_rule[i] = *bufp++;
-
- if (*bufp == 0xA0) /* This is an ASCII character. */
- {
- cmpcharp->glyph[i] = FAST_MAKE_GLYPH ((*++bufp & 0x7F), 0);
- width = 1;
- bufp++;
- }
- else /* Multibyte character. */
- {
- /* Make `bufp' point normal multi-byte form temporally. */
- *bufp -= 0x20;
- cmpcharp->glyph[i]
- = FAST_MAKE_GLYPH (string_to_non_ascii_char (bufp, 4, 0), 0);
- width = WIDTH_BY_CHAR_HEAD (*bufp);
- *bufp += 0x20;
- bufp += BYTES_BY_CHAR_HEAD (*bufp - 0x20);
- }
-
- if (embedded_rule && i > 0)
- {
- /* Reference points (global_ref and new_ref) are
- encoded as below:
-
- 0--1--2 -- ascent
- | |
- | |
- | 4 -+--- center
- -- 3 5 -- baseline
- | |
- 6--7--8 -- descent
-
- Now, we calculate the column offset of the new glyph
- from the left edge of the first glyph. This can avoid
- the same calculation everytime displaying this
- composite character. */
-
- /* Reference points of global glyph and new glyph. */
- int global_ref = (cmpcharp->cmp_rule[i] - 0xA0) / 9;
- int new_ref = (cmpcharp->cmp_rule[i] - 0xA0) % 9;
- /* Column offset relative to the first glyph. */
- float left = (leftmost
- + (global_ref % 3) * (rightmost - leftmost) / 2.0
- - (new_ref % 3) * width / 2.0);
-
- cmpcharp->col_offset[i] = left;
- if (left < leftmost)
- leftmost = left;
- if (left + width > rightmost)
- rightmost = left + width;
- }
- else
- {
- if (width > rightmost)
- rightmost = width;
- }
- }
- if (embedded_rule)
- {
- /* Now col_offset[N] are relative to the left edge of the
- first component. Make them relative to the left edge of
- overall glyph. */
- for (i = 0; i < chars; i++)
- cmpcharp->col_offset[i] -= leftmost;
- /* Make rightmost holds width of overall glyph. */
- rightmost -= leftmost;
- }
-
- cmpcharp->width = rightmost;
- if (cmpcharp->width < rightmost)
- /* To get a ceiling integer value. */
- cmpcharp->width++;
- }
-
- cmpchar_table[n_cmpchars] = cmpcharp;