handle font=0 in drawchar (dummy character passing)
[swftools.git] / lib / devices / text.c
1 /* text.c
2
3    Part of the swftools package.
4
5    Copyright (c) 2006 Matthias Kramm <kramm@quiss.org> 
6  
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <memory.h>
27 #include "../types.h"
28 #include "../mem.h"
29 #include "../gfxdevice.h"
30 #include "../gfxtools.h"
31 #include "../utf8.h"
32
33 typedef struct _textpage {
34     char*text;
35     int textsize;
36     int textpos;
37     struct _textpage*next;
38 } textpage_t;
39
40 typedef struct _internal {
41     textpage_t*first_page;
42     textpage_t*current_page;
43     double currentx;
44     double currenty;
45     double lastadvance;
46 } internal_t;
47
48 int text_setparameter(gfxdevice_t*dev, const char*key, const char*value)
49 {
50     internal_t*i = (internal_t*)dev->internal;
51     return 0;
52 }
53 void text_startpage(gfxdevice_t*dev, int width, int height)
54 {
55     internal_t*i = (internal_t*)dev->internal;
56     if(!i->first_page) {
57         i->first_page = i->current_page = (textpage_t*)malloc(sizeof(textpage_t));
58     } else {
59         i->current_page->next = (textpage_t*)malloc(sizeof(textpage_t));
60         i->current_page = i->current_page->next;
61     }
62     i->current_page->textsize = 4096;
63     i->current_page->text = malloc(i->current_page->textsize);
64     i->current_page->textpos = 0;
65     i->current_page->next = 0;
66     i->currentx = 0;
67     i->currenty = 0;
68     i->lastadvance = 0;
69 }
70 void text_startclip(gfxdevice_t*dev, gfxline_t*line)
71 {
72     internal_t*i = (internal_t*)dev->internal;
73 }
74 void text_endclip(gfxdevice_t*dev)
75 {
76     internal_t*i = (internal_t*)dev->internal;
77 }
78 void text_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
79 {
80     internal_t*i = (internal_t*)dev->internal;
81 }
82 void text_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
83 {
84     internal_t*i = (internal_t*)dev->internal;
85 }
86 void text_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
87 {
88     internal_t*i = (internal_t*)dev->internal;
89 }
90 void text_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
91 {
92     internal_t*i = (internal_t*)dev->internal;
93 }
94 void text_addfont(gfxdevice_t*dev, gfxfont_t*font) {}
95
96 static void addchar(gfxdevice_t*dev, int unicode)
97 {
98     internal_t*i = (internal_t*)dev->internal;
99     if(!i->current_page) {
100         text_startpage(dev, 0, 0);
101     }
102     if(i->current_page->textpos + 10 > i->current_page->textsize) {
103         i->current_page->textsize += 4096;
104         i->current_page->text = realloc(i->current_page->text, i->current_page->textsize);
105     }
106     writeUTF8(unicode, &i->current_page->text[i->current_page->textpos]);
107     i->current_page->textpos += strlen(&i->current_page->text[i->current_page->textpos]);
108 }
109
110 void text_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
111 {
112     internal_t*i = (internal_t*)dev->internal;
113     double xshift = matrix->tx - i->currentx;
114     double yshift = matrix->ty - i->currenty;
115     i->currentx = matrix->tx;
116     i->currenty = matrix->ty;
117
118     if(fabs(yshift)>1.0) {
119         addchar(dev, 10);
120     } else if(xshift > i->lastadvance*1.3 || xshift<0) {
121         addchar(dev, 32);
122     }
123     if(font) {
124         i->lastadvance = font->glyphs[glyphnr].advance*matrix->m00;
125         int u = font->glyphs[glyphnr].unicode;
126     } else {
127         u = glyphnr;
128         i->currentx = 0;i->currenty = 0;
129     }
130     if(u>13) {
131         addchar(dev, u);
132     }
133 }
134
135 void text_drawlink(gfxdevice_t*dev, gfxline_t*line, char*action)
136 {
137     internal_t*i = (internal_t*)dev->internal;
138 }
139
140 void text_endpage(gfxdevice_t*dev)
141 {
142     internal_t*i = (internal_t*)dev->internal;
143 }
144
145 void text_result_write(gfxresult_t*r, int filedesc)
146 {
147     textpage_t*i= (textpage_t*)r->internal;
148 }
149 int text_result_save(gfxresult_t*r, char*filename)
150 {
151     textpage_t*i= (textpage_t*)r->internal;
152     if(!i) {
153         return 0; // no pages drawn
154     }
155     FILE*fi = fopen(filename, "wb");
156     if(!fi)
157         return 0;
158     while(i) {
159         fwrite(i->text, i->textpos, 1, fi);
160         i = i->next;
161     }
162     fclose(fi);
163     return 1;
164 }
165 void*text_result_get(gfxresult_t*r, char*name)
166 {
167     textpage_t*i= (textpage_t*)r->internal;
168     if(!strcmp(name,"text")) {
169         textpage_t*j = i;
170         int len = 0;
171         while(j) {
172             len += i->textpos;
173             j = j->next;
174         }
175         char*text = malloc(len);
176         int pos = 0;
177         j = i;
178         while(j) {
179             memcpy(&text[pos], i->text, i->textpos);
180             pos += i->textpos;
181             j = j->next;
182         }
183         text[pos] = 0;
184         return text;
185     } else if(!strncmp(name,"page",4)) {
186         int pagenr = atoi(&name[4]);
187         if(pagenr<0)
188             pagenr=0;
189         while(pagenr>0) {
190             i = i->next;
191             if(!i)
192                 return 0;
193         }
194         i->text[i->textpos] = 0;
195         return strdup(i->text);
196     }
197     return 0;
198 }
199 void text_result_destroy(gfxresult_t*r)
200 {
201     textpage_t*i= (textpage_t*)r->internal;
202     r->internal = 0;
203     while(i) {
204         textpage_t*next = i->next;
205         free(i->text);i->text = 0;
206         free(i);
207         i = next;
208     }
209     free(r);
210 }
211
212 gfxresult_t* text_finish(struct _gfxdevice*dev)
213 {
214     internal_t*i = (internal_t*)dev->internal;
215     
216     gfxresult_t* res = (gfxresult_t*)rfx_calloc(sizeof(gfxresult_t));
217     
218     res->internal = i->first_page;i->first_page = 0;i->current_page=0;
219     res->write = text_result_write;
220     res->save = text_result_save;
221     res->get = text_result_get;
222     res->destroy = text_result_destroy;
223
224     free(dev->internal); dev->internal = 0; i = 0;
225
226     return res;
227 }
228
229
230
231 void gfxdevice_text_init(gfxdevice_t*dev, gfxdevice_t*out)
232 {
233     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
234     memset(dev, 0, sizeof(gfxdevice_t));
235
236     dev->name = "text";
237
238     dev->internal = i;
239
240     dev->setparameter = text_setparameter;
241     dev->startpage = text_startpage;
242     dev->startclip = text_startclip;
243     dev->endclip = text_endclip;
244     dev->stroke = text_stroke;
245     dev->fill = text_fill;
246     dev->fillbitmap = text_fillbitmap;
247     dev->fillgradient = text_fillgradient;
248     dev->addfont = text_addfont;
249     dev->drawchar = text_drawchar;
250     dev->drawlink = text_drawlink;
251     dev->endpage = text_endpage;
252     dev->finish = text_finish;
253 }
254