diff --git a/apps/sh.c b/apps/sh.c index 1fa2d86f..31f20f46 100644 --- a/apps/sh.c +++ b/apps/sh.c @@ -792,7 +792,7 @@ void sort_commands() { } void show_version(void) { - printf("esh 0.11.0 - experimental shell\n"); + printf("esh 1.3.0\n"); } void show_usage(int argc, char * argv[]) { @@ -944,6 +944,14 @@ uint32_t shell_cmd_set(int argc, char * argv[]) { printf("\033[1555;%sz", argv[2]); fflush(stdout); return 0; + } else if (!strcmp(argv[1], "gamma")) { + if (argc < 3) { + fprintf(stderr, "%s %s [floating point gamma, 1.7 = normal]\n", argv[0], argv[1]); + return 1; + } + printf("\033[1556;%sz", argv[2]); + fflush(stdout); + return 0; } else if (!strcmp(argv[1], "size")) { if (argc < 4) { fprintf(stderr, "%s %s [width] [height]\n", argv[0], argv[1]); diff --git a/apps/terminal-vga.c b/apps/terminal-vga.c index 085499f3..0fd98be4 100644 --- a/apps/terminal-vga.c +++ b/apps/terminal-vga.c @@ -741,6 +741,7 @@ term_callbacks_t term_callbacks = { unsupported_int, unsupported_int, term_set_csr_show, + set_term_font_size, }; void reinit(int send_sig) { diff --git a/apps/terminal.c b/apps/terminal.c index c19f0bc8..cbba4469 100644 --- a/apps/terminal.c +++ b/apps/terminal.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "terminal-palette.h" #include "terminal-font.h" @@ -57,9 +58,10 @@ static FILE * terminal; int scale_fonts = 0; /* Whether fonts should be scaled */ float font_scaling = 1.0; /* How much they should be scaled by */ +float font_gamma = 1.7; /* Gamma to use for SDF library */ uint16_t term_width = 0; /* Width of the terminal (in cells) */ uint16_t term_height = 0; /* Height of the terminal (in cells) */ -uint16_t font_size = 13; /* Font size according to Freetype */ +uint16_t font_size = 13; /* Font size according to SDF library */ uint16_t char_width = 9; /* Width of a cell in pixels */ uint16_t char_height = 20; /* Height of a cell in pixels */ uint16_t char_offset = 0; /* Offset of the font within the cell */ @@ -72,7 +74,7 @@ uint8_t cursor_on = 1; /* Whether or not the cursor should be rendered uint8_t _fullscreen = 0; /* Whether or not we are running in fullscreen mode (GUI only) */ uint8_t _no_frame = 0; /* Whether to disable decorations or not */ uint8_t _login_shell = 0; /* Whether we're going to display a login shell or not */ -uint8_t _use_freetype = 0; /* Whether we should use freetype or not XXX seriously, how about some flags */ +uint8_t _use_sdf = 1; /* Whether or not to use SDF text rendering */ uint8_t _force_kernel = 0; uint8_t _hold_out = 0; /* state indicator on last cell ignore \n */ uint8_t _free_size = 1; /* Disable rounding when resized */ @@ -136,6 +138,11 @@ static void set_term_font_size(float s) { reinit(1); } +static void set_term_font_gamma(float s) { + font_gamma = s; + reinit(1); +} + /* Returns the lower of two shorts */ int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; @@ -185,35 +192,6 @@ static inline void term_set_point(uint16_t x, uint16_t y, uint32_t color ) { } } -/* FreeType text rendering */ -#if 0 -FT_Library library; -FT_Face face; -FT_Face face_bold; -FT_Face face_italic; -FT_Face face_bold_italic; -FT_Face face_extra; -FT_Face face_symbol; -FT_Face face_variable; - -FT_Face * fallbacks[] = {&face_variable, &face_symbol, &face_extra, &face_symbol, NULL}; - - -void drawChar(FT_Bitmap * bitmap, int x, int y, uint32_t fg, uint32_t bg) { - int i, j, p, q; - int x_max = x + bitmap->width; - int y_max = y + bitmap->rows; - for (j = y, q = 0; j < y_max; j++, q++) { - for ( i = x, p = 0; i < x_max; i++, p++) { - uint32_t a = _ALP(fg); - a = (a * bitmap->buffer[q * bitmap->width + p]) / 255; - uint32_t tmp = rgba(_RED(fg),_GRE(fg),_BLU(fg),a); - term_set_point(i,j, alpha_blend_rgba(premultiply(bg), premultiply(tmp))); - } - } -} -#endif - void draw_semi_block(int c, int x, int y, uint32_t fg, uint32_t bg) { int height; bg = premultiply(bg); @@ -432,87 +410,31 @@ term_write_char( } else { _bg = bg; } - if (_use_freetype) { -#if 0 - if (val == 0xFFFF) { return; } /* Unicode, do not redraw here */ + if (val >= 0x2580 && val <= 0x2588) { for (uint8_t i = 0; i < char_height; ++i) { for (uint8_t j = 0; j < char_width; ++j) { term_set_point(x+j,y+i,premultiply(_bg)); } } - if (flags & ANSI_WIDE) { - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = char_width; j < 2 * char_width; ++j) { - term_set_point(x+j,y+i,premultiply(_bg)); - } + draw_semi_block(val, x, y, _fg, _bg); + goto _extra_stuff; + } + if (val > 128) { + val = ununicode(val); + } + if (_use_sdf) { + char tmp[2] = {val,0}; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + term_set_point(x+j,y+i,premultiply(_bg)); } } - if (val < 32 || val == ' ') { - goto _extra_stuff; - } - if (val >= 0x2580 && val <= 0x2588) { - draw_semi_block(val, x, y, _fg, _bg); - goto _extra_stuff; - } - - int pen_x = x; - int pen_y = y + char_offset; - int error; - - FT_Face * _font = NULL; - FT_GlyphSlot slot; - FT_UInt glyph_index; - - if (flags & ANSI_ALTFONT) { - _font = &face_extra; - } else if (flags & ANSI_BOLD && flags & ANSI_ITALIC) { - _font = &face_bold_italic; - } else if (flags & ANSI_ITALIC) { - _font = &face_italic; - } else if (flags & ANSI_BOLD) { - _font = &face_bold; + if (_no_frame) { + draw_sdf_string_gamma(ctx, x, y, tmp, font_size, _fg, SDF_FONT_MONO, font_gamma); } else { - _font = &face; + draw_sdf_string_gamma(ctx, x+decor_left_width, y+decor_top_height, tmp, font_size, _fg, SDF_FONT_MONO, font_gamma); } - glyph_index = FT_Get_Char_Index(*_font, val); - - if (!glyph_index) { - int i = 0; - while (!glyph_index && fallbacks[i]) { - _font = fallbacks[i]; - glyph_index = FT_Get_Char_Index(*_font, val); - i++; - } - } - error = FT_Load_Glyph(*_font, glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(terminal, "Error loading glyph: %d\n", val); - fprintf(stderr, "Error loading glyph: %d\n", val); - }; - slot = (*_font)->glyph; - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - error = FT_Render_Glyph((*_font)->glyph, FT_RENDER_MODE_NORMAL); - if (error) { - fprintf(stderr, "Error rendering glyph: %d\n", val); - goto _extra_stuff; - } - } - drawChar(&slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top, _fg, _bg); - -#endif } else { - if (val >= 0x2580 && val <= 0x2588) { - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - term_set_point(x+j,y+i,premultiply(_bg)); - } - } - draw_semi_block(val, x, y, _fg, _bg); - goto _extra_stuff; - } - if (val > 128) { - val = ununicode(val); - } #ifdef number_font uint8_t * c = number_font[val]; for (uint8_t i = 0; i < char_height; ++i) { @@ -538,27 +460,14 @@ term_write_char( #endif } _extra_stuff: - if (_use_freetype) { - if (flags & ANSI_UNDERLINE) { - for (uint8_t i = 0; i < char_width; ++i) { - term_set_point(x + i, y + char_offset + 2, _fg); - } + if (flags & ANSI_UNDERLINE) { + for (uint8_t i = 0; i < char_width; ++i) { + term_set_point(x + i, y + char_height - 1, _fg); } - if (flags & ANSI_CROSS) { - for (uint8_t i = 0; i < char_width; ++i) { - term_set_point(x + i, y + char_offset - 5, _fg); - } - } - } else { - if (flags & ANSI_UNDERLINE) { - for (uint8_t i = 0; i < char_width; ++i) { - term_set_point(x + i, y + char_height - 1, _fg); - } - } - if (flags & ANSI_CROSS) { - for (uint8_t i = 0; i < char_width; ++i) { - term_set_point(x + i, y + char_height - 7, _fg); - } + } + if (flags & ANSI_CROSS) { + for (uint8_t i = 0; i < char_width; ++i) { + term_set_point(x + i, y + char_height - 7, _fg); } } if (flags & ANSI_BORDER) { @@ -1305,10 +1214,8 @@ void usage(char * argv[]) { "usage: %s [-b] [-F] [-h]\n" "\n" " -F --fullscreen \033[3mRun in fullscreen (background) mode.\033[0m\n" -#if 0 " -b --bitmap \033[3mUse the integrated bitmap font.\033[0m\n" - " -s --scale \033[3mScale the font in FreeType mode by a given amount.\033[0m\n" -#endif + " -s --scale \033[3mScale the font in SDF mode by a given amount.\033[0m\n" " -h --help \033[3mShow this help message.\033[0m\n" " -x --grid \033[3mMake resizes round to nearest match for character cell size.\033[0m\n" " -n --no-frame \033[3mDisable decorations.\033[0m\n" @@ -1335,35 +1242,19 @@ term_callbacks_t term_callbacks = { term_get_cell_width, term_get_cell_height, term_set_csr_show, + set_term_font_gamma, }; void reinit(int send_sig) { - if (_use_freetype) { -#if 0 - /* Reset font sizes */ - - font_size = 13; - char_height = 17; - char_width = 8; - char_offset = 13; - + if (_use_sdf) { + char_width = 10; + char_height = 18; + font_size = 18; if (scale_fonts) { - /* Recalculate scaling */ font_size *= font_scaling; char_height *= font_scaling; char_width *= font_scaling; - char_offset *= font_scaling; } - - /* Initialize the freetype font pixel sizes */ - FT_Set_Pixel_Sizes(face, font_size, font_size); - FT_Set_Pixel_Sizes(face_bold, font_size, font_size); - FT_Set_Pixel_Sizes(face_italic, font_size, font_size); - FT_Set_Pixel_Sizes(face_bold_italic, font_size, font_size); - FT_Set_Pixel_Sizes(face_extra, font_size, font_size); - FT_Set_Pixel_Sizes(face_symbol, font_size, font_size); - FT_Set_Pixel_Sizes(face_variable, font_size, font_size); -#endif } int old_width = term_width; @@ -1605,7 +1496,6 @@ void maybe_flip_cursor(void) { int main(int argc, char ** argv) { - _use_freetype = 0; _login_shell = 0; _fullscreen = 0; _no_frame = 0; @@ -1615,10 +1505,8 @@ int main(int argc, char ** argv) { static struct option long_opts[] = { {"fullscreen", no_argument, 0, 'F'}, -#if 0 {"bitmap", no_argument, 0, 'b'}, {"scale", required_argument, 0, 's'}, -#endif {"login", no_argument, 0, 'l'}, {"help", no_argument, 0, 'h'}, {"kernel", no_argument, 0, 'k'}, @@ -1654,18 +1542,16 @@ int main(int argc, char ** argv) { _no_frame = 1; break; case 'b': - _use_freetype = 0; + _use_sdf = 0; break; case 'h': usage(argv); return 0; break; -#if 0 case 's': scale_fonts = 1; font_scaling = atof(optarg); break; -#endif case 'g': { char * c = strstr(optarg, "x"); @@ -1717,39 +1603,6 @@ int main(int argc, char ** argv) { yutani_window_move(yctx, window, yctx->display_width / 2 - window->width / 2, yctx->display_height / 2 - window->height / 2); - if (_use_freetype) { -#if 0 - int error; - error = FT_Init_FreeType(&library); - if (error) return 1; - - char * font = NULL; - size_t s; - - /* XXX Use shmemfont library */ - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono.ttf", "monospace", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face); if (error) return 1; - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono-Bold.ttf", "monospace.bold", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_bold); if (error) return 1; - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono-Oblique.ttf", "monospace.italic", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_italic); if (error) return 1; - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono-BoldOblique.ttf", "monospace.bolditalic", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_bold_italic); if (error) return 1; - - error = FT_New_Face(library, "/usr/share/fonts/VLGothic.ttf", 0, &face_extra); - - error = FT_New_Face(library, "/usr/share/fonts/Symbola.ttf", 0, &face_symbol); - - font = loadMemFont("/usr/share/fonts/DejaVuSans.ttf", "sans-serif", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_variable); if (error) return 1; - -#endif - } - syscall_openpty(&fd_master, &fd_slave, NULL, NULL, NULL); terminal = fdopen(fd_slave, "w"); diff --git a/base/usr/include/toaru/sdf.h b/base/usr/include/toaru/sdf.h index 0be34b58..532c5b9b 100644 --- a/base/usr/include/toaru/sdf.h +++ b/base/usr/include/toaru/sdf.h @@ -3,7 +3,9 @@ enum sdf_font { SDF_FONT_THIN, SDF_FONT_BOLD, + SDF_FONT_MONO, }; extern int draw_sdf_string(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font); extern int draw_sdf_string_width(const char * str, int size, int font); +extern int draw_sdf_string_gamma(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font, double _gamma); diff --git a/base/usr/include/toaru/termemu.h b/base/usr/include/toaru/termemu.h index 7e37469c..b30946a5 100644 --- a/base/usr/include/toaru/termemu.h +++ b/base/usr/include/toaru/termemu.h @@ -33,6 +33,7 @@ typedef struct { int (*get_cell_width)(void); int (*get_cell_height)(void); void (*set_csr_on)(int); + void (*set_font_gamma)(float); } term_callbacks_t; typedef struct { diff --git a/base/usr/share/sdf_bold.bmp b/base/usr/share/sdf_bold.bmp index d008fdd6..bc08a8f0 100644 Binary files a/base/usr/share/sdf_bold.bmp and b/base/usr/share/sdf_bold.bmp differ diff --git a/base/usr/share/sdf_mono.bmp b/base/usr/share/sdf_mono.bmp new file mode 100644 index 00000000..b13c27b2 Binary files /dev/null and b/base/usr/share/sdf_mono.bmp differ diff --git a/base/usr/share/sdf_thin.bmp b/base/usr/share/sdf_thin.bmp index 9dff6509..3d959b50 100644 Binary files a/base/usr/share/sdf_thin.bmp and b/base/usr/share/sdf_thin.bmp differ diff --git a/lib/sdf.c b/lib/sdf.c index 2e1c7f5b..dece30ce 100644 --- a/lib/sdf.c +++ b/lib/sdf.c @@ -13,128 +13,28 @@ #define BASE_WIDTH 50 #define BASE_HEIGHT 50 -#define GAMMA 1.7 static sprite_t _font_data_thin; static sprite_t _font_data_bold; +static sprite_t _font_data_mono; static hashmap_t * _font_cache; static volatile int _sdf_lock = 0; +static double gamma = 1.7; struct CharData{ char code; size_t width_bold; size_t width_thin; -} _char_data[] = { - {'!', 20, 20}, - {'"', 35, 20}, - {'#', 40, 20}, - {'$', 35, 20}, - {'%', 35, 20}, - {'&', 35, 20}, - {'\'', 35, 20}, - {'(', 22, 20}, - {')', 22, 20}, - {'*', 35, 20}, - {'+', 35, 20}, - {',', 35, 20}, - {'-', 30, 20}, - {'.', 18, 20}, - {'/', 24, 20}, - {'0', 32, 20}, - {'1', 32, 20}, - {'2', 32, 20}, - {'3', 32, 20}, - {'4', 32, 20}, - {'5', 32, 20}, - {'6', 32, 20}, - {'7', 32, 20}, - {'8', 32, 20}, - {'9', 32, 20}, - {':', 22, 20}, - {';', 22, 20}, - {'<', 35, 20}, - {'=', 35, 20}, - {'>', 35, 20}, - {'?', 35, 20}, - {'@', 50, 20}, - {'A', 35, 20}, - {'B', 35, 20}, - {'C', 34, 20}, - {'D', 36, 20}, - {'E', 34, 20}, - {'F', 34, 20}, - {'G', 35, 20}, - {'H', 35, 20}, - {'I', 22, 20}, - {'J', 24, 20}, - {'K', 35, 20}, - {'L', 32, 20}, - {'M', 45, 20}, - {'N', 36, 20}, - {'O', 38, 20}, - {'P', 35, 20}, - {'Q', 38, 20}, - {'R', 36, 20}, - {'S', 35, 20}, - {'T', 35, 20}, - {'U', 35, 20}, - {'V', 37, 20}, - {'W', 50, 20}, - {'X', 35, 20}, - {'Y', 32, 20}, - {'Z', 35, 20}, - {'[', 35, 20}, - {'\\', 35, 20}, - {']', 35, 20}, - {'^', 35, 20}, - {'_', 35, 20}, - {'`', 35, 20}, - {'a', 32, 20}, - {'b', 32, 20}, - {'c', 29, 20}, - {'d', 32, 20}, - {'e', 32, 20}, - {'f', 25, 20}, - {'g', 32, 20}, - {'h', 32, 20}, - {'i', 16, 20}, - {'j', 16, 20}, - {'k', 30, 20}, - {'l', 16, 20}, - {'m', 47, 20}, - {'n', 33, 20}, - {'o', 32, 20}, - {'p', 32, 20}, - {'q', 32, 20}, - {'r', 25, 20}, - {'s', 31, 20}, - {'t', 26, 20}, - {'u', 32, 20}, - {'v', 32, 20}, - {'w', 42, 20}, - {'x', 32, 20}, - {'y', 32, 20}, - {'z', 32, 20}, - {'{', 32, 20}, - {'|', 32, 20}, - {'}', 32, 20}, - {'~', 32, 20}, - {' ', 20, 20}, - {0,0,0}, -}; + size_t width_mono; +} _char_data[256]; static int loaded = 0; static int offset(int ch) { /* Calculate offset into table above */ - if (ch == ' ') { - return '~' + 1 - '!'; - } else { - return ch - '!'; - } - + return ch; } __attribute__((constructor)) @@ -143,9 +43,16 @@ static void _init_sdf(void) { _font_cache = hashmap_create_int(10); load_sprite(&_font_data_thin, "/usr/share/sdf_thin.bmp"); load_sprite(&_font_data_bold, "/usr/share/sdf_bold.bmp"); + load_sprite(&_font_data_mono, "/usr/share/sdf_mono.bmp"); FILE * fi = fopen("/etc/sdf.conf", "r"); char tmp[1024]; char * s = tmp; + for (int i = 0; i < 256; ++i) { + _char_data[i].code = i; + _char_data[i].width_bold = 25; + _char_data[i].width_thin = 20; + _char_data[i].width_mono = 25; + } while ((s = fgets(tmp, 1024, fi))) { if (strlen(s) < 1) continue; int i = offset(*s); @@ -157,6 +64,8 @@ static void _init_sdf(void) { _char_data[i].width_bold = o; } else if (t == 't') { _char_data[i].width_thin = o; + } else if (t == 'm') { + _char_data[i].width_mono = o; } } fclose(fi); @@ -167,6 +76,8 @@ static sprite_t * _select_font(int font) { switch (font) { case SDF_FONT_BOLD: return &_font_data_bold; + case SDF_FONT_MONO: + return &_font_data_mono; case SDF_FONT_THIN: default: return &_font_data_thin; @@ -177,6 +88,8 @@ static int _select_width(char ch, int font) { switch (font) { case SDF_FONT_BOLD: return _char_data[(int)ch].width_bold; + case SDF_FONT_MONO: + return _char_data[(int)ch].width_mono; case SDF_FONT_THIN: default: return _char_data[(int)ch].width_thin; @@ -184,17 +97,7 @@ static int _select_width(char ch, int font) { } static int draw_sdf_character(gfx_context_t * ctx, int32_t x, int32_t y, int ch, int size, uint32_t color, sprite_t * tmp, int font, sprite_t * _font_data) { - if (ch != ' ' && (ch < '!' || ch > '~')) { - /* TODO: Draw missing symbol? */ - return 0; - } - - /* Calculate offset into table above */ - if (ch == ' ') { - ch = '~' + 1 - '!'; - } else { - ch -= '!'; - } + if (ch < 0 || ch > 255) return 0; double scale = (double)size / 50.0; int width = _select_width(ch, font) * scale; @@ -212,8 +115,8 @@ static int draw_sdf_character(gfx_context_t * ctx, int32_t x, int32_t y, int ch, if (fy+j > tmp->height) continue; uint32_t c = SPRITE((tmp), fx+i, fy+j); double dist = (double)_RED(c) / 255.0; - double edge0 = 0.75 - GAMMA * 1.4142 / (double)size; - double edge1 = 0.75 + GAMMA * 1.4142 / (double)size; + double edge0 = 0.75 - gamma * 1.4142 / (double)size; + double edge1 = 0.75 + gamma * 1.4142 / (double)size; double a = (dist - edge0) / (edge1 - edge0); if (a < 0.0) a = 0.0; if (a > 1.0) a = 1.0; @@ -226,7 +129,7 @@ static int draw_sdf_character(gfx_context_t * ctx, int32_t x, int32_t y, int ch, } -int draw_sdf_string(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font) { +int draw_sdf_string_gamma(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font, double _gamma) { sprite_t * _font_data = _select_font(font); @@ -246,32 +149,26 @@ int draw_sdf_string(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, } else { tmp = hashmap_get(_font_cache, (void *)(scale_height | (font << 16))); } - spin_unlock(&_sdf_lock); int32_t out_width = 0; + gamma = _gamma; while (*str) { - int w = draw_sdf_character(ctx,x,y,*str,size,color,tmp,font,_font_data); + int w = draw_sdf_character(ctx,x,y,*((uint8_t *)str),size,color,tmp,font,_font_data); out_width += w; x += w; str++; } + spin_unlock(&_sdf_lock); return out_width; } + +int draw_sdf_string(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font) { + return draw_sdf_string_gamma(ctx,x,y,str,size,color,font,1.7); +} + static int char_width(char ch, int font) { - if (ch != ' ' && (ch < '!' || ch > '~')) { - /* TODO: Draw missing symbol? */ - return 0; - } - - /* Calculate offset into table above */ - if (ch == ' ') { - ch = '~' + 1 - '!'; - } else { - ch -= '!'; - } - return _select_width(ch, font); } diff --git a/lib/termemu.c b/lib/termemu.c index 94774561..e47067c4 100644 --- a/lib/termemu.c +++ b/lib/termemu.c @@ -180,13 +180,16 @@ static void _ansi_put(term_state_t * s, char c) { case 1: callbacks->redraw_cursor(); break; -#if 0 case 1555: if (argc > 1) { callbacks->set_font_size(atof(argv[1])); } break; -#endif + case 1556: + if (argc > 1) { + callbacks->set_font_gamma(atof(argv[1])); + } + break; default: break; }