sync with tizen_2.2
[sdk/emulator/qemu.git] / gl / mesa / src / gallium / auxiliary / util / u_format.c
1 /**************************************************************************
2  *
3  * Copyright 2010 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27
28 /**
29  * @file
30  * Pixel format accessor functions.
31  *
32  * @author Jose Fonseca <jfonseca@vmware.com>
33  */
34
35 #include "u_math.h"
36 #include "u_memory.h"
37 #include "u_rect.h"
38 #include "u_format.h"
39 #include "u_format_s3tc.h"
40
41 #include "pipe/p_defines.h"
42
43
44 boolean
45 util_format_is_float(enum pipe_format format)
46 {
47    const struct util_format_description *desc = util_format_description(format);
48    unsigned i;
49
50    assert(desc);
51    if (!desc) {
52       return FALSE;
53    }
54
55    i = util_format_get_first_non_void_channel(format);
56    if (i == -1) {
57       return FALSE;
58    }
59
60    return desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT ? TRUE : FALSE;
61 }
62
63
64 /**
65  * Return the number of logical channels in the given format by
66  * examining swizzles.
67  * XXX this could be made into a public function if useful elsewhere.
68  */
69 static unsigned
70 nr_logical_channels(const struct util_format_description *desc)
71 {
72    boolean swizzle_used[UTIL_FORMAT_SWIZZLE_MAX];
73
74    memset(swizzle_used, 0, sizeof(swizzle_used));
75
76    swizzle_used[desc->swizzle[0]] = TRUE;
77    swizzle_used[desc->swizzle[1]] = TRUE;
78    swizzle_used[desc->swizzle[2]] = TRUE;
79    swizzle_used[desc->swizzle[3]] = TRUE;
80
81    return (swizzle_used[UTIL_FORMAT_SWIZZLE_X] +
82            swizzle_used[UTIL_FORMAT_SWIZZLE_Y] +
83            swizzle_used[UTIL_FORMAT_SWIZZLE_Z] +
84            swizzle_used[UTIL_FORMAT_SWIZZLE_W]);
85 }
86
87
88 /** Test if the format contains RGB, but not alpha */
89 boolean
90 util_format_is_rgb_no_alpha(enum pipe_format format)
91 {
92    const struct util_format_description *desc =
93       util_format_description(format);
94
95    if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
96         desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
97        nr_logical_channels(desc) == 3) {
98       return TRUE;
99    }
100    return FALSE;
101 }
102
103
104 boolean
105 util_format_is_luminance(enum pipe_format format)
106 {
107    const struct util_format_description *desc =
108       util_format_description(format);
109
110    if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
111         desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
112        desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
113        desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
114        desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
115        desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) {
116       return TRUE;
117    }
118    return FALSE;
119 }
120
121 boolean
122 util_format_is_pure_integer(enum pipe_format format)
123 {
124    const struct util_format_description *desc = util_format_description(format);
125    int i;
126
127    /* Find the first non-void channel. */
128    i = util_format_get_first_non_void_channel(format);
129    if (i == -1)
130       return FALSE;
131
132    return desc->channel[i].pure_integer ? TRUE : FALSE;
133 }
134
135 boolean
136 util_format_is_pure_sint(enum pipe_format format)
137 {
138    const struct util_format_description *desc = util_format_description(format);
139    int i;
140
141    i = util_format_get_first_non_void_channel(format);
142    if (i == -1)
143       return FALSE;
144
145    return (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;
146 }
147
148 boolean
149 util_format_is_pure_uint(enum pipe_format format)
150 {
151    const struct util_format_description *desc = util_format_description(format);
152    int i;
153
154    i = util_format_get_first_non_void_channel(format);
155    if (i == -1)
156       return FALSE;
157
158    return (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;
159 }
160
161 boolean
162 util_format_is_luminance_alpha(enum pipe_format format)
163 {
164    const struct util_format_description *desc =
165       util_format_description(format);
166
167    if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
168         desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
169        desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
170        desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
171        desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
172        desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_Y) {
173       return TRUE;
174    }
175    return FALSE;
176 }
177
178
179 boolean
180 util_format_is_intensity(enum pipe_format format)
181 {
182    const struct util_format_description *desc =
183       util_format_description(format);
184
185    if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
186         desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
187        desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
188        desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
189        desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
190        desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) {
191       return TRUE;
192    }
193    return FALSE;
194 }
195
196
197 boolean
198 util_format_is_supported(enum pipe_format format, unsigned bind)
199 {
200    if (util_format_is_s3tc(format) && !util_format_s3tc_enabled) {
201       return FALSE;
202    }
203
204 #ifndef TEXTURE_FLOAT_ENABLED
205    if ((bind & PIPE_BIND_RENDER_TARGET) &&
206        format != PIPE_FORMAT_R9G9B9E5_FLOAT &&
207        format != PIPE_FORMAT_R11G11B10_FLOAT &&
208        util_format_is_float(format)) {
209       return FALSE;
210    }
211 #endif
212
213    return TRUE;
214 }
215
216
217 void
218 util_format_read_4f(enum pipe_format format,
219                     float *dst, unsigned dst_stride,
220                     const void *src, unsigned src_stride,
221                     unsigned x, unsigned y, unsigned w, unsigned h)
222 {
223    const struct util_format_description *format_desc;
224    const uint8_t *src_row;
225    float *dst_row;
226
227    format_desc = util_format_description(format);
228
229    assert(x % format_desc->block.width == 0);
230    assert(y % format_desc->block.height == 0);
231
232    src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
233    dst_row = dst;
234
235    format_desc->unpack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h);
236 }
237
238
239 void
240 util_format_write_4f(enum pipe_format format,
241                      const float *src, unsigned src_stride,
242                      void *dst, unsigned dst_stride,
243                      unsigned x, unsigned y, unsigned w, unsigned h)
244 {
245    const struct util_format_description *format_desc;
246    uint8_t *dst_row;
247    const float *src_row;
248
249    format_desc = util_format_description(format);
250
251    assert(x % format_desc->block.width == 0);
252    assert(y % format_desc->block.height == 0);
253
254    dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
255    src_row = src;
256
257    format_desc->pack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h);
258 }
259
260
261 void
262 util_format_read_4ub(enum pipe_format format, uint8_t *dst, unsigned dst_stride, const void *src, unsigned src_stride, unsigned x, unsigned y, unsigned w, unsigned h)
263 {
264    const struct util_format_description *format_desc;
265    const uint8_t *src_row;
266    uint8_t *dst_row;
267
268    format_desc = util_format_description(format);
269
270    assert(x % format_desc->block.width == 0);
271    assert(y % format_desc->block.height == 0);
272
273    src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
274    dst_row = dst;
275
276    format_desc->unpack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h);
277 }
278
279
280 void
281 util_format_write_4ub(enum pipe_format format, const uint8_t *src, unsigned src_stride, void *dst, unsigned dst_stride, unsigned x, unsigned y, unsigned w, unsigned h)
282 {
283    const struct util_format_description *format_desc;
284    uint8_t *dst_row;
285    const uint8_t *src_row;
286
287    format_desc = util_format_description(format);
288
289    assert(x % format_desc->block.width == 0);
290    assert(y % format_desc->block.height == 0);
291
292    dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
293    src_row = src;
294
295    format_desc->pack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h);
296 }
297
298 void
299 util_format_read_4ui(enum pipe_format format,
300                      unsigned *dst, unsigned dst_stride,
301                      const void *src, unsigned src_stride,
302                      unsigned x, unsigned y, unsigned w, unsigned h)
303 {
304    const struct util_format_description *format_desc;
305    const uint8_t *src_row;
306    unsigned *dst_row;
307
308    format_desc = util_format_description(format);
309
310    assert(x % format_desc->block.width == 0);
311    assert(y % format_desc->block.height == 0);
312
313    src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
314    dst_row = dst;
315
316    format_desc->unpack_rgba_uint(dst_row, dst_stride, src_row, src_stride, w, h);
317 }
318
319 void
320 util_format_write_4ui(enum pipe_format format,
321                       const unsigned int *src, unsigned src_stride,
322                       void *dst, unsigned dst_stride,
323                       unsigned x, unsigned y, unsigned w, unsigned h)
324 {
325    const struct util_format_description *format_desc;
326    uint8_t *dst_row;
327    const unsigned *src_row;
328
329    format_desc = util_format_description(format);
330
331    assert(x % format_desc->block.width == 0);
332    assert(y % format_desc->block.height == 0);
333
334    dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
335    src_row = src;
336
337    format_desc->pack_rgba_uint(dst_row, dst_stride, src_row, src_stride, w, h);
338 }
339
340 void
341 util_format_read_4i(enum pipe_format format,
342                     int *dst, unsigned dst_stride,
343                     const void *src, unsigned src_stride,
344                     unsigned x, unsigned y, unsigned w, unsigned h)
345 {
346    const struct util_format_description *format_desc;
347    const uint8_t *src_row;
348    int *dst_row;
349
350    format_desc = util_format_description(format);
351
352    assert(x % format_desc->block.width == 0);
353    assert(y % format_desc->block.height == 0);
354
355    src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
356    dst_row = dst;
357
358    format_desc->unpack_rgba_sint(dst_row, dst_stride, src_row, src_stride, w, h);
359 }
360
361 void
362 util_format_write_4i(enum pipe_format format,
363                       const int *src, unsigned src_stride,
364                       void *dst, unsigned dst_stride,
365                       unsigned x, unsigned y, unsigned w, unsigned h)
366 {
367    const struct util_format_description *format_desc;
368    uint8_t *dst_row;
369    const int *src_row;
370
371    format_desc = util_format_description(format);
372
373    assert(x % format_desc->block.width == 0);
374    assert(y % format_desc->block.height == 0);
375
376    dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
377    src_row = src;
378
379    format_desc->pack_rgba_sint(dst_row, dst_stride, src_row, src_stride, w, h);
380 }
381
382 boolean
383 util_is_format_compatible(const struct util_format_description *src_desc,
384                           const struct util_format_description *dst_desc)
385 {
386    unsigned chan;
387
388    if (src_desc->format == dst_desc->format) {
389       return TRUE;
390    }
391
392    if (src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN ||
393        dst_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) {
394       return FALSE;
395    }
396
397    if (src_desc->block.bits != dst_desc->block.bits ||
398        src_desc->nr_channels != dst_desc->nr_channels ||
399        src_desc->colorspace != dst_desc->colorspace) {
400       return FALSE;
401    }
402
403    for (chan = 0; chan < 4; ++chan) {
404       if (src_desc->channel[chan].size !=
405           dst_desc->channel[chan].size) {
406          return FALSE;
407       }
408    }
409
410    for (chan = 0; chan < 4; ++chan) {
411       enum util_format_swizzle swizzle = dst_desc->swizzle[chan];
412
413       if (swizzle < 4) {
414          if (src_desc->swizzle[chan] != swizzle) {
415             return FALSE;
416          }
417          if ((src_desc->channel[swizzle].type !=
418               dst_desc->channel[swizzle].type) ||
419              (src_desc->channel[swizzle].normalized !=
420               dst_desc->channel[swizzle].normalized)) {
421             return FALSE;
422          }
423       }
424    }
425
426    return TRUE;
427 }
428
429
430 boolean
431 util_format_fits_8unorm(const struct util_format_description *format_desc)
432 {
433    unsigned chan;
434
435    /*
436     * After linearized sRGB values require more than 8bits.
437     */
438
439    if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
440       return FALSE;
441    }
442
443    switch (format_desc->layout) {
444
445    case UTIL_FORMAT_LAYOUT_S3TC:
446       /*
447        * These are straight forward.
448        */
449       return TRUE;
450    case UTIL_FORMAT_LAYOUT_RGTC:
451       if (format_desc->format == PIPE_FORMAT_RGTC1_SNORM ||
452           format_desc->format == PIPE_FORMAT_RGTC2_SNORM ||
453           format_desc->format == PIPE_FORMAT_LATC1_SNORM ||
454           format_desc->format == PIPE_FORMAT_LATC2_SNORM)
455          return FALSE;
456       return TRUE;
457
458    case UTIL_FORMAT_LAYOUT_PLAIN:
459       /*
460        * For these we can find a generic rule.
461        */
462
463       for (chan = 0; chan < format_desc->nr_channels; ++chan) {
464          switch (format_desc->channel[chan].type) {
465          case UTIL_FORMAT_TYPE_VOID:
466             break;
467          case UTIL_FORMAT_TYPE_UNSIGNED:
468             if (!format_desc->channel[chan].normalized ||
469                 format_desc->channel[chan].size > 8) {
470                return FALSE;
471             }
472             break;
473          default:
474             return FALSE;
475          }
476       }
477       return TRUE;
478
479    default:
480       /*
481        * Handle all others on a case by case basis.
482        */
483
484       switch (format_desc->format) {
485       case PIPE_FORMAT_R1_UNORM:
486       case PIPE_FORMAT_UYVY:
487       case PIPE_FORMAT_YUYV:
488       case PIPE_FORMAT_R8G8_B8G8_UNORM:
489       case PIPE_FORMAT_G8R8_G8B8_UNORM:
490          return TRUE;
491
492       default:
493          return FALSE;
494       }
495    }
496 }
497
498
499 void
500 util_format_translate(enum pipe_format dst_format,
501                       void *dst, unsigned dst_stride,
502                       unsigned dst_x, unsigned dst_y,
503                       enum pipe_format src_format,
504                       const void *src, unsigned src_stride,
505                       unsigned src_x, unsigned src_y,
506                       unsigned width, unsigned height)
507 {
508    const struct util_format_description *dst_format_desc;
509    const struct util_format_description *src_format_desc;
510    uint8_t *dst_row;
511    const uint8_t *src_row;
512    unsigned x_step, y_step;
513    unsigned dst_step;
514    unsigned src_step;
515
516    dst_format_desc = util_format_description(dst_format);
517    src_format_desc = util_format_description(src_format);
518
519    if (util_is_format_compatible(src_format_desc, dst_format_desc)) {
520       /*
521        * Trivial case.
522        */
523
524       util_copy_rect(dst, dst_format, dst_stride,  dst_x, dst_y,
525                      width, height, src, (int)src_stride,
526                      src_x, src_y);
527       return;
528    }
529
530    assert(dst_x % dst_format_desc->block.width == 0);
531    assert(dst_y % dst_format_desc->block.height == 0);
532    assert(src_x % src_format_desc->block.width == 0);
533    assert(src_y % src_format_desc->block.height == 0);
534
535    dst_row = (uint8_t *)dst + dst_y*dst_stride + dst_x*(dst_format_desc->block.bits/8);
536    src_row = (const uint8_t *)src + src_y*src_stride + src_x*(src_format_desc->block.bits/8);
537
538    /*
539     * This works because all pixel formats have pixel blocks with power of two
540     * sizes.
541     */
542
543    y_step = MAX2(dst_format_desc->block.height, src_format_desc->block.height);
544    x_step = MAX2(dst_format_desc->block.width, src_format_desc->block.width);
545    assert(y_step % dst_format_desc->block.height == 0);
546    assert(y_step % src_format_desc->block.height == 0);
547
548    dst_step = y_step / dst_format_desc->block.height * dst_stride;
549    src_step = y_step / src_format_desc->block.height * src_stride;
550
551    /*
552     * TODO: double formats will loose precision
553     * TODO: Add a special case for formats that are mere swizzles of each other
554     */
555
556    if (src_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS ||
557        dst_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
558       float *tmp_z = NULL;
559       uint8_t *tmp_s = NULL;
560
561       assert(x_step == 1);
562       assert(y_step == 1);
563
564       if (src_format_desc->unpack_z_float &&
565           dst_format_desc->pack_z_float) {
566          tmp_z = MALLOC(width * sizeof *tmp_z);
567       }
568
569       if (src_format_desc->unpack_s_8uint &&
570           dst_format_desc->pack_s_8uint) {
571          tmp_s = MALLOC(width * sizeof *tmp_s);
572       }
573
574       while (height--) {
575          if (tmp_z) {
576             src_format_desc->unpack_z_float(tmp_z, 0, src_row, src_stride, width, 1);
577             dst_format_desc->pack_z_float(dst_row, dst_stride, tmp_z, 0, width, 1);
578          }
579
580          if (tmp_s) {
581             src_format_desc->unpack_s_8uint(tmp_s, 0, src_row, src_stride, width, 1);
582             dst_format_desc->pack_s_8uint(dst_row, dst_stride, tmp_s, 0, width, 1);
583          }
584
585          dst_row += dst_step;
586          src_row += src_step;
587       }
588
589       if (tmp_s) {
590          FREE(tmp_s);
591       }
592
593       if (tmp_z) {
594          FREE(tmp_z);
595       }
596
597       return;
598    }
599
600    if (util_format_fits_8unorm(src_format_desc) ||
601        util_format_fits_8unorm(dst_format_desc)) {
602       unsigned tmp_stride;
603       uint8_t *tmp_row;
604
605       tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
606       tmp_row = MALLOC(y_step * tmp_stride);
607       if (!tmp_row)
608          return;
609
610       while (height >= y_step) {
611          src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, y_step);
612          dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);
613
614          dst_row += dst_step;
615          src_row += src_step;
616          height -= y_step;
617       }
618
619       if (height) {
620          src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, height);
621          dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, height);
622       }
623
624       FREE(tmp_row);
625    }
626    else {
627       unsigned tmp_stride;
628       float *tmp_row;
629
630       tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
631       tmp_row = MALLOC(y_step * tmp_stride);
632       if (!tmp_row)
633          return;
634
635       while (height >= y_step) {
636          src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, y_step);
637          dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);
638
639          dst_row += dst_step;
640          src_row += src_step;
641          height -= y_step;
642       }
643
644       if (height) {
645          src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, height);
646          dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, height);
647       }
648
649       FREE(tmp_row);
650    }
651 }
652
653 void util_format_compose_swizzles(const unsigned char swz1[4],
654                                   const unsigned char swz2[4],
655                                   unsigned char dst[4])
656 {
657    unsigned i;
658
659    for (i = 0; i < 4; i++) {
660       dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ?
661                swz1[swz2[i]] : swz2[i];
662    }
663 }
664
665 void util_format_swizzle_4f(float *dst, const float *src,
666                             const unsigned char swz[4])
667 {
668    unsigned i;
669
670    for (i = 0; i < 4; i++) {
671       if (swz[i] <= UTIL_FORMAT_SWIZZLE_W)
672          dst[i] = src[swz[i]];
673       else if (swz[i] == UTIL_FORMAT_SWIZZLE_0)
674          dst[i] = 0;
675       else if (swz[i] == UTIL_FORMAT_SWIZZLE_1)
676          dst[i] = 1;
677    }
678 }
679
680 void util_format_unswizzle_4f(float *dst, const float *src,
681                               const unsigned char swz[4])
682 {
683    unsigned i;
684
685    for (i = 0; i < 4; i++) {
686       switch (swz[i]) {
687       case UTIL_FORMAT_SWIZZLE_X:
688          dst[0] = src[i];
689          break;
690       case UTIL_FORMAT_SWIZZLE_Y:
691          dst[1] = src[i];
692          break;
693       case UTIL_FORMAT_SWIZZLE_Z:
694          dst[2] = src[i];
695          break;
696       case UTIL_FORMAT_SWIZZLE_W:
697          dst[3] = src[i];
698          break;
699       }
700    }
701 }