OSDN Git Service

updated with TeX Live 2014.
[putex/putex.git] / src / dvipdfmx-pu / src / tt_glyf.c
1 /*  
2     
3     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
4
5     Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6     the dvipdfmx project team.
7     
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12     
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17     
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23 /*
24  * Subsetting glyf, updating loca, hmtx, ...
25  *
26  */
27
28 #include "config.h"
29
30 #include "system.h"
31 #include "mem.h"
32 #include "error.h"
33 #include "dpxutil.h"
34
35 #include "sfnt.h"
36 #include "tt_table.h"
37 #include "tt_glyf.h"
38
39 #define NUM_GLYPH_LIMIT        65534
40 #define TABLE_DATA_ALLOC_SIZE  40960
41 #define GLYPH_ARRAY_ALLOC_SIZE 256
42
43 static USHORT
44 find_empty_slot (struct tt_glyphs *g)
45 {
46   USHORT gid;
47
48   ASSERT(g);
49
50   for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
51     if (!(g->used_slot[gid/8] & (1 << (7 - (gid % 8)))))
52       break;
53   }
54   if (gid == NUM_GLYPH_LIMIT)
55     ERROR("No empty glyph slot available.");
56
57   return gid;
58 }
59
60 USHORT
61 tt_find_glyph (struct tt_glyphs *g, USHORT gid)
62 {
63   USHORT idx, new_gid = 0;
64
65   ASSERT(g);
66
67   for (idx = 0; idx < g->num_glyphs; idx++) {
68     if (gid == g->gd[idx].ogid) {
69       new_gid = g->gd[idx].gid;
70       break;
71     }
72   }
73
74   return new_gid;
75 }
76
77 USHORT
78 tt_get_index (struct tt_glyphs *g, USHORT gid)
79 {
80   USHORT idx;
81
82   ASSERT(g);
83
84   for (idx = 0; idx < g->num_glyphs; idx++) {
85     if (gid == g->gd[idx].gid)
86       break;
87   }
88   if (idx == g->num_glyphs)
89     idx = 0;
90
91   return idx;
92 }
93
94 USHORT
95 tt_add_glyph (struct tt_glyphs *g, USHORT gid, USHORT new_gid)
96 {
97   ASSERT(g);
98
99   if (g->used_slot[new_gid/8] & (1 << (7 - (new_gid % 8)))) {
100     WARN("Slot %u already used.", new_gid);
101   } else {
102     if (g->num_glyphs+1 >= NUM_GLYPH_LIMIT)
103       ERROR("Too many glyphs.");
104
105     if (g->num_glyphs >= g->max_glyphs) {
106       g->max_glyphs += GLYPH_ARRAY_ALLOC_SIZE;
107       g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
108     }
109     g->gd[g->num_glyphs].gid  = new_gid;
110     g->gd[g->num_glyphs].ogid = gid;
111     g->gd[g->num_glyphs].length = 0;
112     g->gd[g->num_glyphs].data   = NULL;
113     g->used_slot[new_gid/8] |= (1 << (7 - (new_gid % 8)));
114     g->num_glyphs += 1;
115   }
116
117   if (new_gid > g->last_gid) {
118     g->last_gid = new_gid;
119   }
120
121   return new_gid;
122 }
123
124 /*
125  * Initialization
126  */
127 struct tt_glyphs *
128 tt_build_init (void)
129 {
130   struct tt_glyphs *g;
131
132   g = NEW(1, struct tt_glyphs);
133
134   g->num_glyphs  = 0;
135   g->max_glyphs  = 0;
136   g->last_gid    = 0;
137   g->emsize      = 1;
138   g->default_advh = 0;
139   g->default_tsb  = 0;
140   g->gd = NULL;
141   g->used_slot = NEW(8192, unsigned char);
142   memset(g->used_slot, 0, 8192);
143   tt_add_glyph(g, 0, 0);
144
145   return g;
146 }
147
148 void
149 tt_build_finish (struct tt_glyphs *g)
150 {
151   if (g) {
152     if (g->gd) {
153       USHORT idx;
154       for (idx = 0; idx < g->num_glyphs; idx++) {
155         if (g->gd[idx].data)
156           RELEASE(g->gd[idx].data);
157       }
158       RELEASE(g->gd);
159     }
160     if (g->used_slot)
161       RELEASE(g->used_slot);
162     RELEASE(g);
163   }
164 }
165
166 static int CDECL 
167 glyf_cmp (const void *v1, const void *v2)
168 {
169   int cmp = 0;
170   const struct tt_glyph_desc *sv1, *sv2;
171
172   sv1 = (const struct tt_glyph_desc *) v1;
173   sv2 = (const struct tt_glyph_desc *) v2;
174
175   if (sv1->gid == sv2->gid)
176     cmp = 0;
177   else if (sv1->gid < sv2->gid)
178     cmp = -1;
179   else
180     cmp = 1;
181     
182   return cmp;
183 }
184
185 /*
186  * TrueType outline data.
187  */
188 #define ARG_1_AND_2_ARE_WORDS     (1 << 0)
189 #define ARGS_ARE_XY_VALUES        (1 << 1)
190 #define ROUND_XY_TO_GRID          (1 << 2)
191 #define WE_HAVE_A_SCALE           (1 << 3)
192 #define RESERVED                  (1 << 4)
193 #define MORE_COMPONENT            (1 << 5)
194 #define WE_HAVE_AN_X_AND_Y_SCALE  (1 << 6)
195 #define WE_HAVE_A_TWO_BY_TWO      (1 << 7)
196 #define WE_HAVE_INSTRUCTIONS      (1 << 8)
197 #define USE_MY_METRICS            (1 << 9)
198
199 int
200 tt_build_tables (sfnt *sfont, struct tt_glyphs *g)
201 {
202   char  *hmtx_table_data = NULL, *loca_table_data = NULL;
203   char  *glyf_table_data = NULL;
204   ULONG  hmtx_table_size, loca_table_size, glyf_table_size;
205   /* some information available from other TrueType table */
206   struct tt_head_table *head = NULL;
207   struct tt_hhea_table *hhea = NULL;
208   struct tt_maxp_table *maxp = NULL;
209   struct tt_longMetrics *hmtx, *vmtx = NULL;
210   struct tt_os2__table  *os2;
211   /* temp */
212   ULONG  *location, offset;
213   long    i;
214   USHORT *w_stat; /* Estimate most frequently appeared width */
215
216   ASSERT(g);
217
218   if (sfont == NULL ||
219 #ifdef XETEX
220       sfont->ft_face == NULL
221 #else
222       sfont->stream == NULL
223 #endif
224      )
225     ERROR("File not opened.");
226
227   if (sfont->type != SFNT_TYPE_TRUETYPE &&
228       sfont->type != SFNT_TYPE_TTC &&
229       sfont->type != SFNT_TYPE_DFONT)
230     ERROR("Invalid font type");
231
232   if (g->num_glyphs > NUM_GLYPH_LIMIT)
233     ERROR("Too many glyphs.");
234
235   /*
236    * Read head, hhea, maxp, loca:
237    *
238    *   unitsPerEm       --> head
239    *   numHMetrics      --> hhea
240    *   indexToLocFormat --> head
241    *   numGlyphs        --> maxp
242    */
243   head = tt_read_head_table(sfont);
244   hhea = tt_read_hhea_table(sfont);
245   maxp = tt_read_maxp_table(sfont);
246
247   if (hhea->metricDataFormat != 0)
248     ERROR("Unknown metricDataFormat.");
249
250   g->emsize = head->unitsPerEm;
251
252   sfnt_locate_table(sfont, "hmtx");
253   hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numOfLongHorMetrics, hhea->numOfExSideBearings);
254
255   os2 = tt_read_os2__table(sfont);
256   g->default_advh = os2->sTypoAscender - os2->sTypoDescender;
257   g->default_tsb  = g->default_advh - os2->sTypoAscender;
258
259   if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
260     struct tt_vhea_table *vhea;
261     vhea = tt_read_vhea_table(sfont);
262     sfnt_locate_table(sfont, "vmtx");
263     vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics, vhea->numOfExSideBearings);
264     RELEASE(vhea);
265   } else {
266     vmtx = NULL;
267   }
268
269   sfnt_locate_table(sfont, "loca");
270   location = NEW(maxp->numGlyphs + 1, ULONG);
271   if (head->indexToLocFormat == 0) {
272     for (i = 0; i <= maxp->numGlyphs; i++)
273       location[i] = 2*((ULONG) sfnt_get_ushort(sfont));
274   } else if (head->indexToLocFormat == 1) {
275     for (i = 0; i <= maxp->numGlyphs; i++)
276       location[i] = sfnt_get_ulong(sfont);
277   } else {
278     ERROR("Unknown IndexToLocFormat.");
279   }
280
281   w_stat = NEW(g->emsize+2, USHORT);
282   memset(w_stat, 0, sizeof(USHORT)*(g->emsize+2));
283   /*
284    * Read glyf table.
285    */
286   offset = sfnt_locate_table(sfont, "glyf");
287   /*
288    * The num_glyphs may grow when composite glyph is found.
289    * A component of glyph refered by a composite glyph is appended
290    * to used_glyphs if it is not already registered in used_glyphs.
291    * Glyph programs of composite glyphs are modified so that it
292    * correctly refer to new gid of their components.
293    */
294   for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
295     USHORT gid;     /* old gid */
296     ULONG  loc, len;
297     BYTE  *p, *endptr;
298     SHORT  number_of_contours;
299
300     if (i >= g->num_glyphs) /* finished */
301       break;
302
303     gid = g->gd[i].ogid;
304     if (gid >= maxp->numGlyphs)
305       ERROR("Invalid glyph index (gid %u)", gid);
306
307     loc = location[gid];
308     len = location[gid+1] - loc;
309     g->gd[i].advw = hmtx[gid].advance;
310     g->gd[i].lsb  = hmtx[gid].sideBearing;
311     if (vmtx) {
312       g->gd[i].advh = vmtx[gid].advance;
313       g->gd[i].tsb  = vmtx[gid].sideBearing;
314     } else {
315       g->gd[i].advh = g->default_advh;
316       g->gd[i].tsb  = g->default_tsb;
317     }
318     g->gd[i].length = len;
319     g->gd[i].data   = NULL;
320     if (g->gd[i].advw <= g->emsize) {
321       w_stat[g->gd[i].advw] += 1;
322     } else {
323       w_stat[g->emsize+1]   += 1; /* larger than em */
324     }
325
326     if (len == 0) { /* Does not contains any data. */
327       continue;
328     } else if (len < 10) {
329       ERROR("Invalid TrueType glyph data (gid %u).", gid);
330     }
331
332     g->gd[i].data = p = NEW(len, BYTE);
333     endptr = p + len;
334
335     sfnt_seek_set(sfont, offset+loc);
336     number_of_contours = sfnt_get_short(sfont);
337     p += sfnt_put_short(p, number_of_contours);
338
339     /* BoundingBox: FWord x 4 */
340     g->gd[i].llx = sfnt_get_short(sfont);
341     g->gd[i].lly = sfnt_get_short(sfont);
342     g->gd[i].urx = sfnt_get_short(sfont);
343     g->gd[i].ury = sfnt_get_short(sfont);
344     /* _FIXME_ */
345 #if  1
346     if (!vmtx) /* vertOriginY == sTypeAscender */
347       g->gd[i].tsb = g->default_advh - g->default_tsb - g->gd[i].ury;
348 #endif
349     p += sfnt_put_short(p, g->gd[i].llx);
350     p += sfnt_put_short(p, g->gd[i].lly);
351     p += sfnt_put_short(p, g->gd[i].urx);
352     p += sfnt_put_short(p, g->gd[i].ury);
353
354     /* Read evrything else. */
355     sfnt_read(p, len - 10, sfont);
356     /*
357      * Fix GIDs of composite glyphs.
358      */
359     if (number_of_contours < 0) {
360       USHORT flags, cgid, new_gid; /* flag, gid of a component */
361       do {
362         if (p >= endptr)
363           ERROR("Invalid TrueType glyph data (gid %u): %u bytes", gid, len);
364         /*
365          * Flags and gid of component glyph are both USHORT.
366          */
367         flags = ((*p) << 8)| *(p+1);
368         p += 2;
369         cgid  = ((*p) << 8)| *(p+1);
370         if (cgid >= maxp->numGlyphs) {
371           ERROR("Invalid gid (%u > %u) in composite glyph %u.", cgid, maxp->numGlyphs, gid);
372         }
373         new_gid = tt_find_glyph(g, cgid);
374         if (new_gid == 0) {
375           new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
376         }
377         p += sfnt_put_ushort(p, new_gid);
378         /*
379          * Just skip remaining part.
380          */
381         p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
382         if (flags & WE_HAVE_A_SCALE) /* F2Dot14 */
383           p += 2;
384         else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) /* F2Dot14 x 2 */
385           p += 4;
386         else if (flags & WE_HAVE_A_TWO_BY_TWO) /* F2Dot14 x 4 */
387           p += 8;
388       } while (flags & MORE_COMPONENT);
389       /*
390        * TrueType instructions comes here:
391        *  length_of_instruction (ushort)
392        *  instruction (byte * length_of_instruction)
393        */
394     }
395   }
396   RELEASE(location);
397   RELEASE(hmtx);
398   if (vmtx)
399     RELEASE(vmtx);
400
401   {
402     int max_count = -1;
403
404     g->dw = g->gd[0].advw;
405     for (i = 0; i < g->emsize + 1; i++) {
406       if (w_stat[i] > max_count) {
407         max_count = w_stat[i];
408         g->dw = i;
409       }
410     }
411   }
412   RELEASE(w_stat);
413
414   qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
415   {
416     USHORT prev, last_advw;
417     char  *p, *q;
418     int    padlen, num_hm_known;
419
420     glyf_table_size = 0UL;
421     num_hm_known = 0;
422     last_advw = g->gd[g->num_glyphs - 1].advw;
423     for (i = g->num_glyphs - 1; i >= 0; i--) {
424       padlen = (g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0;
425       glyf_table_size += g->gd[i].length + padlen;
426       if (!num_hm_known && last_advw != g->gd[i].advw) {
427         hhea->numOfLongHorMetrics = g->gd[i].gid + 2;
428         num_hm_known = 1;
429       }
430     }
431     /* All advance widths are same. */
432     if (!num_hm_known) {
433       hhea->numOfLongHorMetrics = 1;
434     }
435     hmtx_table_size = hhea->numOfLongHorMetrics * 2 + (g->last_gid + 1) * 2;
436
437     /*
438      * Choosing short format does not always give good result
439      * when compressed. Sometimes increases size.
440      */
441     if (glyf_table_size < 0x20000UL) {
442       head->indexToLocFormat = 0;
443       loca_table_size = (g->last_gid + 2)*2;
444     } else {
445       head->indexToLocFormat = 1;
446       loca_table_size = (g->last_gid + 2)*4;
447     }
448
449     hmtx_table_data = p = NEW(hmtx_table_size, char);
450     loca_table_data = q = NEW(loca_table_size, char);
451     glyf_table_data = NEW(glyf_table_size, char);
452
453     offset = 0UL; prev = 0;
454     for (i = 0; i < g->num_glyphs; i++) {
455       long gap, j;
456       gap = (long) g->gd[i].gid - prev - 1;
457       for (j = 1; j <= gap; j++) {
458         if (prev + j == hhea->numOfLongHorMetrics - 1) {
459           p += sfnt_put_ushort(p, last_advw);
460         } else if (prev + j < hhea->numOfLongHorMetrics) {
461           p += sfnt_put_ushort(p, 0);
462         }
463         p += sfnt_put_short (p, 0);
464         if (head->indexToLocFormat == 0) {
465           q += sfnt_put_ushort(q, (USHORT) (offset/2));
466         } else {
467           q += sfnt_put_ulong(q, offset);
468         }
469       }
470       padlen = (g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0;
471       if (g->gd[i].gid < hhea->numOfLongHorMetrics) {
472         p += sfnt_put_ushort(p, g->gd[i].advw);
473       }
474       p += sfnt_put_short (p, g->gd[i].lsb);
475       if (head->indexToLocFormat == 0) {
476         q += sfnt_put_ushort(q, (USHORT) (offset/2));
477       } else {
478         q += sfnt_put_ulong(q, offset);
479       }
480       memset(glyf_table_data + offset, 0, g->gd[i].length + padlen);
481       memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
482       offset += g->gd[i].length + padlen;
483       prev    = g->gd[i].gid;
484       /* free data here since it consume much memory */
485       RELEASE(g->gd[i].data);
486       g->gd[i].length = 0; g->gd[i].data = NULL;
487     }
488     if (head->indexToLocFormat == 0) {
489       q += sfnt_put_ushort(q, (USHORT) (offset/2));
490     } else {
491       q += sfnt_put_ulong(q, offset);
492     }
493
494     sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data, hmtx_table_size);
495     sfnt_set_table(sfont, "loca", (char *) loca_table_data, loca_table_size);
496     sfnt_set_table(sfont, "glyf", (char *) glyf_table_data, glyf_table_size);
497   }
498
499   head->checkSumAdjustment = 0;
500   maxp->numGlyphs          = g->last_gid + 1;
501
502   /* TODO */
503   sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
504   sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
505   sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
506   RELEASE(maxp);
507   RELEASE(hhea);
508   RELEASE(head);
509   RELEASE(os2);
510
511   return 0;
512 }
513
514 int
515 tt_get_metrics (sfnt *sfont, struct tt_glyphs *g)
516 {
517   struct tt_head_table *head = NULL;
518   struct tt_hhea_table *hhea = NULL;
519   struct tt_maxp_table *maxp = NULL;
520   struct tt_longMetrics *hmtx, *vmtx = NULL;
521   struct tt_os2__table  *os2;
522   /* temp */
523   ULONG  *location, offset;
524   long    i;
525   USHORT *w_stat;
526
527   ASSERT(g);
528
529   if (sfont == NULL ||
530 #ifdef XETEX
531       sfont->ft_face == NULL
532 #else
533       sfont->stream == NULL
534 #endif
535      )
536     ERROR("File not opened.");
537
538   if (sfont->type != SFNT_TYPE_TRUETYPE &&
539       sfont->type != SFNT_TYPE_TTC &&
540       sfont->type != SFNT_TYPE_DFONT)
541     ERROR("Invalid font type");
542
543   /*
544    * Read head, hhea, maxp, loca:
545    *
546    *   unitsPerEm       --> head
547    *   numHMetrics      --> hhea
548    *   indexToLocFormat --> head
549    *   numGlyphs        --> maxp
550    */
551   head = tt_read_head_table(sfont);
552   hhea = tt_read_hhea_table(sfont);
553   maxp = tt_read_maxp_table(sfont);
554
555   if (hhea->metricDataFormat != 0)
556     ERROR("Unknown metricDataFormat.");
557
558   g->emsize = head->unitsPerEm;
559
560   sfnt_locate_table(sfont, "hmtx");
561   hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numOfLongHorMetrics, hhea->numOfExSideBearings);
562
563   os2 = tt_read_os2__table(sfont);
564   g->default_advh = os2->sTypoAscender - os2->sTypoDescender;
565   g->default_tsb  = g->default_advh - os2->sTypoAscender;
566
567   if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
568     struct tt_vhea_table *vhea;
569     vhea = tt_read_vhea_table(sfont);
570     sfnt_locate_table(sfont, "vmtx");
571     vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics, vhea->numOfExSideBearings);
572     RELEASE(vhea);
573   } else {
574     vmtx = NULL;
575   }
576
577   sfnt_locate_table(sfont, "loca");
578   location = NEW(maxp->numGlyphs + 1, ULONG);
579   if (head->indexToLocFormat == 0) {
580     for (i = 0; i <= maxp->numGlyphs; i++)
581       location[i] = 2*((ULONG) sfnt_get_ushort(sfont));
582   } else if (head->indexToLocFormat == 1) {
583     for (i = 0; i <= maxp->numGlyphs; i++)
584       location[i] = sfnt_get_ulong(sfont);
585   } else {
586     ERROR("Unknown IndexToLocFormat.");
587   }
588
589   w_stat = NEW(g->emsize+2, USHORT);
590   memset(w_stat, 0, sizeof(USHORT)*(g->emsize+2));
591   /*
592    * Read glyf table.
593    */
594   offset = sfnt_locate_table(sfont, "glyf");
595   for (i = 0; i < g->num_glyphs; i++) {
596     USHORT gid;     /* old gid */
597     ULONG  loc, len;
598
599     gid = g->gd[i].ogid;
600     if (gid >= maxp->numGlyphs)
601       ERROR("Invalid glyph index (gid %u)", gid);
602
603     loc = location[gid];
604     len = location[gid+1] - loc;
605     g->gd[i].advw = hmtx[gid].advance;
606     g->gd[i].lsb  = hmtx[gid].sideBearing;
607     if (vmtx) {
608       g->gd[i].advh = vmtx[gid].advance;
609       g->gd[i].tsb  = vmtx[gid].sideBearing;
610     } else {
611       g->gd[i].advh = g->default_advh;
612       g->gd[i].tsb  = g->default_tsb;
613     }
614     g->gd[i].length = len;
615     g->gd[i].data   = NULL;
616
617     if (g->gd[i].advw <= g->emsize) {
618       w_stat[g->gd[i].advw] += 1;
619     } else {
620       w_stat[g->emsize+1]   += 1; /* larger than em */
621     }
622
623     if (len == 0) { /* Does not contains any data. */
624       continue;
625     } else if (len < 10) {
626       ERROR("Invalid TrueType glyph data (gid %u).", gid);
627     }
628
629     sfnt_seek_set(sfont, offset+loc);
630     (void)               sfnt_get_short(sfont);
631
632     /* BoundingBox: FWord x 4 */
633     g->gd[i].llx = sfnt_get_short(sfont);
634     g->gd[i].lly = sfnt_get_short(sfont);
635     g->gd[i].urx = sfnt_get_short(sfont);
636     g->gd[i].ury = sfnt_get_short(sfont);
637     /* _FIXME_ */
638 #if  1
639     if (!vmtx) /* vertOriginY == sTypeAscender */
640       g->gd[i].tsb = g->default_advh - g->default_tsb - g->gd[i].ury;
641 #endif
642   }
643   RELEASE(location);
644   RELEASE(hmtx);
645   RELEASE(maxp);
646   RELEASE(hhea);
647   RELEASE(head);
648   RELEASE(os2);
649
650   if (vmtx)
651     RELEASE(vmtx);
652
653   {
654     int max_count = -1;
655
656     g->dw = g->gd[0].advw;
657     for (i = 0; i < g->emsize + 1; i++) {
658       if (w_stat[i] > max_count) {
659         max_count = w_stat[i];
660         g->dw = i;
661       }
662     }
663   }
664   RELEASE(w_stat);
665
666
667   return 0;
668 }