1 #include "mupdf/fitz.h"
2 
3 
s_xml_starttag_begin(fz_context * ctx,fz_output * out,const char * id)4 static int s_xml_starttag_begin(fz_context *ctx, fz_output *out, const char* id)
5 {
6 	fz_write_printf(ctx, out, "<%s", id);
7 	return 0;
8 }
9 
s_xml_starttag_end(fz_context * ctx,fz_output * out)10 static int s_xml_starttag_end(fz_context *ctx, fz_output *out)
11 {
12 	fz_write_printf(ctx, out, ">\n");
13 	return 0;
14 }
15 
s_xml_starttag_empty_end(fz_context * ctx,fz_output * out)16 static int s_xml_starttag_empty_end(fz_context *ctx, fz_output *out)
17 {
18 	fz_write_printf(ctx, out, "/>\n");
19 	return 0;
20 }
21 
s_xml_endtag(fz_context * ctx,fz_output * out,const char * id)22 static int s_xml_endtag(fz_context *ctx, fz_output *out, const char* id)
23 {
24 	fz_write_printf(ctx, out, "</%s>\n", id);
25 	return 0;
26 }
27 
s_write_attribute_int(fz_context * ctx,fz_output * out,const char * id,int value)28 static int s_write_attribute_int(fz_context *ctx, fz_output *out, const char* id, int value)
29 {
30 	fz_write_printf(ctx, out, " %s=\"%i\"", id, value);
31 	return 0;
32 }
33 
s_write_attribute_float(fz_context * ctx,fz_output * out,const char * id,float value)34 static int s_write_attribute_float(fz_context *ctx, fz_output *out, const char* id, float value)
35 {
36 	fz_write_printf(ctx, out, " %s=\"%g\"", id, value);
37 	return 0;
38 }
39 
s_write_attribute_string(fz_context * ctx,fz_output * out,const char * id,const char * value)40 static int s_write_attribute_string(fz_context *ctx, fz_output *out, const char* id, const char* value)
41 {
42 	fz_write_printf(ctx, out, " %s=\"%s\"", id, value);
43 	return 0;
44 }
45 
s_write_attribute_char(fz_context * ctx,fz_output * out,const char * id,char value)46 static int s_write_attribute_char(fz_context *ctx, fz_output *out, const char* id, char value)
47 {
48 	if (value == '"') fz_write_printf(ctx, out, " %s=\"\\%c\"", id, value);
49 	else fz_write_printf(ctx, out, " %s=\"%c\"", id, value);
50 	return 0;
51 }
52 
s_write_attribute_matrix(fz_context * ctx,fz_output * out,const char * id,const fz_matrix * matrix)53 static int s_write_attribute_matrix(fz_context *ctx, fz_output *out, const char* id, const fz_matrix* matrix)
54 {
55 	fz_write_printf(ctx, out,
56 		" %s=\"%g %g %g %g %g %g\"",
57 		id,
58 		matrix->a,
59 		matrix->b,
60 		matrix->c,
61 		matrix->d,
62 		matrix->e,
63 		matrix->f
64 		);
65 	return 0;
66 }
67 
68 
69 
70 
71 typedef struct
72 {
73 	fz_device super;
74 	fz_output *out;
75 } fz_xmltext_device;
76 
77 static void
fz_xmltext_text(fz_context * ctx,fz_device * dev_,const fz_text * text,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)78 fz_xmltext_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm,
79 	fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
80 {
81 	fz_xmltext_device *dev = (fz_xmltext_device*) dev_;
82 
83 	fz_text_span *span;
84 	for (span = text->head; span; span = span->next) {
85 		int i;
86 
87 		s_xml_starttag_begin(ctx, dev->out, "span");
88 		s_write_attribute_matrix(ctx, dev->out, "ctm", &ctm);
89 		s_write_attribute_string(ctx, dev->out, "font_name", span->font->name);
90 		if (span->font->flags.is_mono)          s_write_attribute_int(ctx, dev->out, "is_mono", 1);
91 		if (span->font->flags.is_serif)         s_write_attribute_int(ctx, dev->out, "is_serif", 1);
92 		if (span->font->flags.is_italic)        s_write_attribute_int(ctx, dev->out, "is_italic", 1);
93 		if (span->font->flags.ft_substitute)    s_write_attribute_int(ctx, dev->out, "ft_substitute", 1);
94 		if (span->font->flags.ft_stretch)       s_write_attribute_int(ctx, dev->out, "ft_stretch", 1);
95 		if (span->font->flags.fake_bold)        s_write_attribute_int(ctx, dev->out, "fake_bold", 1);
96 		if (span->font->flags.fake_italic)      s_write_attribute_int(ctx, dev->out, "fake_italic", 1);
97 		if (span->font->flags.has_opentype)     s_write_attribute_int(ctx, dev->out, "has_opentype", 1);
98 		if (span->font->flags.invalid_bbox)     s_write_attribute_int(ctx, dev->out, "invalid_bbox", 1);
99 		s_write_attribute_matrix(ctx, dev->out, "trm", &span->trm);
100 		s_write_attribute_int(ctx, dev->out, "len", span->len);
101 		s_write_attribute_int(ctx, dev->out, "wmode", span->wmode);
102 		s_write_attribute_int(ctx, dev->out, "bidi_level", span->bidi_level);
103 		s_write_attribute_int(ctx, dev->out, "markup_dir", span->markup_dir);
104 		s_write_attribute_int(ctx, dev->out, "language", span->language);
105 		s_write_attribute_int(ctx, dev->out, "cap", span->cap);
106 		s_xml_starttag_end(ctx, dev->out);
107 
108 		for (i=0; i<span->len; ++i) {
109 			fz_text_item*   item = &span->items[i];
110 			float adv = 0;
111 			if (span->items[i].gid >= 0) {
112 				adv = fz_advance_glyph(ctx, span->font, span->items[i].gid, span->wmode);
113 			}
114 			s_xml_starttag_begin(ctx, dev->out, "char");
115 			s_write_attribute_float(ctx, dev->out, "x", item->x);
116 			s_write_attribute_float(ctx, dev->out, "y", item->y);
117 			s_write_attribute_int(ctx, dev->out, "gid", item->gid);
118 			s_write_attribute_int(ctx, dev->out, "ucs", item->ucs);
119 
120 			/* Firefox complains if we put special characters here; it's only for debugging
121 			so this isn't really a problem. */
122 			s_write_attribute_char(ctx, dev->out, "debug_char",
123 				(item->ucs >= 32 && item->ucs < 128 && item->ucs != '"')
124 					? item->ucs : ' '
125 				);
126 			s_write_attribute_float(ctx, dev->out, "adv", adv);
127 			s_xml_starttag_empty_end(ctx, dev->out);
128 		}
129 
130 		s_xml_endtag(ctx, dev->out, "span");
131 	}
132 }
133 
134 static void
fz_xmltext_fill_text(fz_context * ctx,fz_device * dev_,const fz_text * text,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)135 fz_xmltext_fill_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm,
136 	fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
137 {
138 	fz_xmltext_text(ctx, dev_, text, ctm, colorspace, color, alpha, color_params);
139 }
140 
141 static void
fz_xmltext_stroke_text(fz_context * ctx,fz_device * dev_,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)142 fz_xmltext_stroke_text(fz_context *ctx, fz_device *dev_, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm,
143 	fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
144 {
145 	fz_xmltext_text(ctx, dev_, text, ctm, colorspace, color, alpha, color_params);
146 }
147 
148 static void
fz_xmltext_clip_text(fz_context * ctx,fz_device * dev_,const fz_text * text,fz_matrix ctm,fz_rect scissor)149 fz_xmltext_clip_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm, fz_rect scissor)
150 {
151 	fz_xmltext_text(ctx, dev_, text, ctm, NULL, NULL, 0 /*alpha*/, fz_default_color_params);
152 }
153 
154 static void
fz_xmltext_clip_stroke_text(fz_context * ctx,fz_device * dev_,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_rect scissor)155 fz_xmltext_clip_stroke_text(fz_context *ctx, fz_device *dev_, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor)
156 {
157 	fz_xmltext_text(ctx, dev_, text, ctm, NULL, 0, 0, fz_default_color_params);
158 }
159 
160 static void
fz_xmltext_ignore_text(fz_context * ctx,fz_device * dev_,const fz_text * text,fz_matrix ctm)161 fz_xmltext_ignore_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm)
162 {
163 }
164 
165 static void
fz_stext_close_device(fz_context * ctx,fz_device * dev_)166 fz_stext_close_device(fz_context *ctx, fz_device *dev_)
167 {
168 }
169 
170 
fz_new_xmltext_device(fz_context * ctx,fz_output * out)171 fz_device *fz_new_xmltext_device(fz_context *ctx, fz_output *out)
172 {
173 	static int page_number = 0;
174 	fz_xmltext_device *dev = fz_new_derived_device(ctx, fz_xmltext_device);
175 
176 	dev->super.close_device = fz_stext_close_device;
177 
178 	dev->super.fill_text = fz_xmltext_fill_text;
179 	dev->super.stroke_text = fz_xmltext_stroke_text;
180 	dev->super.clip_text = fz_xmltext_clip_text;
181 	dev->super.clip_stroke_text = fz_xmltext_clip_stroke_text;
182 	dev->super.ignore_text = fz_xmltext_ignore_text;
183 
184 	dev->out = out;
185 	page_number += 1;
186 
187 	return (fz_device*)dev;
188 }
189