static void draw_text (DiaRenderer *self, Text *text) { DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self); Point pos = text->position; int i; xmlNodePtr node_text, node_tspan; gchar d_buf[G_ASCII_DTOSTR_BUF_SIZE]; node_text = xmlNewChild(renderer->root, renderer->svg_name_space, (const xmlChar *)"text", NULL); /* text 'global' properties */ node_set_text_style(node_text, renderer, text->font, text->height, text->alignment, &text->color); dia_svg_dtostr(d_buf, pos.x); xmlSetProp(node_text, (const xmlChar *)"x", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, pos.y); xmlSetProp(node_text, (const xmlChar *)"y", (xmlChar *) d_buf); pos = text->position; for (i=0;i<text->numlines;i++) { TextLine *text_line = text->lines[i]; node_tspan = xmlNewTextChild(node_text, renderer->svg_name_space, (const xmlChar *)"tspan", (const xmlChar *)text_line_get_string(text_line)); dia_svg_dtostr(d_buf, pos.x); xmlSetProp(node_tspan, (const xmlChar *)"x", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, pos.y); xmlSetProp(node_tspan, (const xmlChar *)"y", (xmlChar *) d_buf); pos.y += text->height; } }
static void draw_text_line(DiaRenderer *self, TextLine *text_line, Point *pos, Alignment alignment, Color *colour) { DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self); xmlNodePtr node; char *style, *tmp; real saved_width; gchar d_buf[DTOSTR_BUF_SIZE]; DiaFont *font; node = xmlNewTextChild(renderer->root, renderer->svg_name_space, (const xmlChar *)"text", (xmlChar *) text_line_get_string(text_line)); saved_width = renderer->linewidth; renderer->linewidth = 0.001; style = (char*)get_fill_style(renderer, colour); /* return value must not be freed */ renderer->linewidth = saved_width; tmp = g_strdup_printf("%s; font-size: %s", style, dia_svg_dtostr(d_buf, text_line_get_height(text_line))); style = tmp; /* This is going to break for non-LTR texts, as SVG thinks 'start' is * 'right' for those. */ switch (alignment) { case ALIGN_LEFT: tmp = g_strconcat(style, "; text-anchor:start", NULL); break; case ALIGN_CENTER: tmp = g_strconcat(style, "; text-anchor:middle", NULL); break; case ALIGN_RIGHT: tmp = g_strconcat(style, "; text-anchor:end", NULL); break; } g_free (style); style = tmp; font = text_line_get_font(text_line); tmp = g_strdup_printf("%s; font-family: %s; font-style: %s; " "font-weight: %s",style, dia_font_get_family(font), dia_font_get_slant_string(font), dia_font_get_weight_string(font)); g_free(style); style = tmp; /* have to do something about fonts here ... */ xmlSetProp(node, (const xmlChar *)"style", (xmlChar *) style); g_free(style); dia_svg_dtostr(d_buf, pos->x); xmlSetProp(node, (const xmlChar *)"x", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, pos->y); xmlSetProp(node, (const xmlChar *)"y", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, text_line_get_width(text_line)); xmlSetProp(node, (const xmlChar*)"textLength", (xmlChar *) d_buf); }
static void text_move_cursor(Text *text, CursorMovement mv) { gchar *str = text_line_get_string(text->lines[text->cursor_row]); gchar *p = str; int curmax = text_get_line_strlen(text, text->cursor_row); if (text->cursor_pos > 0 && text->cursor_pos <= curmax) { int i; for (i = 0; i < text->cursor_pos; ++i) p = g_utf8_next_char (p); } if (WORD_START == mv && text->cursor_pos < 1) { if (text->cursor_row) { text->cursor_row--; text->cursor_pos = text_get_line_strlen(text, text->cursor_row); } return; } else if (WORD_END == mv && text->cursor_pos == curmax) { if (text->cursor_row < text->numlines - 1) { text->cursor_row++; text->cursor_pos = 0; } return; } while (!g_unichar_isalnum (g_utf8_get_char (p))) { p = (WORD_START == mv ? g_utf8_find_prev_char (str, p) : g_utf8_next_char (p)); if (p) text->cursor_pos += (WORD_START == mv ? -1 : 1); if (!p || !*p) return; if (!text->cursor_pos || text->cursor_pos == curmax) return; } while (g_unichar_isalnum (g_utf8_get_char (p))) { p = (WORD_START == mv ? g_utf8_find_prev_char (str, p) : g_utf8_next_char (p)); if (p) text->cursor_pos += (WORD_START == mv ? -1 : 1); if (!p || !*p) return; if (!text->cursor_pos || text->cursor_pos == curmax) return; } }
static void draw_text_line(DiaRenderer *self, TextLine *text_line, Point *pos, Alignment alignment, Color *colour) { DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self); xmlNodePtr node; DiaFont *font = text_line_get_font(text_line); /* no reference? */ real font_height = text_line_get_height(text_line); gchar d_buf[G_ASCII_DTOSTR_BUF_SIZE]; node = xmlNewChild(renderer->root, renderer->svg_name_space, (const xmlChar *)"text", (xmlChar *) text_line_get_string(text_line)); /* not using the renderers font but the textlines */ node_set_text_style(node, renderer, font, font_height, alignment, colour); dia_svg_dtostr(d_buf, pos->x); xmlSetProp(node, (const xmlChar *)"x", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, pos->y); xmlSetProp(node, (const xmlChar *)"y", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, text_line_get_width(text_line)); xmlSetProp(node, (const xmlChar*)"textLength", (xmlChar *) d_buf); }
Text * text_copy(Text *text) { Text *copy; int i; copy = g_new(Text, 1); copy->numlines = text->numlines; copy->lines = g_new(TextLine *, text->numlines); copy->font = dia_font_copy(text->font); copy->height = text->height; copy->position = text->position; copy->color = text->color; copy->alignment = text->alignment; for (i=0;i<text->numlines;i++) { TextLine *text_line = text->lines[i]; copy->lines[i] = text_line_new(text_line_get_string(text_line), text_line_get_font(text_line), text_line_get_height(text_line)); } copy->cursor_pos = 0; copy->cursor_row = 0; copy->focus.obj = NULL; copy->focus.has_focus = FALSE; copy->focus.key_event = text_key_event; copy->focus.text = copy; copy->ascent = text->ascent; copy->descent = text->descent; copy->max_width = text->max_width; return copy; }
/** Draw a TextLine object. * @param object The renderer object to use for transform and output * @param text_line The TextLine to render, including font and height. * @param pos The position to render it at. * @param color The color to render it with. */ static void draw_text_line (DiaRenderer *object, TextLine *text_line, Point *pos, Alignment alignment, Color *color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); GdkColor gdkcolor; int x,y; Point start_pos; PangoLayout* layout = NULL; const gchar *text = text_line_get_string(text_line); int height_pixels; real font_height = text_line_get_height(text_line); real scale = dia_transform_length(renderer->transform, 1.0); if (text == NULL || *text == '\0') return; /* Don't render empty strings. */ point_copy(&start_pos,pos); renderer_color_convert(renderer, color, &gdkcolor); height_pixels = dia_transform_length(renderer->transform, font_height); if (height_pixels < 2) { /* "Greeking" instead of making tiny font */ int width_pixels = dia_transform_length(renderer->transform, text_line_get_width(text_line)); gdk_gc_set_foreground(renderer->gc, &gdkcolor); gdk_gc_set_dashes(renderer->gc, 0, (gint8*)"\1\2", 2); dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y); gdk_draw_line(renderer->pixmap, renderer->gc, x, y, x + width_pixels, y); return; } else { start_pos.y -= text_line_get_ascent(text_line); start_pos.x -= text_line_get_alignment_adjustment (text_line, alignment); dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y); layout = dia_font_build_layout(text, text_line->font, dia_transform_length(renderer->transform, text_line->height)/20.0); #if defined(PANGO_VERSION_ENCODE) # if (PANGO_VERSION >= PANGO_VERSION_ENCODE(1,16,0)) /* I'd say the former Pango API was broken, i.e. leaky */ # define HAVE_pango_layout_get_line_readonly # endif #endif text_line_adjust_layout_line (text_line, #if defined(HAVE_pango_layout_get_line_readonly) pango_layout_get_line_readonly(layout, 0), #else pango_layout_get_line(layout, 0), #endif scale/20.0); if (renderer->highlight_color != NULL) { draw_highlighted_string(renderer, layout, x, y, &gdkcolor); } else { #if defined HAVE_FREETYPE { FT_Bitmap ftbitmap; int width, height; GdkPixbuf *rgba = NULL; width = dia_transform_length(renderer->transform, text_line_get_width(text_line)); height = dia_transform_length(renderer->transform, text_line_get_height(text_line)); if (width > 0) { int stride; guchar* pixels; int i,j; guint8 *graybitmap; initialize_ft_bitmap(&ftbitmap, width, height); pango_ft2_render_layout(&ftbitmap, layout, 0, 0); graybitmap = ftbitmap.buffer; rgba = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); stride = gdk_pixbuf_get_rowstride(rgba); pixels = gdk_pixbuf_get_pixels(rgba); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixels[i*stride+j*4] = gdkcolor.red>>8; pixels[i*stride+j*4+1] = gdkcolor.green>>8; pixels[i*stride+j*4+2] = gdkcolor.blue>>8; pixels[i*stride+j*4+3] = graybitmap[i*ftbitmap.pitch+j]; } } g_free(graybitmap); gdk_draw_pixbuf(renderer->pixmap, renderer->gc, rgba, 0, 0, x, y, width, height, GDK_RGB_DITHER_NONE, 0, 0); g_object_unref(G_OBJECT(rgba)); } } #else gdk_gc_set_foreground(renderer->gc, &gdkcolor); gdk_draw_layout(renderer->pixmap, renderer->gc, x, y, layout); #endif } /* !higlight_color */ g_object_unref(G_OBJECT(layout)); } /* !greeking */
static void draw_text_line(DiaRenderer *self, TextLine *text_line, Point *pos, Alignment alignment, Color *colour) { DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self); xmlNodePtr node; real saved_width; gchar d_buf[DTOSTR_BUF_SIZE]; DiaFont *font; GString *style; node = xmlNewTextChild(renderer->root, renderer->svg_name_space, (const xmlChar *)"text", (xmlChar *) text_line_get_string(text_line)); saved_width = renderer->linewidth; renderer->linewidth = 0.001; /* return value must not be freed */ renderer->linewidth = saved_width; #if 0 /* would need a unit: https://bugzilla.mozilla.org/show_bug.cgi?id=707071#c4 */ style = g_strdup_printf("%s; font-size: %s", get_draw_style(renderer, colour, NULL), dia_svg_dtostr(d_buf, text_line_get_height(text_line))); #else /* get_draw_style: the return value of this function must not be saved * anywhere. And of course it must not be free'd */ style = g_string_new (get_draw_style(renderer, colour, NULL)); #endif /* This is going to break for non-LTR texts, as SVG thinks 'start' is * 'right' for those. */ switch (alignment) { case ALIGN_LEFT: g_string_append (style, "; text-anchor:start"); break; case ALIGN_CENTER: g_string_append (style, "; text-anchor:middle"); break; case ALIGN_RIGHT: g_string_append (style, "; text-anchor:end"); break; default: break; } font = text_line_get_font(text_line); g_string_append_printf (style, "font-family: %s; font-style: %s; font-weight: %s", dia_font_get_family(font), dia_font_get_slant_string(font), dia_font_get_weight_string(font)); xmlSetProp(node, (const xmlChar *)"style", (xmlChar *) style->str); g_string_free (style, TRUE); dia_svg_dtostr(d_buf, pos->x); xmlSetProp(node, (const xmlChar *)"x", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, pos->y); xmlSetProp(node, (const xmlChar *)"y", (xmlChar *) d_buf); /* font-size as single attribute can work like the other length w/o unit */ dia_svg_dtostr(d_buf, text_line_get_height(text_line)); xmlSetProp(node, (const xmlChar *)"font-size", (xmlChar *) d_buf); dia_svg_dtostr(d_buf, text_line_get_width(text_line)); xmlSetProp(node, (const xmlChar*)"textLength", (xmlChar *) d_buf); }
static void draw_text_line(DiaRenderer *self, TextLine *text_line, Point *pos, Alignment alignment, Color *color) { DiaPsFt2Renderer *renderer = DIA_PS_FT2_RENDERER(self); PangoLayout *layout; int line, linecount; double xpos = pos->x, ypos = pos->y; char *text = text_line_get_string(text_line); /* TODO: we could probably pass the alignment down to the PS file? */ xpos -= text_line_get_alignment_adjustment (text_line, alignment); /* Using the global PangoContext does not allow to have renderer specific * different ones. Or it implies the push/pop _context mess. Anyway just * get rid of warnings for now. But the local code may be resurreted * sooner or later... --hb */ #define USE_GLOBAL_CONTEXT #ifndef USE_GLOBAL_CONTEXT PangoAttrList* list; PangoAttribute* attr; guint length; #endif if ((!text)||(text == (const char *)(1))) return; lazy_setcolor(DIA_PS_RENDERER(renderer),color); #define ANNOYING_SCALE_FACTOR 5.9 /* Make sure the letters aren't too wide. */ #ifdef USE_GLOBAL_CONTEXT layout = dia_font_build_layout(text, text_line_get_font(text_line), text_line_get_height(text_line)*ANNOYING_SCALE_FACTOR); #else /* approximately what would be required but w/o dia_font_get_context() */ dia_font_set_height(text_line_get_font(text_line), text_line_get_height(text_line)); layout = pango_layout_new(dia_font_get_context()); length = text ? strlen(text) : 0; pango_layout_set_text(layout,text,length); list = pango_attr_list_new(); attr = pango_attr_font_desc_new(dia_font_get_description(text_line_get_font(text_line))); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert(list,attr); pango_layout_set_attributes(layout,list); pango_attr_list_unref(list); pango_layout_set_indent(layout,0); pango_layout_set_justify(layout,FALSE); #endif pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); linecount = pango_layout_get_line_count(layout); for (line = 0; line < linecount; line++) { PangoLayoutLine *layoutline = pango_layout_get_line(layout, line); /* Not sure scale is the right one here. */ text_line_adjust_layout_line(text_line, layoutline, ANNOYING_SCALE_FACTOR); postscript_draw_contour(DIA_PS_RENDERER(renderer), DPI, /* dpi_x */ layoutline, xpos, ypos); ypos += 10;/* Some line height thing??? */ } }
/* *** Encapsulation functions for transferring to text_line *** */ gchar * text_get_line(const Text *text, int line) { return text_line_get_string(text->lines[line]); }
/** Get the number of characters of the given line. * @param text The text object; * @param line_no The index of the line in the text object, starting at 0. * @returns The number of UTF-8 characters of the indicated line. */ int text_get_line_strlen(const Text *text, int line_no) { return g_utf8_strlen(text_line_get_string(text->lines[line_no]), -1); }