diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-08-14 14:32:13 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-08-14 14:32:13 +0000 |
| commit | d1dbd5e4ca7917b5734a5cd011907176b311d158 (patch) | |
| tree | 2ce69589b16fe70ffb15aba93bfb598fd7bd6d07 /src/libnrtype | |
| parent | Fix crash on empty patterns (diff) | |
| download | inkscape-d1dbd5e4ca7917b5734a5cd011907176b311d158.tar.gz inkscape-d1dbd5e4ca7917b5734a5cd011907176b311d158.zip | |
Fix glyph outlines to always consist of closed paths
(bzr r9508.1.63)
Diffstat (limited to 'src/libnrtype')
| -rw-r--r-- | src/libnrtype/FontInstance.cpp | 175 | ||||
| -rw-r--r-- | src/libnrtype/font-glyph.h | 1 | ||||
| -rw-r--r-- | src/libnrtype/font-instance.h | 3 |
3 files changed, 79 insertions, 100 deletions
diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp index a41f7d370..085cc6c88 100644 --- a/src/libnrtype/FontInstance.cpp +++ b/src/libnrtype/FontInstance.cpp @@ -21,6 +21,7 @@ #include FT_TRUETYPE_TABLES_H #include <pango/pangoft2.h> #include <2geom/pathvector.h> +#include <2geom/svg-path.h> #include "libnr/nr-rect.h" #include "libnrtype/font-glyph.h" #include "libnrtype/font-instance.h" @@ -102,11 +103,17 @@ bool font_style_equal::operator()(const font_style &a,const font_style &b) const /* * Outline extraction */ -typedef struct ft2_to_liv { - Path* theP; - double scale; - Geom::Point last; -} ft2_to_liv; + +struct FT2GeomData { + FT2GeomData(Geom::PathBuilder &b, double s) + : builder(b) + , last(0, 0) + , scale(s) + {} + Geom::PathBuilder &builder; + Geom::Point last; + double scale; +}; // Note: Freetype 2.2.1 redefined function signatures for functions to be placed in an // FT_Outline_Funcs structure. This is needed to keep backwards compatibility with the @@ -121,46 +128,46 @@ typedef FT_Vector FREETYPE_VECTOR; // outline as returned by freetype -> livarot Path // see nr-type-ft2.cpp for the freetype -> artBPath on which this code is based -static int ft2_move_to(FREETYPE_VECTOR *to, void * i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y); +static int ft2_move_to(FREETYPE_VECTOR *to, void * i_user) +{ + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y); // printf("m t=%f %f\n",p[0],p[1]); - user->theP->MoveTo(p); - user->last=p; + user->builder.moveTo(p * user->scale); + user->last = p; return 0; } static int ft2_line_to(FREETYPE_VECTOR *to, void *i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y); + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y); // printf("l t=%f %f\n",p[0],p[1]); - user->theP->LineTo(p); - user->last=p; + user->builder.lineTo(p * user->scale); + user->last = p; return 0; } static int ft2_conic_to(FREETYPE_VECTOR *control, FREETYPE_VECTOR *to, void *i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y); + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y), c(control->x, control->y); + user->builder.quadTo(c * user->scale, p * user->scale); // printf("b c=%f %f t=%f %f\n",c[0],c[1],p[0],p[1]); - user->theP->BezierTo(p); - user->theP->IntermBezierTo(c); - user->theP->EndBezierTo(); - user->last=p; + user->last = p; return 0; } static int ft2_cubic_to(FREETYPE_VECTOR *control1, FREETYPE_VECTOR *control2, FREETYPE_VECTOR *to, void *i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y); - Geom::Point c1(user->scale*control1->x,user->scale*control1->y); - Geom::Point c2(user->scale*control2->x,user->scale*control2->y); + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y); + Geom::Point c1(control1->x, control1->y); + Geom::Point c2(control2->x, control2->y); // printf("c c1=%f %f c2=%f %f t=%f %f\n",c1[0],c1[1],c2[0],c2[1],p[0],p[1]); - user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2)); - user->last=p; + //user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2)); + user->builder.curveTo(c1 * user->scale, c2 * user->scale, p * user->scale); + user->last = p; return 0; } #endif @@ -206,9 +213,6 @@ font_instance::~font_instance(void) theFace = 0; for (int i=0;i<nbGlyph;i++) { - if ( glyphs[i].outline ) { - delete glyphs[i].outline; - } if ( glyphs[i].pathvector ) { delete glyphs[i].pathvector; } @@ -490,14 +494,19 @@ void font_instance::LoadGlyph(int glyph_id) #endif if ( id_to_no.find(glyph_id) == id_to_no.end() ) { + Geom::PathBuilder path_builder; + if ( nbGlyph >= maxGlyph ) { maxGlyph=2*nbGlyph+1; glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph)); } font_glyph n_g; - n_g.outline=NULL; n_g.pathvector=NULL; n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0; + n_g.h_advance = 0; + n_g.v_advance = 0; + n_g.h_width = 0; + n_g.v_width = 0; bool doAdd=false; #ifdef USE_PANGO_WIN32 @@ -516,7 +525,6 @@ void font_instance::LoadGlyph(int glyph_id) n_g.v_advance=otm.otmTextMetrics.tmHeight*scale; n_g.h_width=metrics.gmBlackBoxX*scale; n_g.v_width=metrics.gmBlackBoxY*scale; - n_g.outline=NULL; if ( bufferSize == GDI_ERROR) { // shit happened } else if ( bufferSize == 0) { @@ -528,14 +536,13 @@ void font_instance::LoadGlyph(int glyph_id) // shit happened } else { // Platform SDK is rubbish, read KB87115 instead - n_g.outline=new Path; DWORD polyOffset=0; while ( polyOffset < bufferSize ) { TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer+polyOffset); if (polyOffset+polyHeader->cb > bufferSize) break; if (polyHeader->dwType == TT_POLYGON_TYPE) { - n_g.outline->MoveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale)); + path_builder.moveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale)); DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER); while ( curveOffset < polyOffset+polyHeader->cb ) { @@ -544,41 +551,32 @@ void font_instance::LoadGlyph(int glyph_id) POINTFX const *endp=p+polyCurve->cpfx; switch (polyCurve->wType) { - case TT_PRIM_LINE: - while ( p != endp ) - n_g.outline->LineTo(pointfx_to_nrpoint(*p++, scale)); - break; - - case TT_PRIM_QSPLINE: - { - g_assert(polyCurve->cpfx >= 2); - endp -= 2; - Geom::Point this_mid=pointfx_to_nrpoint(p[0], scale); - while ( p != endp ) { - Geom::Point next_mid=pointfx_to_nrpoint(p[1], scale); - n_g.outline->BezierTo((next_mid+this_mid)/2); - n_g.outline->IntermBezierTo(this_mid); - n_g.outline->EndBezierTo(); - ++p; - this_mid=next_mid; - } - n_g.outline->BezierTo(pointfx_to_nrpoint(p[1], scale)); - n_g.outline->IntermBezierTo(this_mid); - n_g.outline->EndBezierTo(); - break; + case TT_PRIM_LINE: + while ( p != endp ) + path_builder.lineTo(pointfx_to_nrpoint(*p++, scale)); + break; + + case TT_PRIM_QSPLINE: + g_assert(polyCurve->cpfx % 2 == 0); + while ( p != endp ) { + path_builder.quadTo(pointfx_to_nrpoint(p[0], scale), + pointfx_to_nrpoint(p[1], scale)); + p += 2; } - - case 3: // TT_PRIM_CSPLINE - g_assert(polyCurve->cpfx % 3 == 0); - while ( p != endp ) { - n_g.outline->CubicTo(pointfx_to_nrpoint(p[2], scale), pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale)); - p += 3; - } - break; + break; + + case 3: // TT_PRIM_CSPLINE + g_assert(polyCurve->cpfx % 3 == 0); + while ( p != endp ) { + path_builder.curveTo(pointfx_to_nrpoint(p[0], scale), + pointfx_to_nrpoint(p[1], scale), + pointfx_to_nrpoint(p[2], scale)); + p += 3; + } + break; } curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1); } - n_g.outline->Close(); } polyOffset += polyHeader->cb; } @@ -610,21 +608,29 @@ void font_instance::LoadGlyph(int glyph_id) ft2_cubic_to, 0, 0 }; - n_g.outline=new Path; - ft2_to_liv tData; - tData.theP=n_g.outline; - tData.scale=1.0/((double)theFace->units_per_EM); - tData.last=Geom::Point(0,0); - FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &tData); + FT2GeomData user(path_builder, 1.0/((double)theFace->units_per_EM)); + FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &user); } doAdd=true; } #endif + path_builder.finish(); if ( doAdd ) { - if ( n_g.outline ) { - n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]); - n_g.pathvector=n_g.outline->MakePathVector(); + Geom::PathVector pv = path_builder.peek(); + // close all paths + for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) { + i->close(); + } + if ( !pv.empty() ) { + n_g.pathvector = new Geom::PathVector(pv); + Geom::OptRect bounds = bounds_exact(*n_g.pathvector); + if (bounds) { + n_g.bbox[0] = bounds->left(); + n_g.bbox[1] = bounds->top(); + n_g.bbox[2] = bounds->right(); + n_g.bbox[3] = bounds->bottom(); + } } glyphs[nbGlyph]=n_g; id_to_no[glyph_id]=nbGlyph; @@ -720,29 +726,6 @@ Geom::OptRect font_instance::BBox(int glyph_id) } } -Path* font_instance::Outline(int glyph_id,Path* copyInto) -{ - int no = -1; - if ( id_to_no.find(glyph_id) == id_to_no.end() ) { - LoadGlyph(glyph_id); - if ( id_to_no.find(glyph_id) == id_to_no.end() ) { - // didn't load - } else { - no = id_to_no[glyph_id]; - } - } else { - no = id_to_no[glyph_id]; - } - if ( no < 0 ) return NULL; - Path *src_o = glyphs[no].outline; - if ( copyInto ) { - copyInto->Reset(); - copyInto->Copy(src_o); - return copyInto; - } - return src_o; -} - Geom::PathVector* font_instance::PathVector(int glyph_id) { int no = -1; diff --git a/src/libnrtype/font-glyph.h b/src/libnrtype/font-glyph.h index 234502f9d..14da5025b 100644 --- a/src/libnrtype/font-glyph.h +++ b/src/libnrtype/font-glyph.h @@ -11,7 +11,6 @@ struct font_glyph { double v_advance, v_width; double bbox[4]; // bbox of the path (and the artbpath), not the bbox of the glyph // as the fonts sometimes contain - Path* outline; // outline as a livarot Path Geom::PathVector* pathvector; // outline as 2geom pathvector, for text->curve stuff (should be unified with livarot) }; diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h index e9bd291d2..392ac20bf 100644 --- a/src/libnrtype/font-instance.h +++ b/src/libnrtype/font-instance.h @@ -55,9 +55,6 @@ public: // nota: all coordinates returned by these functions are on a [0..1] scale; you need to multiply // by the fontsize to get the real sizes - Path* Outline(int glyph_id, Path *copyInto=NULL); - // queries the outline of the glyph (in livarot Path form), and copies it into copyInto instead - // of allocating a new Path if copyInto != NULL Geom::PathVector* PathVector(int glyph_id); // returns the 2geom-type pathvector for this glyph. no refcounting needed, it's deallocated when the font_instance dies double Advance(int glyph_id, bool vertical); |
