Code

Disabling transientize callback - it's currently causing some data loss
[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/*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 }
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 NR::Point      raster_font::Advance(int glyph_id)
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;
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         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];
126 void           raster_font::LoadRasterGlyph(int glyph_id)
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;
163         
164         res->SetSubPixelPositionning(4);
166 void           raster_font::RemoveRasterGlyph(raster_glyph* who)
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   }
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;*/
187   
188 raster_position::raster_position(void)
190   top=0;
191   bottom=-1;
192   run_on_line=NULL;
193   nbRun=0;
194   runs=NULL;
196 raster_position::~raster_position(void)
198   if ( run_on_line ) free(run_on_line);
199   if ( runs ) free(runs);
201   
202 void      raster_position::AppendRuns(std::vector<float_ligne_run> const &r,int y)
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   }
220   
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     }
228     
229     nbRun += r.size();
230   }
232 void      raster_position::Blit(float ph,int pv,NRPixBlock &over)
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();
241   
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;
255       
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);
264             
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;
275 /*  raster_font*      daddy;
276   int               glyph_id;
277   
278   Path*             outline; 
279   Shape*            polygon;
280   
281   int               nb_sub_pixel;
282   raster_position*  sub_pixel;*/
283   
284 raster_glyph::raster_glyph(void)
286   daddy=NULL;
287   glyph_id=0;
288   outline=NULL;
289   polygon=NULL;
290   nb_sub_pixel=0;
291   sub_pixel=NULL;
293 raster_glyph::~raster_glyph(void)
295   if ( outline ) delete outline;
296   if ( polygon ) delete polygon;
297   if ( sub_pixel ) delete [] sub_pixel;
301 void      raster_glyph::SetSubPixelPositionning(int nb_pos)
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   }
314 void      raster_glyph::LoadSubPixelPosition(int no)
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   }
323   
324   float sub_delta=((float)no)/((float)nb_sub_pixel);
325   
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);
334   
335   // version par FloatLigne
336   int    curPt;
337   float  curY;
338   polygon->BeginQuickRaster(curY, curPt);
339   
340   FloatLigne* theI=new FloatLigne();
341   
342   polygon->DirectQuickScan(curY,curPt,(float)(it-1)+sub_delta,true,1.0);
343   
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();
348     
349     sub_pixel[no].AppendRuns(theI->runs, y);
350   }
351   polygon->EndQuickRaster();
352   delete theI;
355 void      raster_glyph::Blit(const NR::Point &at,NRPixBlock &over)
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);
366 static void
367 glyph_run_A8_OR (raster_info &dest,void */*data*/,int st,float vst,int en,float ven)
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   }