/** * Tells whether a line break can occur between two Unicode characters. * This is a wrapper function to expose a simple interface. Generally * speaking, it is better to use #set_linebreaks_utf32 instead, since * complicated cases involving combining marks, spaces, etc. cannot be * correctly processed. * * @param char1 the first Unicode character * @param char2 the second Unicode character * @param lang language of the input * @return one of #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK, * #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR */ int is_line_breakable( utf32_t char1, utf32_t char2, const char* lang) { utf32_t s[2]; char brks[2]; s[0] = char1; s[1] = char2; set_linebreaks_utf32(s, 2, lang, brks); return brks[0]; }
/* *func:计算给定字符串text 在给定宽度内以自动断行的方式 * 能输出多少行,并返回每一行的指针 *gc[IN]:字符输出的系统环境 *width[IN]:给定宽度 *lang[IN]:文本本地化代码标志 *text[IN]:给定字符串 *len[IN]:给定字符串的字节长 *max_line[IN]:给定的最大可输出行数,即line_len的数组大小,防止越界,请注意不能小于2 *line_from[IN,OUT]:需要外部分配内存后传入,用于返回各行的字符串在 给定字符串text :中的索引,若为NULL,表示 不需要返回字节长度 *line_len[IN,OUT]:需要外部分配内存后传入,用于返回各行的字符串字节长度 :若为NULL,表示 不需要返回字节长度 *line_width[IN,OUT]:用于返回各行的字符串输出的实际宽度, 需要外部分配提供,大小同line_len,如果为NULL,表示不需要返回宽度 *返回:能输出的行数,-1为出错 *常用用法:1 . 获取字符串能输出的行数 lines = utf32GetTextExWordBreakLines(gc,screenwidth,lang,pStr,strlen(pStr),100,NULL,NULL,NULL); 2 . 获取字符串能输出的行数及各行的信息(长度、位置) int *line_from = malloc(100); int *line_len = malloc(100); lines = utf32GetTextExWordBreakLines(gc,screenwidth,lang,pStr,strlen(pStr),100,line_from,line_len,NULL); for(i=0;i<lines;i++) drawText(gc,pStr+line_from[i],line_len[i]); */ int utf32GetTextExWordBreakLines(GR_GC_ID gc, GR_SIZE width,const char* lang, const char *text, size_t len, int max_line,int line_from[],int line_len[],int line_width[]) { GR_SIZE w, h, b; GR_SIZE last_w;//当前字符宽度超过给定宽度时,用于回退到上一次小于给定宽度时的宽度 char *brks;//保存各字节能否break的信息 int i; int line_start;//每行行首所在(相对于整个字符串) int last_word;//上一次字符串宽度小于给定宽度时的那个字符所在 int line_count = 0;//可输出行数 int word_locate; int wordcount = len/4;//字符个数 const char *text_lang; NxGetGCTextSize(gc, text, len, MWTF_UC32, &w, &h, &b); if (w <= width) {//不够输出一行 if(line_len){ line_len[line_count] = len; } if(line_from){ line_from[line_count] = 0; } if(line_width){ line_width[line_count] = w; } line_count = 1; return line_count; } brks = app_malloc(wordcount); if (brks == NULL) return -1; text_lang = get_text_lang(UTF32LE, text, len); /* Show the breaking points */ set_linebreaks_utf32(text, wordcount, text_lang, brks); line_start = 0; last_word = 0; for (i = 1; i <= wordcount; i++) { switch (brks[i-1]) { case LINEBREAK_MUSTBREAK: case LINEBREAK_ALLOWBREAK: NxGetGCTextSize(gc, text + 4*line_start, 4*(i - line_start), MWTF_UC32, &w, &h, &b); if (w > width) { if (last_word > line_start) { if (w - last_w > width) { int partial_len; GR_SIZE partial_w; partial_len = locate_word_to_fit(gc, width - last_w, text + 4*last_word, 4*(i - last_word), &partial_w); partial_len /= 4; last_word += partial_len; last_w += partial_w; } if(line_len){ line_len[line_count] = 4*(last_word - line_start); } if(line_from){ line_from[line_count] = 4*(line_start); } if(line_width){ line_width[line_count] = last_w; } line_count++; line_start = last_word; w = w - last_w; if(line_count>=max_line){ app_free(brks); return line_count; } } /* too long word */ while (w > width) { word_locate = locate_word_to_fit(gc, width, text + 4*line_start, 4*(i - line_start), &last_w); word_locate /= 4; if(line_len){ line_len[line_count] = 4*word_locate;//locate_word_to_fit(gc, width, text + line_start, i - line_start, &last_w); } if(line_from){ line_from[line_count] = 4*line_start; } if(line_width){ line_width[line_count] = last_w; } line_start += word_locate; line_count++; w = w - last_w; if(line_count>=max_line){ app_free(brks); return line_count; } } } if (brks[i-1] == LINEBREAK_MUSTBREAK || w == width) { if(line_len){ line_len[line_count] = 4*(i - line_start); } if(line_from){ line_from[line_count] = 4*(line_start); } if(line_width){ line_width[line_count] = w; } line_count++; line_start = i; last_word = line_start; last_w = 0; if(line_count>=max_line){ app_free(brks); return line_count; } } else { last_word = i; last_w = w; } break; } } if (line_start < wordcount) { if(line_count>=max_line){ app_free(brks); return line_count; } if(line_len){ line_len[line_count] = 4*(wordcount - line_start); } if(line_from){ line_from[line_count] = 4*line_start; } if(line_width){ line_width[line_count] = w; } line_count++; } app_free(brks); return line_count; }
int dsShow_parse_lines(DaisyShow *thiz, utf32_t *text, int size) { char *brks; int skip = MAX_SHOW_LEN / thiz->font_size; int width, byte_len,ch_len; int brk_index; //int count; int cal_width; // size_t in_ret, out_ret; // gchar *p, *q; // char dbg_info[1024]; int line_idx = 0; size_t i, start; utf32_t *line_start; size_t line_len; enum _State { STAT_INIT, STAT_IN_LINE, STAT_OUT_LINE, }state = STAT_INIT; DBGMSG("size=%d\n", size); thiz->total_line = 0; thiz->show_line = 0; if(size <=0){ return -1; } brks = (char *)malloc(size); set_linebreaks_utf32((const utf32_t *)text, size, "zh", brks); start = 0; brk_index = -1; i = 0; while(i < size){ if(brks[i] != LINEBREAK_NOBREAK){ brk_index = i; } switch(state){ case STAT_INIT: { if(text[i] == 0xA){ state = STAT_OUT_LINE; } else{ state = STAT_IN_LINE; } } break; case STAT_IN_LINE: { if(text[i] == 0xA){ state = STAT_OUT_LINE; thiz->show_text[line_idx] = (char*)text+start; thiz->show_txtlen[line_idx] = (i - start)*4; line_idx++; start = i+1; /*skip 0xA*/ brk_index = -1; break; } //ch_len = count; ch_len = (i - start+1); if(ch_len <= skip){ break; } byte_len = (i - start+1)*4; //info_err("byte_len=%d\n", byte_len); width = cal_text_len(thiz,(char*)(text+start), byte_len); cal_width = MAX_SHOW_LEN; //info_err("width=%d, cal with=%d\n", width, cal_width); if(width <= cal_width){ break; } state = STAT_OUT_LINE; line_start = text+start; if(brk_index > 0){ line_len = brk_index - start; start = brk_index; brk_index = -1; //DBGMSG("i =%d, start=%d\n", i, start); } else{ DBGMSG("force line break\n"); line_len = i - start; start = i; } if(brks[i] != LINEBREAK_NOBREAK){ brk_index = i; } thiz->show_text[line_idx] = (char*)line_start; thiz->show_txtlen[line_idx] = line_len*4; line_idx++; state = STAT_IN_LINE; /*because i*/ } break; case STAT_OUT_LINE: { if(text[i] == 0xA){ state = STAT_OUT_LINE; /*empty new line*/ line_start = text+start; line_len = 0; start = i+1; /*skip 0xA*/ brk_index = -1; thiz->show_text[line_idx] = (char*)line_start; thiz->show_txtlen[line_idx] = line_len*4; line_idx++; } else{ state = STAT_IN_LINE; } } break; default:break; } i++; if(line_idx>=MAX_SHOW_LINE){ info_err("so much lines\n"); break; } } free(brks); if((start < size) && (line_idx<MAX_SHOW_LINE)){ line_start = text+start; line_len = size - start; brk_index = -1; thiz->show_text[line_idx] = (char*)line_start; thiz->show_txtlen[line_idx] = line_len*4; line_idx++; } thiz->total_line = line_idx; thiz->start_line = 0; if(thiz->screen_line < thiz->total_line){ thiz->show_line = thiz->screen_line; } else{ thiz->show_line = thiz->total_line; } /*fill show lines*/ DBGMSG("parse end\n"); return 0; }