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