1 /*
2 * RasterFont.cpp
3 * testICU
4 *
5 */
7 #ifdef HAVE_CONFIG_H
8 # include <config.h>
9 #endif
10 #include "RasterFont.h"
12 #include <livarot/float-line.h>
13 #include <livarot/int-line.h>
14 #include <livarot/Path.h>
15 #include <livarot/Shape.h>
16 #include <libnr/nr-pixblock.h>
17 #include <libnrtype/font-instance.h>
18 #include <libnrtype/raster-glyph.h>
19 #include <libnrtype/raster-position.h>
22 static void glyph_run_A8_OR (raster_info &dest,void */*data*/,int st,float vst,int en,float ven);
24 void font_style::Apply(Path* src,Shape* dest) {
25 src->Convert(1);
26 if ( stroke_width > 0 ) {
27 if ( nbDash > 0 ) {
28 double dlen = 0.0;
29 const float scale = 1/*Geom::expansion(transform)*/;
30 for (int i = 0; i < nbDash; i++) dlen += dashes[i] * scale;
31 if (dlen >= 0.01) {
32 float sc_offset = dash_offset * scale;
33 float *tdashs=(float*)malloc((nbDash+1)*sizeof(float));
34 while ( sc_offset >= dlen ) sc_offset-=dlen;
35 tdashs[0]=dashes[0] * scale;
36 for (int i=1;i<nbDash;i++) tdashs[i] = tdashs[i - 1] + dashes[i] * scale;
37 src->DashPolyline(0.0,0.0,dlen,nbDash,tdashs,true,sc_offset);
38 free(tdashs);
39 }
40 }
41 src->Stroke(dest, false, 0.5*stroke_width, stroke_join, stroke_cap, 0.5*stroke_width*stroke_miter_limit);
42 } else {
43 src->Fill(dest,0);
44 }
45 }
47 raster_font::raster_font(font_style const &fstyle) :
48 daddy(NULL),
49 refCount(0),
50 style(fstyle),
51 glyph_id_to_raster_glyph_no(),
52 nbBase(0),
53 maxBase(0),
54 bases(NULL)
55 {
56 // printf("raster font born\n");
57 }
59 raster_font::~raster_font(void)
60 {
61 // printf("raster font death\n");
62 if ( daddy ) daddy->RemoveRasterFont(this);
63 daddy=NULL;
64 if ( style.dashes ) free(style.dashes);
65 style.dashes=NULL;
66 for (int i=0;i<nbBase;i++) delete bases[i];
67 if ( bases ) free(bases);
68 }
70 void raster_font::Unref(void)
71 {
72 refCount--;
73 // printf("raster %x unref'd %i\n",this,refCount);
74 if ( refCount <= 0 ) {
75 if ( daddy ) daddy->RemoveRasterFont(this);
76 daddy=NULL;
77 delete this;
78 }
79 }
80 void raster_font::Ref(void)
81 {
82 refCount++;
83 // printf("raster %x ref'd %i\n",this,refCount);
84 }
85 raster_glyph* raster_font::GetGlyph(int glyph_id)
86 {
87 raster_glyph *res=NULL;
88 if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) {
89 LoadRasterGlyph(glyph_id);
90 if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) { // recheck
91 } else {
92 res=bases[glyph_id_to_raster_glyph_no[glyph_id]];
93 }
94 } else {
95 res=bases[glyph_id_to_raster_glyph_no[glyph_id]];
96 }
97 return res;
98 }
99 Geom::Point raster_font::Advance(int glyph_id)
100 {
101 if ( daddy == NULL ) return Geom::Point(0,0);
102 double a=daddy->Advance(glyph_id,style.vertical);
103 Geom::Point f_a=(style.vertical)?Geom::Point(0,a):Geom::Point(a,0);
104 return f_a*style.transform;
105 }
106 void raster_font::BBox(int glyph_id,NRRect *area)
107 {
108 area->x0=area->y0=area->x1=area->y1=0;
109 if ( daddy == NULL ) return;
110 Geom::OptRect res=daddy->BBox(glyph_id);
111 if (res) {
112 Geom::Point bmi=res->min(),bma=res->max();
113 Geom::Point tlp(bmi[0],bmi[1]),trp(bma[0],bmi[1]),blp(bmi[0],bma[1]),brp(bma[0],bma[1]);
114 tlp=tlp*style.transform;
115 trp=trp*style.transform;
116 blp=blp*style.transform;
117 brp=brp*style.transform;
118 *res=Geom::Rect(tlp,trp);
119 res->expandTo(blp);
120 res->expandTo(brp);
121 area->x0=(res->min())[0];
122 area->y0=(res->min())[1];
123 area->x1=(res->max())[0];
124 area->y1=(res->max())[1];
125 } else {
126 nr_rect_d_set_empty(area);
127 }
128 }
130 void raster_font::LoadRasterGlyph(int glyph_id)
131 {
132 raster_glyph *res=NULL;
133 if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) {
134 res=new raster_glyph();
135 res->daddy=this;
136 res->glyph_id=glyph_id;
137 if ( nbBase >= maxBase ) {
138 maxBase=2*nbBase+1;
139 bases=(raster_glyph**)realloc(bases,maxBase*sizeof(raster_glyph*));
140 }
141 bases[nbBase]=res;
142 glyph_id_to_raster_glyph_no[glyph_id]=nbBase;
143 nbBase++;
144 } else {
145 res=bases[glyph_id_to_raster_glyph_no[glyph_id]];
146 }
147 if ( res == NULL ) return;
148 if ( res->polygon ) return;
149 if ( res->outline == NULL ) {
150 if ( daddy == NULL ) return;
151 Path* outline=daddy->Outline(glyph_id,NULL);
152 res->outline=new Path;
153 if ( outline ) {
154 res->outline->Copy(outline);
155 }
156 res->outline->Transform(style.transform);
157 }
158 Shape* temp=new Shape;
159 res->polygon=new Shape;
160 style.Apply(res->outline,temp);
161 if ( style.stroke_width > 0 ) {
162 res->polygon->ConvertToShape(temp,fill_nonZero);
163 } else {
164 res->polygon->ConvertToShape(temp,fill_oddEven);
165 }
166 delete temp;
168 res->SetSubPixelPositionning(4);
169 }
170 void raster_font::RemoveRasterGlyph(raster_glyph* who)
171 {
172 if ( who == NULL ) return;
173 int glyph_id=who->glyph_id;
174 if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) {
175 int no=glyph_id_to_raster_glyph_no[glyph_id];
176 if ( no >= nbBase-1 ) {
177 } else {
178 bases[no]=bases[--nbBase];
179 glyph_id_to_raster_glyph_no[bases[no]->glyph_id]=no;
180 }
181 glyph_id_to_raster_glyph_no.erase(glyph_id_to_raster_glyph_no.find(glyph_id));
182 } else {
183 // not here
184 }
185 }
187 /*int top,bottom; // baseline is y=0
188 int* run_on_line; // array of size (bottom-top+1): run_on_line[i] gives the number of runs on line top+i
189 int nbRun;
190 float_ligne_run* runs;*/
192 raster_position::raster_position(void)
193 {
194 top=0;
195 bottom=-1;
196 run_on_line=NULL;
197 nbRun=0;
198 runs=NULL;
199 }
200 raster_position::~raster_position(void)
201 {
202 if ( run_on_line ) free(run_on_line);
203 if ( runs ) free(runs);
204 }
206 void raster_position::AppendRuns(std::vector<float_ligne_run> const &r,int y)
207 {
208 if ( top > bottom ) {
209 top=bottom=y;
210 if ( run_on_line ) free(run_on_line);
211 run_on_line=(int*)malloc(sizeof(int));
212 run_on_line[0]=0;
213 } else {
214 if ( y < top ) {
215 // printf("wtf?\n");
216 return;
217 } else if ( y > bottom ) {
218 int ob=bottom;
219 bottom=y;
220 run_on_line=(int*)realloc(run_on_line,(bottom-top+1)*sizeof(int));
221 for (int i=ob+1;i<=bottom;i++) run_on_line[i-top]=0;
222 }
223 }
225 if ( r.empty() == false) {
226 run_on_line[y - top] = r.size();
227 runs = (float_ligne_run *) realloc(runs, (nbRun + r.size()) * sizeof(float_ligne_run));
229 for (int i = 0; i < int(r.size()); i++) {
230 runs[nbRun + i] = r[i];
231 }
233 nbRun += r.size();
234 }
235 }
236 void raster_position::Blit(float ph,int pv,NRPixBlock &over)
237 {
238 int base_y=top+pv;
239 int first_y=top+pv,last_y=bottom+pv;
240 if ( first_y < over.area.y0 ) first_y=over.area.y0;
241 if ( last_y >= over.area.y1 ) last_y=over.area.y1-1;
242 if ( first_y > last_y ) return;
243 IntLigne *theIL=new IntLigne();
244 FloatLigne *theI=new FloatLigne();
246 char* mdata=(char*)over.data.px;
247 if ( over.size == NR_PIXBLOCK_SIZE_TINY ) mdata=(char*)over.data.p;
249 for (int y=first_y;y<=last_y;y++) {
250 int first_r=0,last_r=0;
251 for (int i=base_y;i<y;i++) first_r+=run_on_line[i-base_y];
252 last_r=first_r+run_on_line[y-base_y]-1;
253 if ( first_r <= last_r ) {
254 theI->Reset();
255 for (int i=first_r;i<=last_r;i++) theI->AddRun(runs[i].st+ph,runs[i].en+ph,runs[i].vst,runs[i].ven,runs[i].pente);
256 // for (int i=first_r;i<=last_r;i++) {runs[i].st+=ph;runs[i].en+=ph;}
257 // theI->nbRun=theI->maxRun=last_r-first_r+1;
258 // theI->runs=runs+first_r;
260 theIL->Copy(theI);
261 raster_info dest;
262 dest.startPix=over.area.x0;
263 dest.endPix=over.area.x1;
264 dest.sth=over.area.x0;
265 dest.stv=y;
266 dest.buffer=((uint32_t*)(mdata+(over.rs*(y-over.area.y0))));
267 theIL->Raster(dest,NULL,glyph_run_A8_OR);
269 // theI->nbRun=theI->maxRun=0;
270 // theI->runs=NULL;
271 // for (int i=first_r;i<=last_r;i++) {runs[i].st-=ph;runs[i].en-=ph;}
272 }
273 }
274 delete theIL;
275 delete theI;
276 }
279 /* raster_font* daddy;
280 int glyph_id;
282 Path* outline;
283 Shape* polygon;
285 int nb_sub_pixel;
286 raster_position* sub_pixel;*/
288 raster_glyph::raster_glyph(void)
289 {
290 daddy=NULL;
291 glyph_id=0;
292 outline=NULL;
293 polygon=NULL;
294 nb_sub_pixel=0;
295 sub_pixel=NULL;
296 }
297 raster_glyph::~raster_glyph(void)
298 {
299 if ( outline ) delete outline;
300 if ( polygon ) delete polygon;
301 if ( sub_pixel ) delete [] sub_pixel;
302 }
305 void raster_glyph::SetSubPixelPositionning(int nb_pos)
306 {
307 nb_sub_pixel=nb_pos;
308 if ( nb_sub_pixel <= 0 ) nb_sub_pixel=0;
309 if ( sub_pixel ) delete [] sub_pixel;
310 sub_pixel=NULL;
311 if ( nb_sub_pixel > 0 ) {
312 sub_pixel=new raster_position[nb_pos];
313 if ( polygon ) {
314 for (int i=0;i<nb_sub_pixel;i++) LoadSubPixelPosition(i);
315 }
316 }
317 }
318 void raster_glyph::LoadSubPixelPosition(int no)
319 {
320 if ( no < 0 || no >= nb_sub_pixel ) return;
321 if ( sub_pixel[no].top <= sub_pixel[no].bottom ) return;
322 if ( polygon == NULL ) {
323 if ( daddy == NULL ) return;
324 daddy->LoadRasterGlyph(glyph_id);
325 if ( polygon == NULL ) return;
326 }
328 float sub_delta=((float)no)/((float)nb_sub_pixel);
330 polygon->CalcBBox();
332 float l=polygon->leftX,r=polygon->rightX,t=polygon->topY,b=polygon->bottomY;
333 int il,ir,it,ib;
334 il=(int)floor(l);
335 ir=(int)ceil(r);
336 it=(int)floor(t);
337 ib=(int)ceil(b);
339 // version par FloatLigne
340 int curPt;
341 float curY;
342 polygon->BeginQuickRaster(curY, curPt);
344 FloatLigne* theI=new FloatLigne();
346 polygon->DirectQuickScan(curY,curPt,(float)(it-1)+sub_delta,true,1.0);
348 for (int y=it-1;y<ib;y++) {
349 theI->Reset();
350 polygon->QuickScan(curY,curPt,((float)(y+1))+sub_delta,theI,1.0);
351 theI->Flatten();
353 sub_pixel[no].AppendRuns(theI->runs, y);
354 }
355 polygon->EndQuickRaster();
356 delete theI;
357 }
359 void raster_glyph::Blit(const Geom::Point &at,NRPixBlock &over)
360 {
361 if ( nb_sub_pixel <= 0 ) return;
362 int pv=(int)ceil(at[1]);
363 double dec=4*(ceil(at[1])-at[1]);
364 int no=(int)floor(dec);
365 sub_pixel[no].Blit(at[0],pv,over);
366 }
370 static void
371 glyph_run_A8_OR (raster_info &dest,void */*data*/,int st,float vst,int en,float ven)
372 {
373 if ( st >= en ) return;
374 if ( vst < 0 ) vst=0;
375 if ( vst > 1 ) vst=1;
376 if ( ven < 0 ) ven=0;
377 if ( ven > 1 ) ven=1;
378 float sv=vst;
379 float dv=ven-vst;
380 int len=en-st;
381 unsigned char* d=(unsigned char*)dest.buffer;
382 d+=(st-dest.startPix);
383 if ( fabs(dv) < 0.001 ) {
384 if ( vst > 0.999 ) {
385 /* Simple copy */
386 while (len > 0) {
387 d[0] = 255;
388 d += 1;
389 len -= 1;
390 }
391 } else {
392 sv*=256;
393 unsigned int c0_24=(int)sv;
394 c0_24&=0xFF;
395 while (len > 0) {
396 unsigned int da;
397 /* Draw */
398 da = 65025 - (255 - c0_24) * (255 - d[0]);
399 d[0] = (da + 127) / 255;
400 d += 1;
401 len -= 1;
402 }
403 }
404 } else {
405 if ( en <= st+1 ) {
406 sv=0.5*(vst+ven);
407 sv*=256;
408 unsigned int c0_24=(int)sv;
409 c0_24&=0xFF;
410 unsigned int da;
411 /* Draw */
412 da = 65025 - (255 - c0_24) * (255 - d[0]);
413 d[0] = (da + 127) / 255;
414 } else {
415 dv/=len;
416 sv+=0.5*dv; // correction trapezoidale
417 sv*=16777216;
418 dv*=16777216;
419 int c0_24 = static_cast<int>(CLAMP(sv, 0, 16777216));
420 int s0_24 = static_cast<int>(dv);
421 while (len > 0) {
422 unsigned int ca, da;
423 /* Draw */
424 ca = c0_24 >> 16;
425 if ( ca > 255 ) ca=255;
426 da = 65025 - (255 - ca) * (255 - d[0]);
427 d[0] = (da + 127) / 255;
428 d += 1;
429 c0_24 += s0_24;
430 c0_24 = CLAMP (c0_24, 0, 16777216);
431 len -= 1;
432 }
433 }
434 }
435 }