68ecb2e4d9e71fc9085051b7bb6f8577afe180a8
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/*NR_MATRIX_DF_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 NR::Point raster_font::Advance(int glyph_id)
100 {
101 if ( daddy == NULL ) return NR::Point(0,0);
102 double a=daddy->Advance(glyph_id,style.vertical);
103 NR::Point f_a=(style.vertical)?NR::Point(0,a):NR::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 NR::Rect res=daddy->BBox(glyph_id);
111 NR::Point bmi=res.min(),bma=res.max();
112 NR::Point tlp(bmi[0],bmi[1]),trp(bma[0],bmi[1]),blp(bmi[0],bma[1]),brp(bma[0],bma[1]);
113 tlp=tlp*style.transform;
114 trp=trp*style.transform;
115 blp=blp*style.transform;
116 brp=brp*style.transform;
117 res=NR::Rect(tlp,trp);
118 res.expandTo(blp);
119 res.expandTo(brp);
120 area->x0=(res.min())[0];
121 area->y0=(res.min())[1];
122 area->x1=(res.max())[0];
123 area->y1=(res.max())[1];
124 }
126 void raster_font::LoadRasterGlyph(int glyph_id)
127 {
128 raster_glyph *res=NULL;
129 if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) {
130 res=new raster_glyph();
131 res->daddy=this;
132 res->glyph_id=glyph_id;
133 if ( nbBase >= maxBase ) {
134 maxBase=2*nbBase+1;
135 bases=(raster_glyph**)realloc(bases,maxBase*sizeof(raster_glyph*));
136 }
137 bases[nbBase]=res;
138 glyph_id_to_raster_glyph_no[glyph_id]=nbBase;
139 nbBase++;
140 } else {
141 res=bases[glyph_id_to_raster_glyph_no[glyph_id]];
142 }
143 if ( res == NULL ) return;
144 if ( res->polygon ) return;
145 if ( res->outline == NULL ) {
146 if ( daddy == NULL ) return;
147 Path* outline=daddy->Outline(glyph_id,NULL);
148 res->outline=new Path;
149 if ( outline ) {
150 res->outline->Copy(outline);
151 }
152 res->outline->Transform(style.transform);
153 }
154 Shape* temp=new Shape;
155 res->polygon=new Shape;
156 style.Apply(res->outline,temp);
157 if ( style.stroke_width > 0 ) {
158 res->polygon->ConvertToShape(temp,fill_nonZero);
159 } else {
160 res->polygon->ConvertToShape(temp,fill_oddEven);
161 }
162 delete temp;
164 res->SetSubPixelPositionning(4);
165 }
166 void raster_font::RemoveRasterGlyph(raster_glyph* who)
167 {
168 if ( who == NULL ) return;
169 int glyph_id=who->glyph_id;
170 if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) {
171 int no=glyph_id_to_raster_glyph_no[glyph_id];
172 if ( no >= nbBase-1 ) {
173 } else {
174 bases[no]=bases[--nbBase];
175 glyph_id_to_raster_glyph_no[bases[no]->glyph_id]=no;
176 }
177 glyph_id_to_raster_glyph_no.erase(glyph_id_to_raster_glyph_no.find(glyph_id));
178 } else {
179 // not here
180 }
181 }
183 /*int top,bottom; // baseline is y=0
184 int* run_on_line; // array of size (bottom-top+1): run_on_line[i] gives the number of runs on line top+i
185 int nbRun;
186 float_ligne_run* runs;*/
188 raster_position::raster_position(void)
189 {
190 top=0;
191 bottom=-1;
192 run_on_line=NULL;
193 nbRun=0;
194 runs=NULL;
195 }
196 raster_position::~raster_position(void)
197 {
198 if ( run_on_line ) free(run_on_line);
199 if ( runs ) free(runs);
200 }
202 void raster_position::AppendRuns(std::vector<float_ligne_run> const &r,int y)
203 {
204 if ( top > bottom ) {
205 top=bottom=y;
206 if ( run_on_line ) free(run_on_line);
207 run_on_line=(int*)malloc(sizeof(int));
208 run_on_line[0]=0;
209 } else {
210 if ( y < top ) {
211 // printf("wtf?\n");
212 return;
213 } else if ( y > bottom ) {
214 int ob=bottom;
215 bottom=y;
216 run_on_line=(int*)realloc(run_on_line,(bottom-top+1)*sizeof(int));
217 for (int i=ob+1;i<=bottom;i++) run_on_line[i-top]=0;
218 }
219 }
221 if ( r.empty() == false) {
222 run_on_line[y - top] = r.size();
223 runs = (float_ligne_run *) realloc(runs, (nbRun + r.size()) * sizeof(float_ligne_run));
225 for (int i = 0; i < int(r.size()); i++) {
226 runs[nbRun + i] = r[i];
227 }
229 nbRun += r.size();
230 }
231 }
232 void raster_position::Blit(float ph,int pv,NRPixBlock &over)
233 {
234 int base_y=top+pv;
235 int first_y=top+pv,last_y=bottom+pv;
236 if ( first_y < over.area.y0 ) first_y=over.area.y0;
237 if ( last_y >= over.area.y1 ) last_y=over.area.y1-1;
238 if ( first_y > last_y ) return;
239 IntLigne *theIL=new IntLigne();
240 FloatLigne *theI=new FloatLigne();
242 char* mdata=(char*)over.data.px;
243 if ( over.size == NR_PIXBLOCK_SIZE_TINY ) mdata=(char*)over.data.p;
245 for (int y=first_y;y<=last_y;y++) {
246 int first_r=0,last_r=0;
247 for (int i=base_y;i<y;i++) first_r+=run_on_line[i-base_y];
248 last_r=first_r+run_on_line[y-base_y]-1;
249 if ( first_r <= last_r ) {
250 theI->Reset();
251 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);
252 // for (int i=first_r;i<=last_r;i++) {runs[i].st+=ph;runs[i].en+=ph;}
253 // theI->nbRun=theI->maxRun=last_r-first_r+1;
254 // theI->runs=runs+first_r;
256 theIL->Copy(theI);
257 raster_info dest;
258 dest.startPix=over.area.x0;
259 dest.endPix=over.area.x1;
260 dest.sth=over.area.x0;
261 dest.stv=y;
262 dest.buffer=((uint32_t*)(mdata+(over.rs*(y-over.area.y0))));
263 theIL->Raster(dest,NULL,glyph_run_A8_OR);
265 // theI->nbRun=theI->maxRun=0;
266 // theI->runs=NULL;
267 // for (int i=first_r;i<=last_r;i++) {runs[i].st-=ph;runs[i].en-=ph;}
268 }
269 }
270 delete theIL;
271 delete theI;
272 }
275 /* raster_font* daddy;
276 int glyph_id;
278 Path* outline;
279 Shape* polygon;
281 int nb_sub_pixel;
282 raster_position* sub_pixel;*/
284 raster_glyph::raster_glyph(void)
285 {
286 daddy=NULL;
287 glyph_id=0;
288 outline=NULL;
289 polygon=NULL;
290 nb_sub_pixel=0;
291 sub_pixel=NULL;
292 }
293 raster_glyph::~raster_glyph(void)
294 {
295 if ( outline ) delete outline;
296 if ( polygon ) delete polygon;
297 if ( sub_pixel ) delete [] sub_pixel;
298 }
301 void raster_glyph::SetSubPixelPositionning(int nb_pos)
302 {
303 nb_sub_pixel=nb_pos;
304 if ( nb_sub_pixel <= 0 ) nb_sub_pixel=0;
305 if ( sub_pixel ) delete [] sub_pixel;
306 sub_pixel=NULL;
307 if ( nb_sub_pixel > 0 ) {
308 sub_pixel=new raster_position[nb_pos];
309 if ( polygon ) {
310 for (int i=0;i<nb_sub_pixel;i++) LoadSubPixelPosition(i);
311 }
312 }
313 }
314 void raster_glyph::LoadSubPixelPosition(int no)
315 {
316 if ( no < 0 || no >= nb_sub_pixel ) return;
317 if ( sub_pixel[no].top <= sub_pixel[no].bottom ) return;
318 if ( polygon == NULL ) {
319 if ( daddy == NULL ) return;
320 daddy->LoadRasterGlyph(glyph_id);
321 if ( polygon == NULL ) return;
322 }
324 float sub_delta=((float)no)/((float)nb_sub_pixel);
326 polygon->CalcBBox();
328 float l=polygon->leftX,r=polygon->rightX,t=polygon->topY,b=polygon->bottomY;
329 int il,ir,it,ib;
330 il=(int)floor(l);
331 ir=(int)ceil(r);
332 it=(int)floor(t);
333 ib=(int)ceil(b);
335 // version par FloatLigne
336 int curPt;
337 float curY;
338 polygon->BeginQuickRaster(curY, curPt);
340 FloatLigne* theI=new FloatLigne();
342 polygon->DirectQuickScan(curY,curPt,(float)(it-1)+sub_delta,true,1.0);
344 for (int y=it-1;y<ib;y++) {
345 theI->Reset();
346 polygon->QuickScan(curY,curPt,((float)(y+1))+sub_delta,theI,1.0);
347 theI->Flatten();
349 sub_pixel[no].AppendRuns(theI->runs, y);
350 }
351 polygon->EndQuickRaster();
352 delete theI;
353 }
355 void raster_glyph::Blit(const NR::Point &at,NRPixBlock &over)
356 {
357 if ( nb_sub_pixel <= 0 ) return;
358 int pv=(int)ceil(at[1]);
359 double dec=4*(ceil(at[1])-at[1]);
360 int no=(int)floor(dec);
361 sub_pixel[no].Blit(at[0],pv,over);
362 }
366 static void
367 glyph_run_A8_OR (raster_info &dest,void */*data*/,int st,float vst,int en,float ven)
368 {
369 if ( st >= en ) return;
370 if ( vst < 0 ) vst=0;
371 if ( vst > 1 ) vst=1;
372 if ( ven < 0 ) ven=0;
373 if ( ven > 1 ) ven=1;
374 float sv=vst;
375 float dv=ven-vst;
376 int len=en-st;
377 unsigned char* d=(unsigned char*)dest.buffer;
378 d+=(st-dest.startPix);
379 if ( fabs(dv) < 0.001 ) {
380 if ( vst > 0.999 ) {
381 /* Simple copy */
382 while (len > 0) {
383 d[0] = 255;
384 d += 1;
385 len -= 1;
386 }
387 } else {
388 sv*=256;
389 unsigned int c0_24=(int)sv;
390 c0_24&=0xFF;
391 while (len > 0) {
392 unsigned int da;
393 /* Draw */
394 da = 65025 - (255 - c0_24) * (255 - d[0]);
395 d[0] = (da + 127) / 255;
396 d += 1;
397 len -= 1;
398 }
399 }
400 } else {
401 if ( en <= st+1 ) {
402 sv=0.5*(vst+ven);
403 sv*=256;
404 unsigned int c0_24=(int)sv;
405 c0_24&=0xFF;
406 unsigned int da;
407 /* Draw */
408 da = 65025 - (255 - c0_24) * (255 - d[0]);
409 d[0] = (da + 127) / 255;
410 } else {
411 dv/=len;
412 sv+=0.5*dv; // correction trapezoidale
413 sv*=16777216;
414 dv*=16777216;
415 int c0_24 = static_cast<int>(CLAMP(sv, 0, 16777216));
416 int s0_24 = static_cast<int>(dv);
417 while (len > 0) {
418 unsigned int ca, da;
419 /* Draw */
420 ca = c0_24 >> 16;
421 if ( ca > 255 ) ca=255;
422 da = 65025 - (255 - ca) * (255 - d[0]);
423 d[0] = (da + 127) / 255;
424 d += 1;
425 c0_24 += s0_24;
426 c0_24 = CLAMP (c0_24, 0, 16777216);
427 len -= 1;
428 }
429 }
430 }
431 }