summaryrefslogtreecommitdiffstats
path: root/src/extension/internal/text_reassemble.c
diff options
context:
space:
mode:
authorDavid Mathog <mathog@caltech.edu>2014-02-08 07:17:30 +0000
committer~suv <suv-sf@users.sourceforge.net>2014-02-08 07:17:30 +0000
commit042cc81dd7c3ca2f0d42b68356f4b450074c8473 (patch)
treef9acbfb046848f7cd420a1fbdf718bdcd604ed11 /src/extension/internal/text_reassemble.c
parentExtensions->Render submenu. Scaling of input parameters into document units, ... (diff)
downloadinkscape-042cc81dd7c3ca2f0d42b68356f4b450074c8473.tar.gz
inkscape-042cc81dd7c3ca2f0d42b68356f4b450074c8473.zip
EMF/WMF support: Various changes (see bug #1263242 c35 for details)
EMF support: - linear gradients: improve numeric stability on round-trip editing - linear gradients: fix scaling issue libTERE/text_reassemble update: - improve handling of whitespace created with large x kerns - fix handling of absolute RTL-positioning of LTR text in EMF files WMF support: - fix support for 'textout' records and Placeable headers - add support for CREATEPATTERNBRUSH - fix offset on load if opened via GUI (bug #1250250) Fixed bugs: - https://launchpad.net/bugs/1263242 - https://launchpad.net/bugs/1250250 (bzr r13008)
Diffstat (limited to 'src/extension/internal/text_reassemble.c')
-rw-r--r--src/extension/internal/text_reassemble.c137
1 files changed, 90 insertions, 47 deletions
diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c
index cd84910fc..e28e5effb 100644
--- a/src/extension/internal/text_reassemble.c
+++ b/src/extension/internal/text_reassemble.c
@@ -67,11 +67,11 @@ Optional compiler switches for development:
File: text_reassemble.c
-Version: 0.0.10
-Date: 06-MAY-2013
+Version: 0.0.12
+Date: 07-FEB-2014
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2013 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2014 David Mathog and California Institute of Technology (Caltech)
*/
#ifdef __cplusplus
@@ -665,7 +665,7 @@ FT_INFO *ftinfo_clear(FT_INFO *fti){
free(fsp->file); /* release memory holding copies of paths */
free(fsp->fontspec); /* release memory holding copies of font names */
FcPatternDestroy(fsp->fpat); /* release memory for FontConfig fpats */
- FcFontSetDestroy(fti->fonts[i].fontset);
+ FcFontSetDestroy(fsp->fontset);
if(fsp->alts){ free(fsp->alts); }
}
free(fti->fonts);
@@ -726,9 +726,10 @@ int ftinfo_find_loaded_by_src(const FT_INFO *fti, const uint8_t *filename){
*/
int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){
- FcPattern *pattern, *fpat;
- FcFontSet *fontset;
- FcResult result = FcResultMatch;
+ FcPattern *pattern = NULL;
+ FcPattern *fpat = NULL;
+ FcFontSet *fontset = NULL;
+ FcResult result = FcResultMatch;
char *filename;
double fd;
FNT_SPECS *fsp;
@@ -738,38 +739,45 @@ int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){
if(!fti)return(-1);
/* If it is already loaded, do not load it again */
- if((status = ftinfo_find_loaded_by_spec(fti, (uint8_t *) fontspec))>=0){
- return(status);
- }
+ status = ftinfo_find_loaded_by_spec(fti, (uint8_t *) fontspec);
+ if(status >= 0){ return(status); }
+ status = 0; /* was -1, reset to 0 */
ftinfo_make_insertable(fti);
fi_idx = fti->used;
- if(!(pattern = FcNameParse((const FcChar8 *)fontspec)) )return(2);
- if(!FcConfigSubstitute(NULL, pattern, FcMatchPattern) )return(3);
- FcDefaultSubstitute(pattern);
- /* get a fontset, trimmed to only those with new glyphs as needed, so that missing glyph's may be handled */
- if(!(fontset = FcFontSort (NULL,pattern, FcTrue, NULL, &result))
- || result != FcResultMatch)return(4);
- if(!(fpat = FcFontRenderPrepare(NULL, pattern, fontset->fonts[0])) )return(405);
- if(FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch)return(5);
- if(FcPatternGetDouble( fpat, FC_SIZE, 0, &fd) != FcResultMatch)return(6);
-
- /* copy these into memory for external use */
- fsp = &(fti->fonts[fti->used]);
- fsp->fontset = fontset;
- fsp->alts = NULL; /* Initially no links to alternate fonts */
- fsp->space = 0;
- fsp->file = (uint8_t *) U_strdup((char *) filename);
- fsp->fontspec = (uint8_t *) U_strdup((char *) fontspec);
- fsp->fpat = fpat;
- fsp->fsize = fd;
-
+ pattern = FcNameParse((const FcChar8 *)fontspec);
+ while(1) { /* this is NOT a loop, it uses breaks to avoid gotos and deep nesting */
+ if(!(pattern)){ status = -2; break; }
+ if(!FcConfigSubstitute(NULL, pattern, FcMatchPattern)){ status = -3; break; };
+ FcDefaultSubstitute(pattern);
+ /* get a fontset, trimmed to only those with new glyphs as needed, so that missing glyph's may be handled */
+ if(!(fontset = FcFontSort (NULL,pattern, FcTrue, NULL, &result)) || (result != FcResultMatch)){ status = -4; break; }
+ if(!(fpat = FcFontRenderPrepare(NULL, pattern, fontset->fonts[0]))){ status = -405; break; }
+ if(FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch){ status = -5; break; }
+ if(FcPatternGetDouble( fpat, FC_SIZE, 0, &fd) != FcResultMatch){ status = -6; break; }
+
+ /* copy these into memory for external use */
+ fsp = &(fti->fonts[fti->used]);
+ fsp->fontset = fontset;
+ fsp->alts = NULL; /* Initially no links to alternate fonts */
+ fsp->space = 0;
+ fsp->file = (uint8_t *) U_strdup((char *) filename);
+ fsp->fontspec = (uint8_t *) U_strdup((char *) fontspec);
+ fsp->fpat = fpat;
+ fsp->fsize = fd;
+ break;
+ }
/* release FC's own memory related to this call that does not need to be kept around so that face will work */
- FcPatternDestroy(pattern);
+ if(pattern)FcPatternDestroy(pattern); /* done with this memory */
+ if(status<0){
+ if(fontset)FcFontSetDestroy(fontset);
+ if(fpat)FcPatternDestroy(fpat);
+ return(status);
+ }
/* get the current face */
- if(FT_New_Face( fti->library, (const char *) fsp->file, 0, &(fsp->face) )){ return(8); }
+ if(FT_New_Face( fti->library, (const char *) fsp->file, 0, &(fsp->face) )){ return(-8); }
if(FT_Set_Char_Size(
fsp->face, /* handle to face object */
@@ -777,12 +785,12 @@ int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){
fd*64, /* char_height in 1/64th of points */
72, /* horizontal device resolution, DPI */
72) /* vebrical device resolution, DPI */
- ){ return(9); }
+ ){ return(-9); }
/* The space advance is needed in various places. Get it now, and get it in the font units,
so that it can be scaled later with the text size */
status = TR_getadvance(fti, fsp,' ',0,FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED, NULL, NULL);
- if(status < 0)return(7);
+ if(status < 0)return(-7);
fsp->spcadv = ((double) status)/(64.0);
fti->used++;
@@ -1380,7 +1388,7 @@ printf("Overlap rprect (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n
}
/**
- \brief Check for a text element upstream from the start element and in the reversed direction.
+ \brief Check for various sorts of invalid text elements upstream (language dir changes, draw order backwards from language direction)
\returns 0 on success (not upstream), 1 if upstream, anything else is an error.
\param bri pointer to the BR_INFO structure
\param dst index of the destination bounding rectangle.
@@ -1405,6 +1413,12 @@ int brinfo_upstream(BR_INFO *bri, int dst, int src, int ddir, int sdir){
else if( ddir == LDIR_LR && sdir == LDIR_RL){
if((br_src->xll + br_src->xur)/2.0 <= br_dst->xll ){ status = 1; }
}
+ else if( ddir == LDIR_RL && sdir == LDIR_RL){
+ if(br_dst->xur <= (br_src->xll + br_src->xur)/2.0){ status = 1; }
+ }
+ else if( ddir == LDIR_LR && sdir == LDIR_LR){
+ if((br_src->xll + br_src->xur)/2.0 <= br_dst->xll ){ status = 1; }
+ }
return(status);
}
@@ -1490,13 +1504,19 @@ TR_INFO *trinfo_init(TR_INFO *tri){
!(tri->bri = brinfo_init()) ||
!(tri->cxi = cxinfo_init())
){ tri = trinfo_release(tri); }
+ tri->out = NULL; /* This will allocate as needed, it might not ever be needed. */
+ tri->qe = 0.0;
+ tri->esc = 0.0;
+ tri->x = DBL_MAX;
+ tri->y = DBL_MAX;
+ tri->dirty = 0;
tri->use_kern = 1;
- tri->usebk = BKCLR_NONE;
tri->load_flags = FT_LOAD_NO_SCALE;
tri->kern_mode = FT_KERNING_UNSCALED;
- tri->out = NULL; /* This will allocate as needed, it might not ever be needed. */
tri->outspace = 0;
tri->outused = 0;
+ tri->usebk = BKCLR_NONE;
+ memset(&(tri->bkcolor),0,sizeof(TRCOLORREF));
return(tri);
}
@@ -1552,9 +1572,6 @@ TR_INFO *trinfo_release_except_FC(TR_INFO *tri){
*/
TR_INFO *trinfo_clear(TR_INFO *tri){
if(tri){
- tri->dirty = 0; /* set these back to their defaults */
- tri->esc = 0.0;
- /* Do NOT modify use_kern, usebk, load_flags, or kern_mode */
if(tri->bri)tri->bri=brinfo_release(tri->bri);
if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi);
@@ -1565,6 +1582,11 @@ TR_INFO *trinfo_clear(TR_INFO *tri){
tri->outused = 0;
tri->outspace = 0;
};
+ /* Do NOT modify: qe, use_kern, usebk, load_flags, kern_mode, or bkcolor. Set the rest back to their defaults */
+ tri->esc = 0.0;
+ tri->x = DBL_MAX;
+ tri->y = DBL_MAX;
+ tri->dirty = 0;
if(!(tri->tpi = tpinfo_init()) || /* re-init the pieces just released */
!(tri->bri = brinfo_init()) ||
!(tri->cxi = cxinfo_init())
@@ -1958,7 +1980,7 @@ void TR_layout_2_svg(TR_INFO *tri){
cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":");
sprintf(obuf,"font-family:%.*s;",cutat,fti->fonts[tsp->fi_idx].fontspec);
TRPRINT(tri, obuf);
- sprintf(obuf,"\n\">%s</text>\n",tsp->string);
+ sprintf(obuf,"\n\">%s</text>\n",&tsp->string[tsp->spaces]);
TRPRINT(tri, obuf);
#endif /* DBG_TR_INPUT debugging code, original text objects */
}
@@ -2278,7 +2300,10 @@ int TR_layout_analyze(TR_INFO *tri){
next logical piece of text is "upstream" positionally of its logical predecessor. The meaning of such
a construct is at best ambiguous. The test is only applied with respect to the first text chunk. This sort
of construct may appear when a valid initial construct like [1->English][2<-Hebrew][3->English] is edited
- and the leading chunk of text removed.
+ and the leading chunk of text removed.
+
+ Also reject reversed order text as in (English) <A><B><C> (draw order) arranged as <C><B><A>. This happens
+ if the language direction field is incorrect, perhaps due to a corrupt or malformed input file.
*/
if(brinfo_upstream(bri,
dst_rt, /* index into bri for dst */
@@ -2422,10 +2447,28 @@ int TR_layout_analyze(TR_INFO *tri){
}
}
- /* if x or y kern is less than the quantization error it is probably noise, set it to zero */
- if(fabs(tspj->xkern)<tri->qe)tspj->xkern = 0.0;
- if(fabs(tspj->ykern)<tri->qe)tspj->ykern = 0.0;
-
+ /* if x or y kern is less than twice the quantization error it is probably noise, set it to zero */
+ if(fabs(tspj->xkern) <= 2.0*tri->qe)tspj->xkern = 0.0;
+ if(fabs(tspj->ykern) <= 2.0*tri->qe)tspj->ykern = 0.0;
+
+ /* reintroduce spaces on the leading edge of text "j" if the kerning can be in part or in whole replaced
+ with 1 or 2 spaces */
+ if(tspj->ykern == 0.0){
+ double spaces = tspj->xkern/spcadv; /* negative on RL language, positive on LR */
+ if((ldir == LDIR_RL && (spaces <= -0.9 && spaces >= -2.1)) ||
+ (ldir == LDIR_LR && (spaces >= 0.9 && spaces <= 2.1)) ){
+ int ispaces = lround(spaces);
+ tspj->xkern -= ((double)ispaces*spcadv);
+ if(ispaces<0)ispaces=-ispaces;
+ size_t slen = strlen((char *)tspj->string);
+ uint8_t *newstring = malloc(1 + ispaces + slen);
+ sprintf((char *)newstring," "); /* start with two spaces, possibly overwrite one in the next line */
+ memcpy(newstring+ispaces,tspj->string,slen+1); /* copy existing string to proper position */
+ free(tspj->string);
+ tspj->string = newstring;
+ tspj->spaces = ispaces; // only needed to fix optional debugging SVG output later
+ }
+ }
tspi = tspj;
lastldir = ldir;
@@ -2699,7 +2742,7 @@ int main(int argc, char *argv[]){
tsp.weight = 80;
tsp.condensed = 100;
tsp.decoration = 0; /* none */
- tsp.co = 0;
+ tsp.spaces = 0; /* none */
tsp.fi_idx = -1; /* set to an invalid */
tsp.rt_tidx = -1; /* set to an invalid */
tsp.xkern = tsp.ykern = 0.0;