📄 text.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / 2D rendering module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "stacks2d.h"#include "visualsurface2d.h"#include <gpac/utf.h>#include <gpac/options.h>/*default value when no fontStyle*/#define FSFAMILY (fs && fs->family.count) ? (const char *)fs->family.vals[0] : ""/*here it's tricky since it depends on our metric system...*/#define FSSIZE (fs ? fs->size : -1)#define FSSTYLE (fs && fs->style.buffer) ? (const char *)fs->style.buffer : ""#define FSMAJOR ( (fs && fs->justify.count && fs->justify.vals[0]) ? (const char *)fs->justify.vals[0] : "FIRST")#define FSMINOR ( (fs && (fs->justify.count>1) && fs->justify.vals[1]) ? (const char *)fs->justify.vals[1] : "FIRST")#define FSHORIZ (fs ? fs->horizontal : 1)#define FSLTR (fs ? fs->leftToRight : 1)#define FSTTB (fs ? fs->topToBottom : 1)#define FSLANG (fs ? fs->language : "")#define FSSPACE (fs ? fs->spacing : 1)void text2D_get_ascent_descent(DrawableContext *ctx, Fixed *a, Fixed *d){ TextStack2D *stack = (TextStack2D *) gf_node_get_private(ctx->drawable->node); *a = stack->ascent; *d = stack->descent;}typedef struct{ /*regular drawing*/ GF_Path *path; GF_Rect bounds; /*texture drawing*/ GF_HWTEXTURE hwtx; Render2D *sr; GF_Path *tx_path; Bool tx_ready; /*take only into account the window-scaling zoom, not any navigation one (would be too big)*/ SFVec2f last_scale; GF_Rect tx_bounds; Bool failed;} TextLineEntry2D;TextLineEntry2D *NewTextLine2D(Render2D *sr){ TextLineEntry2D *tl; GF_SAFEALLOC(tl, TextLineEntry2D); tl->path = gf_path_new(); /*text texturing enabled*/ tl->sr = sr; tl->last_scale.x = sr->scale_x; tl->last_scale.y = sr->scale_y; return tl;}void TextLine_StoreBounds(TextLineEntry2D *tl){ gf_path_get_bounds(tl->path, &tl->bounds);}Bool TextLine2D_TextureIsReady(TextLineEntry2D *tl){ GF_Matrix2D mx; GF_STENCIL stenc; GF_SURFACE surf; Fixed cx, cy; u32 width, height; Fixed scale, max; GF_Err e; GF_Raster2D *r2d = tl->sr->compositor->r2d; /*something failed*/ if (tl->failed) return 0; if (!tl->hwtx) tl->hwtx = r2d->stencil_new(r2d, GF_STENCIL_TEXTURE); if (tl->tx_ready) { if ((tl->last_scale.x == tl->sr->scale_x) && (tl->last_scale.y == tl->sr->scale_y) ) return 1; if (tl->hwtx) r2d->stencil_delete(tl->hwtx); if (tl->tx_path) gf_path_del(tl->tx_path); tl->tx_path = NULL; tl->hwtx = r2d->stencil_new(r2d, GF_STENCIL_TEXTURE); tl->last_scale.x = tl->sr->scale_x; tl->last_scale.y = tl->sr->scale_y; } max = INT2FIX(512); scale = MAX(tl->last_scale.x, tl->last_scale.y); if ((gf_mulfix(scale, tl->bounds.width)>max) || (gf_mulfix(scale, tl->bounds.height)>max)) { scale = MIN(gf_divfix(max, tl->bounds.width), gf_divfix(max, tl->bounds.height)); } if (scale<FIX_ONE) scale = FIX_ONE; width = FIX2INT(gf_ceil(gf_mulfix(scale, tl->bounds.width))); height = FIX2INT(gf_ceil(gf_mulfix(scale, tl->bounds.height))); width += 1; height += 1; surf = r2d->surface_new(r2d, 1); if (!surf) { r2d->stencil_delete(tl->hwtx); tl->hwtx = NULL; tl->failed = 1; return 0; } /*FIXME - make it work with alphagrey...*/ e = r2d->stencil_create_texture(tl->hwtx, width, height, GF_PIXEL_ARGB); if (!e) e = r2d->surface_attach_to_texture(surf, tl->hwtx); r2d->surface_clear(surf, NULL, 0); stenc = r2d->stencil_new(r2d, GF_STENCIL_SOLID); r2d->stencil_set_brush_color(stenc, 0xFF000000);// cx = (tl->path->max_x + tl->path->min_x) / 2; // cy = (tl->path->max_y + tl->path->min_y) / 2; cx = tl->bounds.x + tl->bounds.width/2; cy = tl->bounds.y - tl->bounds.height/2; gf_mx2d_init(mx); gf_mx2d_add_translation(&mx, -cx, -cy); gf_mx2d_add_scale(&mx, scale, scale); gf_mx2d_add_translation(&mx, FIX_ONE/3, FIX_ONE/3); r2d->surface_set_matrix(surf, &mx); r2d->surface_set_raster_level(surf, GF_RASTER_HIGH_QUALITY); r2d->surface_set_path(surf, tl->path); r2d->surface_fill(surf, stenc); r2d->stencil_delete(stenc); r2d->surface_delete(surf); tl->tx_path = gf_path_new(); gf_path_add_move_to(tl->tx_path, tl->bounds.x, tl->bounds.y-tl->bounds.height); gf_path_add_line_to(tl->tx_path, tl->bounds.x+tl->bounds.width, tl->bounds.y-tl->bounds.height); gf_path_add_line_to(tl->tx_path, tl->bounds.x+tl->bounds.width, tl->bounds.y); gf_path_add_line_to(tl->tx_path, tl->bounds.x, tl->bounds.y); gf_path_close(tl->tx_path); tl->tx_bounds.x = tl->tx_bounds.y = 0; tl->tx_bounds.width = INT2FIX(width); tl->tx_bounds.height = INT2FIX(height); if (e) { r2d->stencil_delete(tl->hwtx); tl->hwtx = NULL; tl->failed = 1; return 0; } tl->tx_ready = 1; return 1;}void TextStack2D_clean_paths(TextStack2D *stack){ TextLineEntry2D *tl; /*delete all path objects*/ while (gf_list_count(stack->text_lines)) { tl = (TextLineEntry2D *) gf_list_get(stack->text_lines, 0); gf_list_rem(stack->text_lines, 0); if (tl->path) gf_path_del(tl->path); if (tl->hwtx) tl->sr->compositor->r2d->stencil_delete(tl->hwtx); if (tl->tx_path) gf_path_del(tl->tx_path); free(tl); } gf_rect_reset(&stack->bounds); drawable_reset_path(stack->graph);}static void split_text_letters(TextStack2D *st, M_Text *txt, RenderEffect2D *eff){ unsigned short wcTemp[5000]; unsigned short letter[2]; DrawableContext *ctx; TextLineEntry2D *tl; u32 i, j, len; Fixed fontSize, start_y, font_height, line_spacing; GF_Rect rc, bounds; GF_FontRaster *ft_dr = eff->surface->render->compositor->font_engine; M_FontStyle *fs = (M_FontStyle *)txt->fontStyle; fontSize = FSSIZE; if (fontSize <= 0) { fontSize = INT2FIX(12); if (!R2D_IsPixelMetrics((GF_Node *)txt)) fontSize = gf_divfix(fontSize, eff->surface->render->cur_width); } line_spacing = gf_mulfix(FSSPACE, fontSize); if (ft_dr->set_font(ft_dr, FSFAMILY, FSSTYLE) != GF_OK) { if (ft_dr->set_font(ft_dr, NULL, NULL) != GF_OK) { return; } } ft_dr->set_font_size(ft_dr, fontSize); ft_dr->get_font_metrics(ft_dr, &st->ascent, &st->descent, &font_height); if (!strcmp(FSMINOR, "MIDDLE")) { start_y = (st->descent + st->ascent)/2; } else if (!strcmp(FSMINOR, "BEGIN")) { start_y = st->descent; } else if (!strcmp(FSMINOR, "END")) { start_y = st->descent + st->ascent; } else { start_y = st->ascent; } gf_rect_reset(&st->bounds); for (i=0; i < txt->string.count; i++) { char *str = txt->string.vals[i]; if (!str) continue; len = gf_utf8_mbstowcs(wcTemp, 5000, (const char **) &str); if (len == (size_t) (-1)) continue; letter[1] = (unsigned short) 0; for (j=0; j<len; j++) { if (FSLTR) { letter[0] = wcTemp[j]; } else { letter[0] = wcTemp[len - j - 1]; } /*request a context (first one is always valid when entering render)*/ if (j) group2d_start_child(eff->parent); ctx = drawable_init_context(st->graph, eff); if (!ctx) return; ctx->flags |= CTX_IS_TEXT; tl = NewTextLine2D(eff->surface->render); gf_list_add(st->text_lines, tl); ctx->sub_path_index = gf_list_count(st->text_lines); ft_dr->add_text_to_path(ft_dr, tl->path, 1, letter, 0, start_y, FIX_ONE, FIX_ONE, st->ascent, &rc); bounds.width = rc.width; bounds.x = rc.x; bounds.height = MAX(st->ascent + st->descent, rc.height); bounds.y = start_y; TextLine_StoreBounds(tl); drawable_finalize_render(ctx, eff, &bounds); group2d_end_child(eff->parent); } }}static void split_text_words(TextStack2D *st, M_Text *txt, RenderEffect2D *eff){ unsigned short wcTemp[5000]; unsigned short letter[5000]; DrawableContext *ctx; TextLineEntry2D *tl; u32 i, j, len, k, first_char; Fixed fontSize, font_height, line_spacing; GF_Rect rc, bounds; GF_FontRaster *ft_dr = eff->surface->render->compositor->font_engine; M_FontStyle *fs = (M_FontStyle *)txt->fontStyle; fontSize = FSSIZE; if (fontSize <= 0) { fontSize = INT2FIX(12); if (!R2D_IsPixelMetrics((GF_Node *)txt)) fontSize = gf_divfix(fontSize, eff->surface->render->cur_width); } line_spacing = gf_mulfix(FSSPACE, fontSize); if (ft_dr->set_font(ft_dr, FSFAMILY, FSSTYLE) != GF_OK) { if (ft_dr->set_font(ft_dr, NULL, NULL) != GF_OK) { return; } } ft_dr->set_font_size(ft_dr, fontSize); ft_dr->get_font_metrics(ft_dr, &st->ascent, &st->descent, &font_height); gf_rect_reset(&st->bounds); for (i=0; i < txt->string.count; i++) { char *str = txt->string.vals[i]; if (!str) continue; len = gf_utf8_mbstowcs(wcTemp, 5000, (const char **) &str); if (len == (size_t) (-1)) continue; first_char = 0; for (j=0; j<len; j++) { /*we currently only split sentences at spaces*/ if ((j+1!=len) && (wcTemp[j] != (unsigned short) ' ')) continue; if (FSLTR) { for (k=0; k<=j - first_char; k++) letter[k] = wcTemp[first_char+k]; } else { for (k=0; k<=j - first_char; k++) letter[k] = wcTemp[len - first_char - k - 1]; } letter[k] = (unsigned short) 0; /*request a context (first one is always valid when entering render)*/ if (first_char) group2d_start_child(eff->parent); ctx = drawable_init_context(st->graph, eff); if (!ctx) return; ctx->flags |= CTX_IS_TEXT; tl = NewTextLine2D(eff->surface->render); gf_list_add(st->text_lines, tl); ctx->sub_path_index = gf_list_count(st->text_lines); /*word splitting only happen in layout, so we don't need top/left anchors*/ ft_dr->add_text_to_path(ft_dr, tl->path, 1, letter, 0, 0, FIX_ONE, FIX_ONE, st->ascent, &rc); bounds.width = rc.width; bounds.height = st->ascent + st->descent; bounds.x = bounds.y = 0; tl->bounds = bounds; drawable_finalize_render(ctx, eff, &bounds); group2d_end_child(eff->parent); first_char = j+1; } }}/*for vert and horiz text*/typedef struct{ unsigned short *wcText; u32 length; Fixed width, height; Fixed x_scaling, y_scaling;} TextLine2D;static void BuildVerticalTextGraph(TextStack2D *st, M_Text *txt, RenderEffect2D *eff){ TextLine2D *lines; unsigned short wcTemp[5000]; u32 i, int_major, len, k; Fixed fontSize, start_x, start_y, space, line_spacing, tot_width, tot_height, max_scale, tmp; GF_Rect rc, final; Fixed lw, lh, max_lw; unsigned short letter[2]; GF_FontRaster *ft_dr = eff->surface->render->compositor->font_engine; M_FontStyle *fs = (M_FontStyle *)txt->fontStyle; fontSize = FSSIZE; if (fontSize <= 0) { fontSize = INT2FIX(12); if (!R2D_IsPixelMetrics((GF_Node *)txt)) fontSize = gf_divfix(fontSize, eff->surface->render->cur_width); } line_spacing = gf_mulfix(FSSPACE, fontSize); if (ft_dr->set_font(ft_dr, FSFAMILY, FSSTYLE) != GF_OK) { if (ft_dr->set_font(ft_dr, NULL, NULL) != GF_OK) { return; } } ft_dr->set_font_size(ft_dr, fontSize); ft_dr->get_font_metrics(ft_dr, &st->ascent, &st->descent, &space); /*compute overall bounding box size*/ tot_width = 0; tot_height = 0; lines = (TextLine2D *) malloc(sizeof(TextLine2D)*txt->string.count); memset(lines, 0, sizeof(TextLine2D)*txt->string.count); letter[1] = (unsigned short) '\0';/* space = st->ascent + st->descent; space = fontSize - st->ascent + st->descent;*/ for (i=0; i < txt->string.count; i++) { char *str = txt->string.vals[i]; if (!str) continue; lines[i].length = 0; len = gf_utf8_mbstowcs(wcTemp, 5000, (const char **) &str); if (len == (size_t) (-1)) continue; lines[i].wcText = (u16*)malloc(sizeof(unsigned short) * len); memcpy(lines[i].wcText, wcTemp, sizeof(unsigned short) * len); lines[i].length = len; lines[i].y_scaling = lines[i].x_scaling = FIX_ONE; lines[i].height = len * space; if (!lines[i].height) continue; if ((txt->length.count>i) && (txt->length.vals[i]>0) ) lines[i].y_scaling = gf_divfix(txt->length.vals[i], lines[i].height); tmp = gf_mulfix(lines[i].height, lines[i].y_scaling); if (tot_height < tmp) tot_height = tmp; } tot_width = txt->string.count * line_spacing; st->bounds.width = tot_width; max_scale = FIX_ONE; if ((txt->maxExtent>0) && (tot_height>txt->maxExtent)) { max_scale = gf_divfix(txt->maxExtent, tot_height); tot_height = txt->maxExtent; } if (!strcmp(FSMINOR, "MIDDLE")) { if (FSLTR) { start_x = -tot_width/2; st->bounds.x = start_x; } else { start_x = tot_width/2 - line_spacing; st->bounds.x = - tot_width + line_spacing; } } else if (!strcmp(FSMINOR, "END")) { if (FSLTR) { start_x = -tot_width; st->bounds.x = start_x; } else { start_x = tot_width-line_spacing; st->bounds.x = 0; } } else { if (FSLTR) { start_x = 0; st->bounds.x = start_x; } else { start_x = -line_spacing; st->bounds.x = -tot_width; } } if (!strcmp(FSMAJOR, "MIDDLE")) { int_major = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -