Code

convert almost all libnrtype to Geom::
[inkscape.git] / src / libnrtype / RasterFont.cpp
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 }
69   
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)
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;
106 void           raster_font::BBox(int glyph_id,NRRect *area)
108         area->x0=area->y0=area->x1=area->y1=0;
109         if ( daddy == NULL ) return;
110         boost::optional<Geom::Rect> 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         }
130 void           raster_font::LoadRasterGlyph(int glyph_id)
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;
167         
168         res->SetSubPixelPositionning(4);
170 void           raster_font::RemoveRasterGlyph(raster_glyph* who)
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   }
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;*/
191   
192 raster_position::raster_position(void)
194   top=0;
195   bottom=-1;
196   run_on_line=NULL;
197   nbRun=0;
198   runs=NULL;
200 raster_position::~raster_position(void)
202   if ( run_on_line ) free(run_on_line);
203   if ( runs ) free(runs);
205   
206 void      raster_position::AppendRuns(std::vector<float_ligne_run> const &r,int y)
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   }
224   
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     }
232     
233     nbRun += r.size();
234   }
236 void      raster_position::Blit(float ph,int pv,NRPixBlock &over)
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();
245   
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;
259       
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);
268             
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;
279 /*  raster_font*      daddy;
280   int               glyph_id;
281   
282   Path*             outline; 
283   Shape*            polygon;
284   
285   int               nb_sub_pixel;
286   raster_position*  sub_pixel;*/
287   
288 raster_glyph::raster_glyph(void)
290   daddy=NULL;
291   glyph_id=0;
292   outline=NULL;
293   polygon=NULL;
294   nb_sub_pixel=0;
295   sub_pixel=NULL;
297 raster_glyph::~raster_glyph(void)
299   if ( outline ) delete outline;
300   if ( polygon ) delete polygon;
301   if ( sub_pixel ) delete [] sub_pixel;
305 void      raster_glyph::SetSubPixelPositionning(int nb_pos)
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   }
318 void      raster_glyph::LoadSubPixelPosition(int no)
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   }
327   
328   float sub_delta=((float)no)/((float)nb_sub_pixel);
329   
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);
338   
339   // version par FloatLigne
340   int    curPt;
341   float  curY;
342   polygon->BeginQuickRaster(curY, curPt);
343   
344   FloatLigne* theI=new FloatLigne();
345   
346   polygon->DirectQuickScan(curY,curPt,(float)(it-1)+sub_delta,true,1.0);
347   
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();
352     
353     sub_pixel[no].AppendRuns(theI->runs, y);
354   }
355   polygon->EndQuickRaster();
356   delete theI;
359 void      raster_glyph::Blit(const Geom::Point &at,NRPixBlock &over)
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);
370 static void
371 glyph_run_A8_OR (raster_info &dest,void */*data*/,int st,float vst,int en,float ven)
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   }