int renderTruetypeSymbolCairo(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *s) { int unicode; cairo_glyph_t glyph; cairo_text_extents_t extents; cairo_matrix_t trans; double ox,oy; cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img); cairo_renderer *r = CAIRO_RENDERER(img); faceCacheObj *face = getFontFace(cache,symbol->full_font_path); if(!face) return MS_FAILURE; cairo_save(r->cr); cairo_set_font_face(r->cr,face->face); cairo_set_font_size(r->cr,s->scale*96/72.0); msUTF8ToUniChar(symbol->character, &unicode); if (face->ftface->charmap && face->ftface->charmap->encoding == FT_ENCODING_MS_SYMBOL) unicode |= 0xf000; glyph.index = FT_Get_Char_Index(face->ftface, unicode); glyph.x=0; glyph.y=0; cairo_glyph_extents(r->cr,&glyph,1,&extents); ox=extents.x_bearing+extents.width/2.; oy=extents.y_bearing+extents.height/2.; cairo_matrix_init_rotate(&trans,-s->rotation); cairo_matrix_transform_point(&trans,&ox,&oy); /* cairo_translate(cr,-extents.width/2,-extents.height/2); */ cairo_translate(r->cr,x-ox,y-oy); cairo_rotate(r->cr, -s->rotation); cairo_glyph_path(r->cr,&glyph,1); if (s->outlinewidth) { msCairoSetSourceColor(r->cr, s->outlinecolor); cairo_set_line_width(r->cr, s->outlinewidth + 1); cairo_stroke_preserve(r->cr); } if(s->color) { msCairoSetSourceColor(r->cr, s->color); cairo_fill_preserve(r->cr); } cairo_new_path(r->cr); cairo_restore(r->cr); return MS_SUCCESS; }
int agg2RenderTruetypeSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj * style) { AGG2Renderer *r = AGG_RENDERER(img); aggRendererCache *cache = (aggRendererCache*)MS_RENDERER_CACHE(MS_IMAGE_RENDERER(img)); if(aggLoadFont(cache,symbol->full_font_path,style->scale) == MS_FAILURE) return MS_FAILURE; int unicode; font_curve_type m_curves(cache->m_fman.path_adaptor()); msUTF8ToUniChar(symbol->character, &unicode); const mapserver::glyph_cache* glyph = cache->m_fman.glyph(unicode); double ox = (glyph->bounds.x1 + glyph->bounds.x2) / 2.; double oy = (glyph->bounds.y1 + glyph->bounds.y2) / 2.; mapserver::trans_affine mtx = mapserver::trans_affine_translation(-ox, -oy); if(style->rotation) mtx *= mapserver::trans_affine_rotation(-style->rotation); mtx *= mapserver::trans_affine_translation(x, y); mapserver::path_storage glyphs; cache->m_fman.init_embedded_adaptors(glyph, 0,0); mapserver::conv_transform<font_curve_type, mapserver::trans_affine> trans_c(m_curves, mtx); glyphs.concat_path(trans_c); if (style->outlinecolor) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); mapserver::conv_contour<mapserver::path_storage> cc(glyphs); cc.auto_detect_orientation(true); cc.width(style->outlinewidth + 1); r->m_rasterizer_aa.add_path(cc); r->m_renderer_scanline.color(aggColor(style->outlinecolor)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } if (style->color) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); r->m_rasterizer_aa.add_path(glyphs); r->m_renderer_scanline.color(aggColor(style->color)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } return MS_SUCCESS; }
int msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p, styleObj *style, double scalefactor) { int ret = MS_SUCCESS; if (!p) return MS_SUCCESS; if (style->symbol >= map->symbolset.numsymbols || style->symbol <= 0) return MS_SUCCESS; /* no such symbol, 0 is OK */ if (image) { if(MS_RENDERER_PLUGIN(image->format)) { rendererVTableObj *renderer = image->format->vtable; symbolStyleObj s; double p_x,p_y; symbolObj *symbol = map->symbolset.symbol[style->symbol]; /* store a reference to the renderer to be used for freeing */ symbol->renderer = renderer; if(preloadSymbol(&map->symbolset,symbol,renderer) != MS_SUCCESS) { return MS_FAILURE; } computeSymbolStyle(&s,style,symbol,scalefactor,image->resolutionfactor); s.style = style; if (!s.color && !s.outlinecolor && symbol->type != MS_SYMBOL_PIXMAP && symbol->type != MS_SYMBOL_SVG) { return MS_SUCCESS; // nothing to do if no color, except for pixmap symbols } if(s.scale == 0) { return MS_SUCCESS; } /* TODO: skip the drawing of the symbol if it's smaller than a pixel ? if (s.size < 1) return; // size too small */ p_x = p->x; p_y = p->y; if (style->polaroffsetpixel != 0 || style->polaroffsetangle != 0) { double angle = style->polaroffsetangle * MS_DEG_TO_RAD; p_x += (style->polaroffsetpixel * cos(-angle)) * scalefactor; p_y += (style->polaroffsetpixel * sin(-angle)) * scalefactor; } p_x += style->offsetx * scalefactor; p_y += style->offsety * scalefactor; if(symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) { double sx,sy; double ox, oy; if(UNLIKELY(MS_FAILURE == msGetMarkerSize(map, style, &sx, &sy, scalefactor))) { return MS_FAILURE; } ox = (0.5 - symbol->anchorpoint_x) * sx; oy = (0.5 - symbol->anchorpoint_y) * sy; if(s.rotation != 0) { double sina, cosa; double rox,roy; sina = sin(-s.rotation); cosa = cos(-s.rotation); rox = ox * cosa - oy * sina; roy = ox * sina + oy * cosa; p_x += rox; p_y += roy; } else { p_x += ox; p_y += oy; } } if(renderer->use_imagecache) { imageObj *tile = getTile(image, symbol, &s, -1, -1,0); if(tile!=NULL) return renderer->renderTile(image, tile, p_x, p_y); else { msSetError(MS_RENDERERERR, "problem creating cached tile", "msDrawMarkerSymbol()"); return MS_FAILURE; } } switch (symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &map->fontset); if(UNLIKELY(!face)) return MS_FAILURE; msUTF8ToUniChar(symbol->character,&unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face,s.scale,unicode); if(UNLIKELY(!glyphc)) return MS_FAILURE; ret = drawGlyphMarker(image, face, glyphc, p_x, p_y, s.scale, s.rotation, s.color, s.outlinecolor, s.outlinewidth); } break; case (MS_SYMBOL_PIXMAP): { assert(symbol->pixmap_buffer); ret = renderer->renderPixmapSymbol(image,p_x,p_y,symbol,&s); } break; case (MS_SYMBOL_ELLIPSE): { ret = renderer->renderEllipseSymbol(image, p_x, p_y,symbol, &s); } break; case (MS_SYMBOL_VECTOR): { ret = renderer->renderVectorSymbol(image, p_x, p_y, symbol, &s); } break; case (MS_SYMBOL_SVG): { if (renderer->supports_svg) { ret = renderer->renderSVGSymbol(image, p_x, p_y, symbol, &s); } else { #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) ret = msRenderRasterizedSVGSymbol(image, p_x,p_y, symbol, &s); #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msDrawMarkerSymbol()"); return MS_FAILURE; #endif } } break; default: break; } return ret; } else if( MS_RENDERER_IMAGEMAP(image->format) ) msDrawMarkerSymbolIM(map, image, p, style, scalefactor); } return ret; }
int msImagePolylineMarkers(imageObj *image, shapeObj *p, symbolObj *symbol, symbolStyleObj *style, double spacing, double initialgap, int auto_angle) { rendererVTableObj *renderer = MS_IMAGE_RENDERER(image); int i,j; pointObj point; double original_rotation = style->rotation; double symbol_width,symbol_height; glyph_element *glyphc = NULL; face_element *face; int ret = MS_SUCCESS; if(symbol->type != MS_SYMBOL_TRUETYPE) { symbol_width = MS_MAX(1,symbol->sizex*style->scale); symbol_height = MS_MAX(1,symbol->sizey*style->scale); } else { unsigned int unicode; msUTF8ToUniChar(symbol->character, &unicode); face = msGetFontFace(symbol->font, &image->map->fontset); if(UNLIKELY(!face)) return MS_FAILURE; unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, style->scale, unicode); if(UNLIKELY(!glyphc)) return MS_FAILURE; symbol_width = glyphc->metrics.maxx - glyphc->metrics.minx; symbol_height = glyphc->metrics.maxy - glyphc->metrics.miny; } for(i=0; i<p->numlines; i++) { int line_in = 0; double line_length=0; double current_length; if(initialgap < 0) { current_length = spacing/2.0; /* initial padding for each line */ } else { current_length = initialgap; /* initial padding for each line */ } for(j=1; j<p->line[i].numpoints; j++) { double rx,ry,theta,length; length = sqrt((pow((p->line[i].point[j].x - p->line[i].point[j-1].x),2) + pow((p->line[i].point[j].y - p->line[i].point[j-1].y),2))); line_length += length; if(length==0)continue; rx = (p->line[i].point[j].x - p->line[i].point[j-1].x)/length; ry = (p->line[i].point[j].y - p->line[i].point[j-1].y)/length; if (auto_angle) { theta = asin(ry); if(rx < 0) { theta += MS_PI; } else theta = -theta; style->rotation = original_rotation + theta; } while (current_length <= length) { point.x = p->line[i].point[j - 1].x + current_length * rx; point.y = p->line[i].point[j - 1].y + current_length * ry; if(symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) { double ox, oy; ox = (0.5 - symbol->anchorpoint_x) * symbol_width; oy = (0.5 - symbol->anchorpoint_y) * symbol_height; if(style->rotation != 0) { double sina,cosa; double rox,roy; sina = sin(-style->rotation); cosa = cos(-style->rotation); rox = ox * cosa - oy * sina; roy = ox * sina + oy * cosa; point.x += rox; point.y += roy; } else { point.x += ox; point.y += oy; } } /* if the point is not in the map extent, skip it. (POLYLINE_NO_CLIP) */ if ( (point.x < -(symbol_width) || point.x > (image->width+symbol_width)) || (point.y < -(symbol_height) || point.y > (image->height+symbol_height)) ) { current_length += spacing; line_in=1; continue; } switch (symbol->type) { case MS_SYMBOL_PIXMAP: ret = renderer->renderPixmapSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_ELLIPSE: ret = renderer->renderEllipseSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_VECTOR: ret = renderer->renderVectorSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_TRUETYPE: ret = drawGlyphMarker(image, face, glyphc, point.x, point.y, style->scale, style->rotation, style->color, style->outlinecolor, style->outlinewidth); break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) if (renderer->supports_svg) { ret = renderer->renderSVGSymbol(image, point.x, point.y, symbol, style); } else { ret = msRenderRasterizedSVGSymbol(image,point.x,point.y,symbol, style); } #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msImagePolylineMarkers()()"); ret = MS_FAILURE; #endif break; } if( ret != MS_SUCCESS) return ret; current_length += spacing; line_in=1; } current_length -= length; } /* * if we couldn't place a symbol on the line and no initialgap was * specified, add one now we don't add the symbol if the line is shorter * than the length of the symbol itself */ if(initialgap < 0 && !line_in && line_length>symbol_width) { /* total lengths of beginnning and end of current segment */ double before_length=0,after_length=0; /*optimize*/ line_length /= 2.0; for(j=1; j<p->line[i].numpoints; j++) { double length; length = sqrt((pow((p->line[i].point[j].x - p->line[i].point[j-1].x),2) + pow((p->line[i].point[j].y - p->line[i].point[j-1].y),2))); after_length += length; if(after_length>line_length) { double rx,ry,theta; /* offset where the symbol should be drawn on the current * segment */ double offset = line_length - before_length; rx = (p->line[i].point[j].x - p->line[i].point[j-1].x)/length; ry = (p->line[i].point[j].y - p->line[i].point[j-1].y)/length; if (auto_angle) { theta = asin(ry); if(rx < 0) { theta += MS_PI; } else theta = -theta; style->rotation = original_rotation + theta; } point.x = p->line[i].point[j - 1].x + offset * rx; point.y = p->line[i].point[j - 1].y + offset * ry; switch (symbol->type) { case MS_SYMBOL_PIXMAP: ret = renderer->renderPixmapSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_ELLIPSE: ret = renderer->renderEllipseSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_VECTOR: ret = renderer->renderVectorSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_TRUETYPE: ret = drawGlyphMarker(image, face, glyphc, point.x, point.y, style->scale, style->rotation, style->color, style->outlinecolor, style->outlinewidth); break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) if (renderer->supports_svg) { ret = renderer->renderSVGSymbol(image, point.x, point.y, symbol, style); } else { ret = msRenderRasterizedSVGSymbol(image,point.x,point.y,symbol, style); } #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msImagePolylineMarkers()()"); ret = MS_FAILURE; #endif break; } break; /* we have rendered the single marker for this line */ } before_length += length; } } } return ret; }
imageObj *getTile(imageObj *img, symbolObj *symbol, symbolStyleObj *s, int width, int height, int seamlessmode) { tileCacheObj *tile; int status = MS_SUCCESS; rendererVTableObj *renderer = img->format->vtable; if(width==-1 || height == -1) { width=height=MS_MAX(symbol->sizex,symbol->sizey); } tile = searchTileCache(img,symbol,s,width,height); if(tile==NULL) { imageObj *tileimg; double p_x,p_y; tileimg = msImageCreate(width,height,img->format,NULL,NULL,img->resolution, img->resolution, NULL); if(UNLIKELY(!tileimg)) { return NULL; } if(!seamlessmode) { p_x = width/2.0; p_y = height/2.0; switch(symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &img->map->fontset); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, s->scale, unicode); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); } break; case (MS_SYMBOL_PIXMAP): status = msPreloadImageSymbol(renderer,symbol); if(UNLIKELY(status == MS_FAILURE)) { break; } status = renderer->renderPixmapSymbol(tileimg, p_x, p_y, symbol, s); break; case (MS_SYMBOL_ELLIPSE): status = renderer->renderEllipseSymbol(tileimg, p_x, p_y,symbol, s); break; case (MS_SYMBOL_VECTOR): status = renderer->renderVectorSymbol(tileimg, p_x, p_y, symbol, s); break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) status = msPreloadSVGSymbol(symbol); if(LIKELY(status == MS_SUCCESS)) { if (renderer->supports_svg) { status = renderer->renderSVGSymbol(tileimg, p_x, p_y, symbol, s); } else { status = msRenderRasterizedSVGSymbol(tileimg,p_x,p_y,symbol, s); } } #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "getTile()"); status = MS_FAILURE; #endif break; default: msSetError(MS_SYMERR, "Unknown symbol type %d", "getTile()", symbol->type); status = MS_FAILURE; break; } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tileimg); return NULL; } } else { /* * in seamless mode, we render the the symbol 9 times on a 3x3 grid to account for * antialiasing blending from one tile to the next. We finally keep the center tile */ imageObj *tile3img = msImageCreate(width*3,height*3,img->format,NULL,NULL, img->resolution, img->resolution, NULL); int i,j; rasterBufferObj tmpraster; for(i=1; i<=3; i++) { p_x = (i+0.5)*width; for(j=1; j<=3; j++) { p_y = (j+0.5) * height; switch(symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &img->map->fontset); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, s->scale, unicode); if(UNLIKELY(!glyphc)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); } break; case (MS_SYMBOL_PIXMAP): status = msPreloadImageSymbol(renderer,symbol); if(UNLIKELY(status == MS_FAILURE)) { break; } status = renderer->renderPixmapSymbol(tile3img, p_x, p_y, symbol, s); break; case (MS_SYMBOL_ELLIPSE): status = renderer->renderEllipseSymbol(tile3img, p_x, p_y,symbol, s); break; case (MS_SYMBOL_VECTOR): status = renderer->renderVectorSymbol(tile3img, p_x, p_y, symbol, s); break; default: msSetError(MS_SYMERR, "BUG: Seamless mode is only for vector symbols", "getTile()"); return NULL; } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } } } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } status = MS_IMAGE_RENDERER(tile3img)->getRasterBufferHandle(tile3img,&tmpraster); if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } status = renderer->mergeRasterBuffer(tileimg, &tmpraster, 1.0,width,height,0,0,width,height ); msFreeImage(tile3img); } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tileimg); return NULL; } tile = addTileCache(img,tileimg,symbol,s,width,height); } return tile->image; }
int renderGlyphsCairo(imageObj *img,double x, double y, labelStyleObj *style, char *text) { cairo_renderer *r = CAIRO_RENDERER(img); cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img); faceCacheObj *face = getFontFace(cache,style->font); char *utfptr=text; int i,has_kerning,unicode; unsigned long previdx=0; int numglyphs = msGetNumGlyphs(text); cairo_glyph_t glyph; cairo_text_extents_t extents; double px=0,py=0; if(face == NULL) { return MS_FAILURE; } cairo_set_font_face(r->cr,face->face); cairo_set_font_size(r->cr,style->size*96/72.0); cairo_save(r->cr); cairo_translate(r->cr,MS_NINT(x),MS_NINT(y)); if(style->rotation != 0.0) cairo_rotate(r->cr, -style->rotation); has_kerning = FT_HAS_KERNING((face->ftface)); for(i=0;i<numglyphs;i++) { utfptr+=msUTF8ToUniChar(utfptr, &unicode); glyph.x=px; glyph.y=py; if(unicode=='\n') { py += ceil(style->size*CAIROLINESPACE); px = 0; previdx=0; continue; } glyph.index = FT_Get_Char_Index(face->ftface, unicode); if( has_kerning && previdx ) { FT_Vector delta; FT_Get_Kerning( face->ftface, previdx, glyph.index, FT_KERNING_DEFAULT, &delta ); px += delta.x / 64.; } cairo_glyph_extents(r->cr,&glyph,1,&extents); cairo_glyph_path(r->cr,&glyph,1); px += extents.x_advance; previdx=glyph.index; } if (style->outlinewidth > 0) { cairo_save(r->cr); msCairoSetSourceColor(r->cr, style->outlinecolor); cairo_set_line_width(r->cr, style->outlinewidth + 1); cairo_stroke_preserve(r->cr); cairo_restore(r->cr); } if(style->color) { msCairoSetSourceColor(r->cr, style->color); cairo_fill(r->cr); } cairo_new_path(r->cr); cairo_restore(r->cr); return MS_SUCCESS; }
int getTruetypeTextBBoxCairo(rendererVTableObj *renderer, char *font, double size, char *text, rectObj *rect, double **advances) { cairoCacheData *cache = MS_RENDERER_CACHE(renderer); faceCacheObj *face = getFontFace(cache,font); char *utfptr=text; int i,has_kerning,unicode; unsigned long previdx=0; int numglyphs = msGetNumGlyphs(text); cairo_glyph_t glyph; cairo_text_extents_t extents; double px=0,py=0; if(face == NULL) { return MS_FAILURE; } cairo_set_font_face(cache->dummycr,face->face); cairo_set_font_size(cache->dummycr,size*96/72.0); has_kerning = FT_HAS_KERNING((face->ftface)); if(advances != NULL) { *advances = (double*)malloc(numglyphs*sizeof(double)); } for(i=0;i<numglyphs;i++) { utfptr+=msUTF8ToUniChar(utfptr, &unicode); glyph.x=px; glyph.y=py; if(unicode=='\n') { py += ceil(size*CAIROLINESPACE); px = 0; previdx=0; continue; } glyph.index = FT_Get_Char_Index(face->ftface, unicode); if( has_kerning && previdx ) { FT_Vector delta; FT_Get_Kerning( face->ftface, previdx, glyph.index, FT_KERNING_DEFAULT, &delta ); px += delta.x / 64.; } cairo_glyph_extents(cache->dummycr,&glyph,1,&extents); if(i==0) { rect->minx = px+extents.x_bearing; rect->miny = py+extents.y_bearing; rect->maxx = px+extents.x_bearing+extents.width; rect->maxy = py+extents.y_bearing+extents.height; } else { rect->minx = MS_MIN(rect->minx,px+extents.x_bearing); rect->miny = MS_MIN(rect->miny,py+extents.y_bearing); rect->maxy = MS_MAX(rect->maxy,py+extents.y_bearing+extents.height); rect->maxx = MS_MAX(rect->maxx,px+extents.x_bearing+extents.width); } if(advances!=NULL) (*advances)[i]=extents.x_advance; px += extents.x_advance; previdx=glyph.index; } /* rect->minx = 0; rect->miny = 0; rect->maxx = 1; rect->maxy = 1; */ return MS_SUCCESS; }
/* helper functions */ int agg2GetTruetypeTextBBox(rendererVTableObj *renderer, char **fonts, int numfonts, double size, char *string, rectObj *rect, double **advances,int bAdjustBaseline) { aggRendererCache *cache = (aggRendererCache*)MS_RENDERER_CACHE(renderer); if(aggLoadFont(cache,fonts[0],size) == MS_FAILURE) return MS_FAILURE; int curfontidx = 0; int unicode, curGlyph = 1, numglyphs = 0; if (advances) { numglyphs = msGetNumGlyphs(string); } const mapserver::glyph_cache* glyph; string += msUTF8ToUniChar(string, &unicode); if(curfontidx != 0) { if(aggLoadFont(cache,fonts[0],size) == MS_FAILURE) return MS_FAILURE; curfontidx = 0; } glyph = cache->m_fman.glyph(unicode); if(!glyph || glyph->glyph_index == 0) { int i; for(i=1; i<numfonts; i++) { if(aggLoadFont(cache,fonts[i],size) == MS_FAILURE) return MS_FAILURE; curfontidx = i; glyph = cache->m_fman.glyph(unicode); if(glyph && glyph->glyph_index != 0) { break; } } } if (glyph) { rect->minx = glyph->bounds.x1; rect->maxx = glyph->bounds.x2; rect->miny = glyph->bounds.y1; rect->maxy = bAdjustBaseline?1:glyph->bounds.y2; } else return MS_FAILURE; if (advances) { *advances = (double*) malloc(numglyphs * sizeof (double)); MS_CHECK_ALLOC(*advances, numglyphs * sizeof (double), MS_FAILURE); (*advances)[0] = glyph->advance_x; } double fx = glyph->advance_x, fy = glyph->advance_y; while (*string) { if (advances) { if (*string == '\r' || *string == '\n') (*advances)[curGlyph++] = -fx; } if (*string == '\r') { fx = 0; string++; continue; } if (*string == '\n') { fx = 0; fy += ceil(size * AGG_LINESPACE); string++; continue; } string += msUTF8ToUniChar(string, &unicode); if(curfontidx != 0) { if(aggLoadFont(cache,fonts[0],size) == MS_FAILURE) return MS_FAILURE; curfontidx = 0; } glyph = cache->m_fman.glyph(unicode); if(!glyph || glyph->glyph_index == 0) { int i; for(i=1; i<numfonts; i++) { if(aggLoadFont(cache,fonts[i],size) == MS_FAILURE) return MS_FAILURE; curfontidx = i; glyph = cache->m_fman.glyph(unicode); if(glyph && glyph->glyph_index != 0) { break; } } } if (glyph) { rect->minx = MS_MIN(rect->minx, fx+glyph->bounds.x1); rect->miny = MS_MIN(rect->miny, fy+glyph->bounds.y1); rect->maxx = MS_MAX(rect->maxx, fx+glyph->bounds.x2); rect->maxy = MS_MAX(rect->maxy, fy+(bAdjustBaseline?1:glyph->bounds.y2)); fx += glyph->advance_x; fy += glyph->advance_y; if (advances) { (*advances)[curGlyph++] = glyph->advance_x; } } } return MS_SUCCESS; }
int agg2RenderGlyphsLine(imageObj *img, labelPathObj *labelpath, labelStyleObj *style, char *text) { AGG2Renderer *r = AGG_RENDERER(img); aggRendererCache *cache = (aggRendererCache*)MS_RENDERER_CACHE(MS_IMAGE_RENDERER(img)); if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); const mapserver::glyph_cache* glyph; int unicode; int curfontidx = 0; font_curve_type m_curves(cache->m_fman.path_adaptor()); mapserver::path_storage glyphs; for (int i = 0; i < labelpath->path.numpoints; i++) { assert(text); mapserver::trans_affine mtx; mtx *= mapserver::trans_affine_translation(-labelpath->path.point[i].x,-labelpath->path.point[i].y); mtx *= mapserver::trans_affine_rotation(-labelpath->angles[i]); mtx *= mapserver::trans_affine_translation(labelpath->path.point[i].x,labelpath->path.point[i].y); text += msUTF8ToUniChar(text, &unicode); if(curfontidx != 0) { if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = 0; } glyph = cache->m_fman.glyph(unicode); if(!glyph || glyph->glyph_index == 0) { int i; for(i=1; i<style->numfonts; i++) { if(aggLoadFont(cache,style->fonts[i],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = i; glyph = cache->m_fman.glyph(unicode); if(glyph && glyph->glyph_index != 0) { break; } } } if (glyph) { cache->m_fman.init_embedded_adaptors(glyph, labelpath->path.point[i].x,labelpath->path.point[i].y); mapserver::conv_transform<font_curve_type, mapserver::trans_affine> trans_c(m_curves, mtx); glyphs.concat_path(trans_c); } } if (style->outlinewidth) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); mapserver::conv_contour<mapserver::path_storage> cc(glyphs); cc.width(style->outlinewidth + 1); r->m_rasterizer_aa.add_path(cc); r->m_renderer_scanline.color(aggColor(style->outlinecolor)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } if (style->color) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); r->m_rasterizer_aa.add_path(glyphs); r->m_renderer_scanline.color(aggColor(style->color)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } return MS_SUCCESS; }
int agg2RenderGlyphs(imageObj *img, double x, double y, labelStyleObj *style, char *text) { AGG2Renderer *r = AGG_RENDERER(img); aggRendererCache *cache = (aggRendererCache*)MS_RENDERER_CACHE(MS_IMAGE_RENDERER(img)); if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); int curfontidx = 0; const mapserver::glyph_cache* glyph; int unicode; font_curve_type m_curves(cache->m_fman.path_adaptor()); mapserver::trans_affine mtx; mtx *= mapserver::trans_affine_translation(-x, -y); /*agg angles are antitrigonometric*/ mtx *= mapserver::trans_affine_rotation(-style->rotation); mtx *= mapserver::trans_affine_translation(x, y); double fx = x, fy = y; const char *utfptr = text; mapserver::path_storage glyphs; //first render all the glyphs to a path while (*utfptr) { if (*utfptr == '\r') { fx = x; utfptr++; continue; } if (*utfptr == '\n') { fx = x; fy += ceil(style->size * AGG_LINESPACE); utfptr++; continue; } utfptr += msUTF8ToUniChar(utfptr, &unicode); if(curfontidx != 0) { if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = 0; } glyph = cache->m_fman.glyph(unicode); if(!glyph || glyph->glyph_index == 0) { int i; for(i=1; i<style->numfonts; i++) { if(aggLoadFont(cache,style->fonts[i],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = i; glyph = cache->m_fman.glyph(unicode); if(glyph && glyph->glyph_index != 0) { break; } } } if (glyph) { //cache->m_fman.add_kerning(&fx, &fy); cache->m_fman.init_embedded_adaptors(glyph, fx, fy); mapserver::conv_transform<font_curve_type, mapserver::trans_affine> trans_c(m_curves, mtx); glyphs.concat_path(trans_c); fx += glyph->advance_x; fy += glyph->advance_y; } } if (style->outlinewidth) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); mapserver::conv_contour<mapserver::path_storage> cc(glyphs); cc.width(style->outlinewidth + 1); r->m_rasterizer_aa.add_path(cc); r->m_renderer_scanline.color(aggColor(style->outlinecolor)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } if (style->color) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); r->m_rasterizer_aa.add_path(glyphs); r->m_renderer_scanline.color(aggColor(style->color)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } return MS_SUCCESS; }
int getTruetypeTextBBoxCairo(rendererVTableObj *renderer, char **fonts, int numfonts, double size, char *text, rectObj *rect, double **advances, int bAdjustBaseline) { cairoCacheData *cache = MS_RENDERER_CACHE(renderer); faceCacheObj* face = getFontFace(cache,fonts[0]); int curfontidx = 0; char *utfptr=text; int i,unicode; unsigned long previdx=0; faceCacheObj* prevface = face; int numglyphs = msGetNumGlyphs(text); cairo_glyph_t glyph; cairo_text_extents_t extents; double px=0,py=0; if(face == NULL) { return MS_FAILURE; } cairo_set_font_face(cache->dummycr,face->face); cairo_set_font_size(cache->dummycr,size*96/72.0); if(advances != NULL) { *advances = (double*)malloc(numglyphs*sizeof(double)); } for(i=0; i<numglyphs; i++) { utfptr+=msUTF8ToUniChar(utfptr, &unicode); glyph.x=px; glyph.y=py; if(unicode=='\n') { py += ceil(size*CAIROLINESPACE); px = 0; previdx=0; continue; } if (curfontidx != 0) { face = getFontFace(cache, fonts[0]); cairo_set_font_face(cache->dummycr, face->face); curfontidx = 0; } if (face->ftface->charmap && face->ftface->charmap->encoding == FT_ENCODING_MS_SYMBOL) unicode |= 0xf000; glyph.index = FT_Get_Char_Index(face->ftface, unicode); if (glyph.index == 0) { int j; for (j = 1; j < numfonts; j++) { curfontidx = j; face = getFontFace(cache, fonts[j]); glyph.index = FT_Get_Char_Index(face->ftface, unicode); if (glyph.index != 0) { cairo_set_font_face(cache->dummycr, face->face); break; } } } if( FT_HAS_KERNING((prevface->ftface)) && previdx ) { FT_Vector delta; FT_Get_Kerning( prevface->ftface, previdx, glyph.index, FT_KERNING_DEFAULT, &delta ); px += delta.x / 64.; } cairo_glyph_extents(cache->dummycr,&glyph,1,&extents); if(i==0) { rect->minx = px+extents.x_bearing; rect->miny = py+extents.y_bearing; rect->maxx = px+extents.x_bearing+extents.width; rect->maxy = py+(bAdjustBaseline?1:(extents.y_bearing+extents.height)); } else { rect->minx = MS_MIN(rect->minx,px+extents.x_bearing); rect->miny = MS_MIN(rect->miny,py+extents.y_bearing); rect->maxy = MS_MAX(rect->maxy,py+(bAdjustBaseline?1:(extents.y_bearing+extents.height))); rect->maxx = MS_MAX(rect->maxx,px+extents.x_bearing+extents.width); } if(advances!=NULL) (*advances)[i]=extents.x_advance; px += extents.x_advance; previdx=glyph.index; prevface = face; } return MS_SUCCESS; }