[mapserver-commits] r7931 - trunk/mapserver
svn at osgeo.org
svn at osgeo.org
Sun Sep 28 13:29:54 EDT 2008
Author: tbonfort
Date: 2008-09-28 13:29:54 -0400 (Sun, 28 Sep 2008)
New Revision: 7931
Modified:
trunk/mapserver/maplabel.c
trunk/mapserver/mapstring.c
Log:
add comments for rfc40
a few memory optimizations in line centering
Modified: trunk/mapserver/maplabel.c
===================================================================
--- trunk/mapserver/maplabel.c 2008-09-26 18:08:09 UTC (rev 7930)
+++ trunk/mapserver/maplabel.c 2008-09-28 17:29:54 UTC (rev 7931)
@@ -49,6 +49,9 @@
* the function:
* text = msWrapText(label,text);
*
+ * TODO/FIXME: function will produce erroneous/crashing? results
+ * if the wrap character is encoded with multiple bytes
+ *
* see http://mapserver.gis.umn.edu/development/rfc/ms-rfc-40/
* for a summary of how wrap/maxlength interact on the result
* of the text transformation
@@ -56,40 +59,47 @@
char *msWrapText(labelObj *label, char *text) {
char wrap;
int maxlength;
- if(!text)
+ if(!text) /*not an error if no text*/
return text;
wrap = label->wrap;
maxlength = label->maxlength;
if(maxlength == 0) {
if(wrap!='\0') {
- /* if maxlength = 0 and a wrap character was specified, replace
- * all wrap characters by \n
+ /* if maxlength = 0 *and* a wrap character was specified,
+ * replace all wrap characters by \n
+ * this is the traditional meaning of the wrap character
*/
msReplaceChar(text, wrap, '\n');
}
/* if neither maxlength, nor wrap were specified,
- * don't transform this text
- */
+ * don't transform this text */
return text;
} else if(maxlength>0) {
if(wrap!='\0') {
+ /* split input text at the wrap character, only if
+ * the current line length is over maxlength */
+
+ /* TODO: check if the wrap character is a valid byte
+ * inside a multibyte utf8 glyph. if so, the msCountChars
+ * will return an erroneous value */
int numwrapchars = msCountChars(text,wrap);
+
if(numwrapchars > 0) {
if(label->encoding) {
-/*
- * we have to use utf decoding functions here, so as not to
- * split a text line on a multibyte character
- */
- int num_cur_glyph_on_line = 0;
+ /* we have to use utf decoding functions here, so as not to
+ * split a text line on a multibyte character */
+
+ int num_cur_glyph_on_line = 0; /*count for the number of glyphs
+ on the current line*/
char *textptr = text;
- char glyph[11];
- int glyphlen = 0;
+ char glyph[11]; /*storage for unicode fetching function*/
+ int glyphlen = 0; /*size of current glyph in bytes*/
while((glyphlen = msGetNextGlyph((const char**)&textptr,glyph))>0) {
num_cur_glyph_on_line++;
if(*glyph == wrap && num_cur_glyph_on_line>=(maxlength)) {
/*FIXME (if wrap becomes something other than char):*/
- *(textptr-1)='\n';
- num_cur_glyph_on_line=0;
+ *(textptr-1)='\n'; /*replace wrap char with a \n*/
+ num_cur_glyph_on_line=0; /*reset count*/
}
}
} else {
@@ -98,21 +108,20 @@
while(*textptr != 0) {
cur_char_on_line++;
if(*textptr == wrap && cur_char_on_line>=maxlength) {
- *textptr='\n';
- cur_char_on_line=0;
+ *textptr='\n'; /*replace wrap char with a \n*/
+ cur_char_on_line=0; /*reset count*/
}
textptr++;
}
}
return text;
} else {
- /*text is shorter than fixed limit*/
+ /*there are no characters available for wrapping*/
return text;
}
} else {
- /*don't draw this label if it is longer thant the specified length
- * and no wrap character was specified
- */
+ /* if no wrap character was specified, but a maxlength was,
+ * don't draw this label if it is longer than the specified maxlength*/
if(msGetNumGlyphs(text)>maxlength) {
free(text);
return NULL;
@@ -120,11 +129,13 @@
return text;
}
}
- } else { /*maxlength<0*/
+ } else { /* negative maxlength: we split lines unconditionally, i.e. without
+ loooking for a wrap character*/
int numglyphs,numlines;
- maxlength = -maxlength;
+ maxlength = -maxlength; /* use a positive value*/
numglyphs = msGetNumGlyphs(text);
- numlines = numglyphs / maxlength;
+ numlines = numglyphs / maxlength; /*count total number of lines needed
+ after splitting*/
if(numlines>1) {
char *newtext = malloc(strlen(text)+numlines+1);
char *newtextptr = newtext;
@@ -134,6 +145,7 @@
num_cur_glyph++;
newtextptr += glyphlen;
if(num_cur_glyph%maxlength == 0 && num_cur_glyph != numglyphs) {
+ /*we're at a split location, insert a newline*/
*newtextptr = '\n';
newtextptr++;
}
@@ -141,46 +153,81 @@
free(text);
return newtext;
} else {
+ /*no splitting needed, return the original*/
return text;
}
}
}
char *msAlignText(mapObj *map, imageObj *image, labelObj *label, char *text) {
- double spacewidth=0.0;
+ double spacewidth=0.0; /*size of a single space, in fractional pixels*/
int numlines;
char **textlines,*newtext,*newtextptr;
int *textlinelengths,*numspacesforpadding;
int numspacestoadd,maxlinelength,i;
rectObj label_rect;
+ if(!msCountChars(text,'\n'))
+ return text; /*only one line*/
+
+ /*split text into individual lines
+ * TODO: check if splitting on \n is utf8 safe*/
+ textlines = msStringSplit(text,'\n',&numlines);
+
+ /*
+ * label->space_size_10 contains a cache for the horizontal size of a single
+ * 'space' character, at size 10 for the current label
+ * FIXME: in case of attribute binding for the FONT of the label, this cache will
+ * be wrong for labels where the attributed font is different than the first
+ * computed font. This shouldn't happen too often, and hopefully the size of a
+ * space character shouldn't vary too much between different fonts*/
if(label->space_size_10 == 0.0) {
+ /*if the cache hasn't been initialized yet, or with pixmap fonts*/
int size;
if(label->type == MS_TRUETYPE) {
- size = label->size;
+ size = label->size; /*keep a copy of the original size*/
label->size=10;
}
- if(msGetLabelSize(image, " ", label, &label_rect, &map->fontset, 1.0, MS_FALSE)==-1)
- return text; /*error*/
+ /* compute the size of 16 adjacent spaces. we can't do this for just one space,
+ * as the labelSize computing functions return integer bounding boxes. we assume
+ * that the integer rounding for such a number of spaces will be negligeable
+ * compared to the actual size of thoses spaces */
+ if(msGetLabelSize(image, " ", label,&label_rect,
+ &map->fontset, 1.0, MS_FALSE)==-1) {
+ /*error computing label size, we can't continue*/
+
+ /*free the previously allocated split text*/
+ while(numlines--)
+ free(textlines[numlines]);
+ free(textlines);
+ return text;
+ }
+
+ /* this is the size of a single space character. for truetype fonts,
+ * it's the size of a 10pt space. For pixmap fonts, it's the size
+ * for the current label */
spacewidth = (label_rect.maxx-label_rect.minx)/16.0;
if(label->type == MS_TRUETYPE) {
- label->size = size;
- label->space_size_10=spacewidth;
+ label->size = size; /*restore original label size*/
+ label->space_size_10=spacewidth; /*cache the computed size*/
+
+ /*size of a space for current label size*/
spacewidth = spacewidth * (double)label->size/10.0;
}
} else {
spacewidth = label->space_size_10 * (double)label->size/10.0;
}
- textlines = msStringSplit(text,'\n',&numlines);
- if(numlines==1) {
- /*nothing to do*/
- free(textlines[0]);
- free(textlines);
- return text;
- }
-
+
+
+ /*length in pixels of each line*/
textlinelengths = (int*)malloc(numlines*sizeof(int));
+
+ /*number of spaces that need to be added to each line*/
numspacesforpadding = (int*)malloc(numlines*sizeof(int));
+
+ /*total number of spaces that need to be added*/
numspacestoadd=0;
+
+ /*length in pixels of the longest line*/
maxlinelength=0;
for(i=0;i<numlines;i++) {
msGetLabelSize(image, textlines[i], label, &label_rect, &map->fontset, 1.0, MS_FALSE);
@@ -189,8 +236,10 @@
maxlinelength=textlinelengths[i];
}
for(i=0;i<numlines;i++) {
+ /* number of spaces to add so the current line is
+ * as long as the longest line */
double nfracspaces = (maxlinelength - textlinelengths[i])/spacewidth;
- numspacesforpadding[i]=MS_NINT(((maxlinelength - textlinelengths[i])/2.0)/(spacewidth));
+
if(label->align == MS_ALIGN_CENTER) {
numspacesforpadding[i]=MS_NINT(nfracspaces/2.0);
} else {
@@ -200,19 +249,26 @@
}
numspacestoadd+=numspacesforpadding[i];
}
+
+ /*allocate new text with room for the additional spaces needed*/
newtext = (char*)malloc(strlen(text)+1+numspacestoadd);
newtextptr=newtext;
for(i=0;i<numlines;i++) {
int j;
+ /*padd beginning of line with needed spaces*/
for(j=0;j<numspacesforpadding[i];j++) {
*(newtextptr++)=' ';
}
+ /*copy original line*/
strcpy(newtextptr,textlines[i]);
+ /*place pointer at the char right after the current line*/
newtextptr+=strlen(textlines[i])+1;
if(i!=numlines-1) {
- *(newtextptr-1)='\n';
+ /*put the \n back in (was taken away by msStringSplit)*/
+ *(newtextptr-1)='\n';
}
}
+ /*free the original text*/
free(text);
for(i=0;i<numlines;i++) {
free(textlines[i]);
@@ -220,8 +276,13 @@
free(textlines);
free(textlinelengths);
free(numspacesforpadding);
+
+ /*return the aligned text. note that the terminating \0 was added by the last
+ * call to strcpy */
return newtext;
}
+
+
/*
* this function applies the label encoding and wrap parameters
* to the supplied text
Modified: trunk/mapserver/mapstring.c
===================================================================
--- trunk/mapserver/mapstring.c 2008-09-26 18:08:09 UTC (rev 7930)
+++ trunk/mapserver/mapstring.c 2008-09-28 17:29:54 UTC (rev 7931)
@@ -1686,23 +1686,35 @@
* msGetFirstLine()
*
* returns the first line of a given string.
- * used for calculating the baseline of labels
+ * called by getLabelSize functions for calculating
+ * the baseline offsets of labels
+ *
+ * this function was implemented to avoid using the
+ * msSplitString function and its multiple mallocs, as
+ * only one malloc is used here.
+ *
+ * this function can be called if the input isn't a
+ * multiline string, but this wastes a malloc
*/
char* msGetFirstLine(char* text) {
- int firstLineLength=0;
+ int firstLineLength=0; /*number of bytes up to first \n character */
int glyphLength;
char glyph[11];
const char *textptr=text;
char *firstLine,*firstLineCur;
+ /*loop through glyphs in text*/
while((glyphLength=msGetNextGlyph(&textptr,glyph))) {
- if(glyphLength==1 && *glyph=='\n') {
+ if(glyphLength==1 && *glyph=='\n') { /*we've hit the first \n char*/
firstLineCur = firstLine = malloc(firstLineLength+1);
+
+ /*copy the first line into the return array*/
while(firstLineLength--) {
*firstLineCur++ = *text++;
}
*firstLineCur='\0';
return firstLine;
}
+ /*increment byte count if we haven't hit a \n yet*/
firstLineLength+=glyphLength;
}
/*no newline found in text*/
More information about the mapserver-commits
mailing list