summaryrefslogtreecommitdiffstats
path: root/src/libnrtype
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-08-14 14:32:13 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2010-08-14 14:32:13 +0000
commitd1dbd5e4ca7917b5734a5cd011907176b311d158 (patch)
tree2ce69589b16fe70ffb15aba93bfb598fd7bd6d07 /src/libnrtype
parentFix crash on empty patterns (diff)
downloadinkscape-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.cpp175
-rw-r--r--src/libnrtype/font-glyph.h1
-rw-r--r--src/libnrtype/font-instance.h3
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);