Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP4:GA
ImageMagick
ImageMagick-CVE-2017-14989.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File ImageMagick-CVE-2017-14989.patch of Package ImageMagick
From 28bad01242898d7f863deedbfa8502c348293093 Mon Sep 17 00:00:00 2001 From: Cristy <urban-warrior@imagemagick.org> Date: Tue, 26 Sep 2017 07:16:49 -0400 Subject: [PATCH] https://github.com/ImageMagick/ImageMagick/issues/781 --- magick/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) Index: ImageMagick-6.8.8-1/magick/annotate.c =================================================================== @@ -45,6 +45,7 @@ #include "magick/studio.h" #include "magick/annotate.h" #include "magick/attribute.h" +#include "magick/cache-private.h" #include "magick/cache-view.h" #include "magick/channel.h" #include "magick/client.h" @@ -70,13 +71,14 @@ #include "magick/semaphore.h" #include "magick/statistic.h" #include "magick/string_.h" +#include "magick/token.h" #include "magick/token-private.h" #include "magick/transform.h" #include "magick/type.h" #include "magick/utility.h" #include "magick/xwindow-private.h" #if defined(MAGICKCORE_FREETYPE_DELEGATE) -#if defined(__MINGW32__) || defined(__MINGW64__) +#if defined(__MINGW32__) # undef interface #endif #include <ft2build.h> @@ -101,6 +103,20 @@ # include <freetype/ftbbox.h> #endif /* defined(FT_BBOX_H) */ #endif +#if defined(MAGICKCORE_RAQM_DELEGATE) +#include <raqm.h> +#endif +typedef struct _GraphemeInfo +{ + ssize_t + index, + x_offset, + x_advance, + y_offset; + + size_t + cluster; +} GraphemeInfo; /* Annotate semaphores. @@ -138,7 +154,8 @@ static MagickBooleanType */ MagickExport MagickBooleanType AnnotateComponentGenesis(void) { - AcquireSemaphoreInfo(&annotate_semaphore); + if (annotate_semaphore == (SemaphoreInfo *) NULL) + annotate_semaphore=AllocateSemaphoreInfo(); return(MagickTrue); } @@ -318,24 +361,22 @@ MagickExport MagickBooleanType AnnotateI { offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+ geometry.width/2.0+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+ - annotate_info->affine.ry*(metrics.ascent+metrics.descent); + annotate_info->affine.sx*metrics.width/2.0+annotate_info->affine.ry* + (metrics.ascent+metrics.descent); offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i* annotate_info->affine.sy*height+annotate_info->affine.sy* - metrics.ascent-annotate_info->affine.rx*(metrics.width- - metrics.bounds.x1)/2.0; + metrics.ascent-annotate_info->affine.rx*metrics.width/2.0; break; } case NorthEastGravity: { offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+ geometry.width+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+ - annotate_info->affine.ry*(metrics.ascent+metrics.descent)-1.0; + annotate_info->affine.sx*metrics.width+annotate_info->affine.ry* + (metrics.ascent+metrics.descent)-1.0; offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i* annotate_info->affine.sy*height+annotate_info->affine.sy* - metrics.ascent-annotate_info->affine.rx*(metrics.width- - metrics.bounds.x1); + metrics.ascent-annotate_info->affine.rx*metrics.width; break; } case WestGravity: @@ -354,28 +395,24 @@ MagickExport MagickBooleanType AnnotateI { offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+ geometry.width/2.0+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+ - annotate_info->affine.ry*(metrics.ascent+metrics.descent- - (number_lines-1)*height)/2.0; + annotate_info->affine.sx*metrics.width/2.0+annotate_info->affine.ry* + (metrics.ascent+metrics.descent-(number_lines-1)*height)/2.0; offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+ geometry.height/2.0+i*annotate_info->affine.sy*height- - annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0+ - annotate_info->affine.sy*(metrics.ascent+metrics.descent- - (number_lines-1.0)*height)/2.0; + annotate_info->affine.rx*metrics.width/2.0+annotate_info->affine.sy* + (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0; break; } case EastGravity: { offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+ geometry.width+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+ - annotate_info->affine.ry*(metrics.ascent+metrics.descent- - (number_lines-1.0)*height)/2.0-1.0; + annotate_info->affine.sx*metrics.width+annotate_info->affine.ry* + (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0-1.0; offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+ geometry.height/2.0+i*annotate_info->affine.sy*height- - annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)+ - annotate_info->affine.sy*(metrics.ascent+metrics.descent- - (number_lines-1.0)*height)/2.0; + annotate_info->affine.rx*metrics.width+annotate_info->affine.sy* + (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0; break; } case SouthWestGravity: @@ -392,24 +429,24 @@ MagickExport MagickBooleanType AnnotateI { offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+ geometry.width/2.0+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0- - annotate_info->affine.ry*(number_lines-1.0)*height/2.0; + annotate_info->affine.sx*metrics.width/2.0-annotate_info->affine.ry* + (number_lines-1.0)*height/2.0; offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+ geometry.height+i*annotate_info->affine.sy*height- - annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0- - annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent; + annotate_info->affine.rx*metrics.width/2.0-annotate_info->affine.sy* + (number_lines-1.0)*height+metrics.descent; break; } case SouthEastGravity: { offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+ geometry.width+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)- - annotate_info->affine.ry*(number_lines-1.0)*height-1.0; + annotate_info->affine.sx*metrics.width-annotate_info->affine.ry* + (number_lines-1.0)*height-1.0; offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+ geometry.height+i*annotate_info->affine.sy*height- - annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)- - annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent; + annotate_info->affine.rx*metrics.width-annotate_info->affine.sy* + (number_lines-1.0)*height+metrics.descent; break; } } @@ -424,17 +461,17 @@ MagickExport MagickBooleanType AnnotateI case CenterAlign: { offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0; + annotate_info->affine.sx*metrics.width/2.0; offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height- - annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0; + annotate_info->affine.rx*metrics.width/2.0; break; } case RightAlign: { offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height- - annotate_info->affine.sx*(metrics.width+metrics.bounds.x1); + annotate_info->affine.sx*metrics.width; offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height- - annotate_info->affine.rx*(metrics.width+metrics.bounds.x1); + annotate_info->affine.rx*metrics.width; break; } default: @@ -454,7 +491,7 @@ MagickExport MagickBooleanType AnnotateI undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent; undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent; (void) FormatLocaleString(primitive,MaxTextExtent, - "rectangle -0.5,-0.5 %g,%.20g",metrics.origin.x,(double) height); + "rectangle 0.0,0.0 %g,%g",metrics.origin.x,(double) height); (void) CloneString(&undercolor_info->primitive,primitive); (void) DrawImage(image,undercolor_info); (void) DestroyDrawInfo(undercolor_info); @@ -538,10 +575,8 @@ MagickExport MagickBooleanType AnnotateI MagickExport ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info, const MagickBooleanType split,TypeMetric *metrics,char **caption) { - char - *text; - MagickBooleanType + digit, status; register char @@ -558,13 +593,16 @@ MagickExport ssize_t FormatMagickCaption ssize_t n; - text=AcquireString(draw_info->text); + digit=MagickFalse; + width=0; q=draw_info->text; s=(char *) NULL; for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p)) { - if (IsUTFSpace(GetUTFCode(p)) != MagickFalse) + if ((digit == MagickFalse) && (IsUTFSpace(GetUTFCode(p)) != MagickFalse)) s=p; + digit=((GetUTFCode(p) >= 0x0030) && (GetUTFCode(p) <= 0x0039)) ? + MagickTrue : MagickFalse; if (GetUTFCode(p) == '\n') q=draw_info->text; for (i=0; i < (ssize_t) GetUTFOctets(p); i++) @@ -574,16 +612,15 @@ MagickExport ssize_t FormatMagickCaption if (status == MagickFalse) break; width=(size_t) floor(metrics->width+draw_info->stroke_width+0.5); - if ((width <= image->columns) || (strcmp(text,draw_info->text) == 0)) + if ((width <= image->columns) || (s == (char *) NULL)) continue; - (void) strcpy(text,draw_info->text); if ((s != (char *) NULL) && (GetUTFOctets(s) == 1)) { *s='\n'; p=s; } else - if ((s != (char *) NULL) || (split != MagickFalse)) + if (split != MagickFalse) { char *target; @@ -603,7 +640,61 @@ MagickExport ssize_t FormatMagickCaption q=draw_info->text; s=(char *) NULL; } - text=DestroyString(text); + if (width > image->columns) + { + char + *text; + + /* + No convenient break point, force one. + */ + text=AcquireString(draw_info->text); + q=draw_info->text; + s=(char *) NULL; + for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p)) + { + if (IsUTFSpace(GetUTFCode(p)) != MagickFalse) + s=p; + if (GetUTFCode(p) == '\n') + q=draw_info->text; + for (i=0; i < (ssize_t) GetUTFOctets(p); i++) + *q++=(*(p+i)); + *q='\0'; + status=GetTypeMetrics(image,draw_info,metrics); + if (status == MagickFalse) + break; + width=(size_t) floor(metrics->width+draw_info->stroke_width+0.5); + if ((width <= image->columns) || (strcmp(text,draw_info->text) == 0)) + continue; + (void) strcpy(text,draw_info->text); + if ((s != (char *) NULL) && (GetUTFOctets(s) == 1)) + { + *s='\n'; + p=s; + } + else + if ((s != (char *) NULL) || (split != MagickFalse)) + { + char + *target; + + /* + No convenient line breaks-- insert newline. + */ + target=AcquireString(*caption); + n=p-(*caption); + CopyMagickString(target,*caption,n+1); + ConcatenateMagickString(target,"\n",strlen(*caption)+1); + ConcatenateMagickString(target,p,strlen(*caption)+2); + (void) DestroyString(*caption); + *caption=target; + p=(*caption)+n; + } + q=draw_info->text; + s=(char *) NULL; + } + text=DestroyString(text); + } n=0; for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p)) if (GetUTFCode(p) == '\n') @@ -950,6 +1041,140 @@ static MagickBooleanType RenderType(Imag #if defined(MAGICKCORE_FREETYPE_DELEGATE) +static size_t ComplexTextLayout(const Image *image,const DrawInfo *draw_info, + const char *text,const size_t length,const FT_Face face,const FT_Int32 flags, + GraphemeInfo **grapheme) +{ +#if defined(MAGICKCORE_RAQM_DELEGATE) + const char + *features; + + raqm_t + *rq; + + raqm_glyph_t + *glyphs; + + register ssize_t + i; + + size_t + extent; + + extent=0; + rq=raqm_create(); + if (rq == (raqm_t *) NULL) + goto cleanup; + if (raqm_set_text_utf8(rq,text,length) == 0) + goto cleanup; + if (raqm_set_par_direction(rq,(raqm_direction_t) draw_info->direction) == 0) + goto cleanup; + if (raqm_set_freetype_face(rq,face) == 0) + goto cleanup; + features=GetImageProperty(image,"type:features"); + if (features != (const char *) NULL) + { + char + breaker, + quote, + *token; + + int + next, + status_token; + + TokenInfo + *token_info; + + next=0; + token_info=AcquireTokenInfo(); + token=AcquireString(""); + status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0', + &breaker,&next,"e); + while (status_token == 0) + { + raqm_add_font_feature(rq,token,strlen(token)); + status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0', + &breaker,&next,"e); + } + token_info=DestroyTokenInfo(token_info); + token=DestroyString(token); + } + if (raqm_layout(rq) == 0) + goto cleanup; + glyphs=raqm_get_glyphs(rq,&extent); + if (glyphs == (raqm_glyph_t *) NULL) + { + extent=0; + goto cleanup; + } + *grapheme=(GraphemeInfo *) AcquireQuantumMemory(extent,sizeof(**grapheme)); + if (*grapheme == (GraphemeInfo *) NULL) + { + extent=0; + goto cleanup; + } + for (i=0; i < (ssize_t) extent; i++) + { + (*grapheme)[i].index=glyphs[i].index; + (*grapheme)[i].x_offset=glyphs[i].x_offset; + (*grapheme)[i].x_advance=glyphs[i].x_advance; + (*grapheme)[i].y_offset=glyphs[i].y_offset; + (*grapheme)[i].cluster=glyphs[i].cluster; + } + +cleanup: + raqm_destroy(rq); + return(extent); +#else + const char + *p; + + FT_Error + ft_status; + + register ssize_t + i; + + ssize_t + last_glyph; + + /* + Simple layout for bi-directional text (right-to-left or left-to-right). + */ + *grapheme=(GraphemeInfo *) AcquireQuantumMemory(length+1,sizeof(**grapheme)); + if (*grapheme == (GraphemeInfo *) NULL) + return(0); + last_glyph=0; + p=text; + for (i=0; GetUTFCode(p) != 0; p+=GetUTFOctets(p), i++) + { + (*grapheme)[i].index=FT_Get_Char_Index(face,GetUTFCode(p)); + (*grapheme)[i].x_offset=0; + (*grapheme)[i].y_offset=0; + if (((*grapheme)[i].index != 0) && (last_glyph != 0)) + { + if (FT_HAS_KERNING(face)) + { + FT_Vector + kerning; + + ft_status=FT_Get_Kerning(face,(FT_UInt) last_glyph,(FT_UInt) + (*grapheme)[i].index,ft_kerning_default,&kerning); + if (ft_status == 0) + (*grapheme)[i-1].x_advance+=(FT_Pos) ((draw_info->direction == + RightToLeftDirection ? -1.0 : 1.0)*kerning.x); + } + } + ft_status=FT_Load_Glyph(face,(*grapheme)[i].index,flags); + (*grapheme)[i].x_advance=face->glyph->advance.x; + (*grapheme)[i].cluster=p-text; + last_glyph=(*grapheme)[i].index; + } + return((size_t) i); +#endif +} + static int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to, DrawInfo *draw_info) { @@ -960,10 +1185,9 @@ static int TraceCubicBezier(FT_Vector *p path[MaxTextExtent]; affine=draw_info->affine; - (void) FormatLocaleString(path,MaxTextExtent, - "C%g,%g %g,%g %g,%g",affine.tx+p->x/64.0,affine.ty- - p->y/64.0,affine.tx+q->x/64.0,affine.ty-q->y/64.0,affine.tx+to->x/64.0, - affine.ty-to->y/64.0); + (void) FormatLocaleString(path,MaxTextExtent,"C%g,%g %g,%g %g,%g",affine.tx+ + p->x/64.0,affine.ty-p->y/64.0,affine.tx+q->x/64.0,affine.ty-q->y/64.0, + affine.tx+to->x/64.0,affine.ty-to->y/64.0); (void) ConcatenateString(&draw_info->primitive,path); return(0); } @@ -977,8 +1201,8 @@ static int TraceLineTo(FT_Vector *to,Dra path[MaxTextExtent]; affine=draw_info->affine; - (void) FormatLocaleString(path,MaxTextExtent,"L%g,%g",affine.tx+ - to->x/64.0,affine.ty-to->y/64.0); + (void) FormatLocaleString(path,MaxTextExtent,"L%g,%g",affine.tx+to->x/64.0, + affine.ty-to->y/64.0); (void) ConcatenateString(&draw_info->primitive,path); return(0); } @@ -992,8 +1216,8 @@ static int TraceMoveTo(FT_Vector *to,Dra path[MaxTextExtent]; affine=draw_info->affine; - (void) FormatLocaleString(path,MaxTextExtent,"M%g,%g",affine.tx+ - to->x/64.0,affine.ty-to->y/64.0); + (void) FormatLocaleString(path,MaxTextExtent,"M%g,%g",affine.tx+to->x/64.0, + affine.ty-to->y/64.0); (void) ConcatenateString(&draw_info->primitive,path); return(0); } @@ -1008,9 +1232,9 @@ static int TraceQuadraticBezier(FT_Vecto path[MaxTextExtent]; affine=draw_info->affine; - (void) FormatLocaleString(path,MaxTextExtent,"Q%g,%g %g,%g", - affine.tx+control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0, - affine.ty-to->y/64.0); + (void) FormatLocaleString(path,MaxTextExtent,"Q%g,%g %g,%g",affine.tx+ + control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0,affine.ty- + to->y/64.0); (void) ConcatenateString(&draw_info->primitive,path); return(0); } @@ -1037,12 +1261,12 @@ static MagickBooleanType RenderFreetype( const char *value; - double - direction; - DrawInfo *annotate_info; + ExceptionInfo + *exception; + FT_BBox bounds; @@ -1077,6 +1301,9 @@ static MagickBooleanType RenderFreetype( glyph, last_glyph; + GraphemeInfo + *grapheme; + MagickBooleanType status; @@ -1087,6 +1314,12 @@ static MagickBooleanType RenderFreetype( register char *p; + register ssize_t + i; + + size_t + length; + ssize_t code, y; @@ -1121,14 +1354,16 @@ static MagickBooleanType RenderFreetype( args.pathname=ConstantString(draw_info->font+1); face=(FT_Face) NULL; ft_status=FT_Open_Face(library,&args,(long) draw_info->face,&face); - args.pathname=DestroyString(args.pathname); + exception=(&image->exception); if (ft_status != 0) { (void) FT_Done_FreeType(library); - (void) ThrowMagickException(&image->exception,GetMagickModule(),TypeError, - "UnableToReadFont","`%s'",draw_info->font); + (void) ThrowMagickException(exception,GetMagickModule(),TypeError, + "UnableToReadFont","`%s'",args.pathname); + args.pathname=DestroyString(args.pathname); return(MagickFalse); } + args.pathname=DestroyString(args.pathname); if ((draw_info->metrics != (char *) NULL) && (IsPathAccessible(draw_info->metrics) != MagickFalse)) (void) FT_Attach_File(face,draw_info->metrics); @@ -1170,7 +1405,11 @@ static MagickBooleanType RenderFreetype( encoding_type=ft_encoding_wansung; ft_status=FT_Select_Charmap(face,encoding_type); if (ft_status != 0) - ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding); + { + (void) FT_Done_Face(face); + (void) FT_Done_FreeType(library); + ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding); + } } /* Set text size. @@ -1194,6 +1433,12 @@ static MagickBooleanType RenderFreetype( ft_status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize), (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x, (FT_UInt) resolution.y); + if (ft_status != 0) + { + (void) FT_Done_Face(face); + (void) FT_Done_FreeType(library); + ThrowBinaryException(TypeError,"UnableToReadFont",draw_info->font); + } metrics->pixels_per_em.x=face->size->metrics.x_ppem; metrics->pixels_per_em.y=face->size->metrics.y_ppem; metrics->ascent=(double) face->size->metrics.ascender/64.0; @@ -1227,7 +1472,9 @@ static MagickBooleanType RenderFreetype( encoding != (char *) NULL ? encoding : "none", draw_info->encoding != (char *) NULL ? draw_info->encoding : "none", draw_info->pointsize); - flags=FT_LOAD_NO_BITMAP; + flags=FT_LOAD_DEFAULT; + if (draw_info->render == MagickFalse) + flags=FT_LOAD_NO_BITMAP; if (draw_info->text_antialias == MagickFalse) flags|=FT_LOAD_TARGET_MONO; else @@ -1259,7 +1506,10 @@ static MagickBooleanType RenderFreetype( affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5); } annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info); + if (annotate_info->dash_pattern != (double *) NULL) + annotate_info->dash_pattern[0]=0.0; (void) CloneString(&annotate_info->primitive,"path '"); + status=MagickTrue; if (draw_info->render != MagickFalse) { if (image->storage_class != DirectClass) @@ -1267,9 +1517,6 @@ static MagickBooleanType RenderFreetype( if (image->matte == MagickFalse) (void) SetImageAlphaChannel(image,OpaqueAlphaChannel); } - direction=1.0; - if (draw_info->direction == RightToLeftDirection) - direction=(-1.0); point.x=0.0; point.y=0.0; for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p)) @@ -1284,32 +1531,22 @@ static MagickBooleanType RenderFreetype( if (utf8 != (unsigned char *) NULL) p=(char *) utf8; } - status=MagickTrue; - for (code=0; GetUTFCode(p) != 0; p+=GetUTFOctets(p)) + grapheme=(GraphemeInfo *) NULL; + length=ComplexTextLayout(image,draw_info,p,strlen(p),face,flags,&grapheme); + code=0; + for (i=0; i < (ssize_t) length; i++) { /* Render UTF-8 sequence. */ - glyph.id=FT_Get_Char_Index(face,GetUTFCode(p)); + glyph.id=grapheme[i].index; if (glyph.id == 0) glyph.id=FT_Get_Char_Index(face,'?'); if ((glyph.id != 0) && (last_glyph.id != 0)) - { - if (fabs(draw_info->kerning) >= MagickEpsilon) - origin.x+=(FT_Pos) (64.0*direction*draw_info->kerning); - else - if (FT_HAS_KERNING(face)) - { - FT_Vector - kerning; - - ft_status=FT_Get_Kerning(face,last_glyph.id,glyph.id, - ft_kerning_default,&kerning); - if (ft_status == 0) - origin.x+=(FT_Pos) (direction*kerning.x); - } - } + origin.x+=(FT_Pos) (64.0*draw_info->kerning); glyph.origin=origin; + glyph.origin.x+=grapheme[i].x_offset; + glyph.origin.y+=grapheme[i].y_offset; ft_status=FT_Load_Glyph(face,glyph.id,flags); if (ft_status != 0) continue; @@ -1321,27 +1558,29 @@ static MagickBooleanType RenderFreetype( if (ft_status != 0) continue; if ((p == draw_info->text) || (bounds.xMin < metrics->bounds.x1)) - metrics->bounds.x1=(double) bounds.xMin; + if (bounds.xMin != 0) + metrics->bounds.x1=(double) bounds.xMin; if ((p == draw_info->text) || (bounds.yMin < metrics->bounds.y1)) - metrics->bounds.y1=(double) bounds.yMin; + if (bounds.yMin != 0) + metrics->bounds.y1=(double) bounds.yMin; if ((p == draw_info->text) || (bounds.xMax > metrics->bounds.x2)) - metrics->bounds.x2=(double) bounds.xMax; + if (bounds.xMax != 0) + metrics->bounds.x2=(double) bounds.xMax; if ((p == draw_info->text) || (bounds.yMax > metrics->bounds.y2)) - metrics->bounds.y2=(double) bounds.yMax; - if ((draw_info->stroke.opacity != TransparentOpacity) || - (draw_info->stroke_pattern != (Image *) NULL)) + if (bounds.yMax != 0) + metrics->bounds.y2=(double) bounds.yMax; + if (((draw_info->stroke.opacity != TransparentOpacity) || + (draw_info->stroke_pattern != (Image *) NULL)) && + ((status != MagickFalse) && (draw_info->render != MagickFalse))) { - if ((status != MagickFalse) && (draw_info->render != MagickFalse)) - { - /* - Trace the glyph. - */ - annotate_info->affine.tx=glyph.origin.x/64.0; - annotate_info->affine.ty=glyph.origin.y/64.0; - (void) FT_Outline_Decompose(&((FT_OutlineGlyph) glyph.image)-> - outline,&OutlineMethods,annotate_info); - } - } + /* + Trace the glyph. + */ + annotate_info->affine.tx=glyph.origin.x/64.0; + annotate_info->affine.ty=(-glyph.origin.y/64.0); + (void) FT_Outline_Decompose(&((FT_OutlineGlyph) glyph.image)->outline, + &OutlineMethods,annotate_info); + } FT_Vector_Transform(&glyph.origin,&affine); (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin); ft_status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal, @@ -1358,16 +1597,20 @@ static MagickBooleanType RenderFreetype( CacheView *image_view; - ExceptionInfo - *exception; - register unsigned char *p; + MagickBooleanType + transparent_fill; + /* Rasterize the glyph. */ - exception=(&image->exception); + transparent_fill=((draw_info->fill.opacity == TransparentOpacity) && + (draw_info->fill_pattern == (Image *) NULL) && + (draw_info->stroke.opacity == TransparentOpacity) && + (draw_info->stroke_pattern == (Image *) NULL)) ? MagickTrue : + MagickFalse; p=bitmap->bitmap.buffer; image_view=AcquireAuthenticCacheView(image,exception); for (y=0; y < (ssize_t) bitmap->bitmap.rows; y++) @@ -1415,7 +1658,8 @@ static MagickBooleanType RenderFreetype( x_offset++; if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns)) { - q++; + if (q != (PixelPacket *) NULL) + q++; continue; } if (bitmap->bitmap.pixel_mode != ft_pixel_mode_mono) @@ -1429,14 +1673,25 @@ static MagickBooleanType RenderFreetype( q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1, exception); if (q == (PixelPacket *) NULL) + continue; + if (transparent_fill == MagickFalse) { - q++; - continue; + (void) GetFillColor(draw_info,x_offset,y_offset,&fill_color); + fill_opacity=QuantumRange-fill_opacity*(QuantumRange- + fill_color.opacity); + MagickCompositeOver(&fill_color,fill_opacity,q,q->opacity,q); + } + else + { + double + Sa, + Da; + + Da=1.0-(QuantumScale*(QuantumRange-q->opacity)); + Sa=fill_opacity; + fill_opacity=(1.0-RoundToUnity(Sa+Da-Sa*Da))*QuantumRange; + SetPixelAlpha(q,fill_opacity); } - (void) GetFillColor(draw_info,x_offset,y_offset,&fill_color); - fill_opacity=QuantumRange-fill_opacity*(QuantumRange- - fill_color.opacity); - MagickCompositeOver(&fill_color,fill_opacity,q,q->opacity,q); if (active == MagickFalse) { sync=SyncCacheViewAuthenticPixels(image_view,exception); @@ -1450,75 +1705,52 @@ static MagickBooleanType RenderFreetype( status=MagickFalse; } image_view=DestroyCacheView(image_view); + if (((draw_info->stroke.opacity != TransparentOpacity) || + (draw_info->stroke_pattern != (Image *) NULL)) && + (status != MagickFalse)) + { + /* + Draw text stroke. + */ + annotate_info->linejoin=RoundJoin; + annotate_info->affine.tx=offset->x; + annotate_info->affine.ty=offset->y; + (void) ConcatenateString(&annotate_info->primitive,"'"); + (void) DrawImage(image,annotate_info); + (void) CloneString(&annotate_info->primitive,"path '"); + } } - if ((bitmap->left+bitmap->bitmap.width) > metrics->width) - metrics->width=bitmap->left+bitmap->bitmap.width; if ((fabs(draw_info->interword_spacing) >= MagickEpsilon) && - (IsUTFSpace(GetUTFCode(p)) != MagickFalse) && + (IsUTFSpace(GetUTFCode(p+grapheme[i].cluster)) != MagickFalse) && (IsUTFSpace(code) == MagickFalse)) - origin.x+=(FT_Pos) (64.0*direction*draw_info->interword_spacing); + origin.x+=(FT_Pos) (64.0*draw_info->interword_spacing); else - origin.x+=(FT_Pos) (direction*face->glyph->advance.x); + origin.x+=(FT_Pos) grapheme[i].x_advance; metrics->origin.x=(double) origin.x; metrics->origin.y=(double) origin.y; + if (metrics->origin.x > metrics->width) + metrics->width=metrics->origin.x; if (last_glyph.id != 0) FT_Done_Glyph(last_glyph.image); last_glyph=glyph; - code=GetUTFCode(p); + code=GetUTFCode(p+grapheme[i].cluster); } + if (grapheme != (GraphemeInfo *) NULL) + grapheme=(GraphemeInfo *) RelinquishMagickMemory(grapheme); if (utf8 != (unsigned char *) NULL) utf8=(unsigned char *) RelinquishMagickMemory(utf8); if (last_glyph.id != 0) FT_Done_Glyph(last_glyph.image); - if ((draw_info->stroke.opacity != TransparentOpacity) || - (draw_info->stroke_pattern != (Image *) NULL)) - { - if ((status != MagickFalse) && (draw_info->render != MagickFalse)) - { - /* - Draw text stroke. - */ - annotate_info->linejoin=RoundJoin; - annotate_info->affine.tx=offset->x; - annotate_info->affine.ty=offset->y; - (void) ConcatenateString(&annotate_info->primitive,"'"); - (void) DrawImage(image,annotate_info); - } - } /* Determine font metrics. */ - glyph.id=FT_Get_Char_Index(face,'_'); - glyph.origin=origin; - ft_status=FT_Load_Glyph(face,glyph.id,flags); - if (ft_status == 0) - { - ft_status=FT_Get_Glyph(face->glyph,&glyph.image); - if (ft_status == 0) - { - ft_status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)-> - outline,&bounds); - if (ft_status == 0) - { - FT_Vector_Transform(&glyph.origin,&affine); - (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin); - ft_status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal, - (FT_Vector *) NULL,MagickTrue); - bitmap=(FT_BitmapGlyph) glyph.image; - if (bitmap->left > metrics->width) - metrics->width=bitmap->left; - } - } - FT_Done_Glyph(glyph.image); - } - metrics->width-=metrics->bounds.x1/64.0; - metrics->width+=annotate_info->stroke_width; metrics->bounds.x1/=64.0; metrics->bounds.y1/=64.0; metrics->bounds.x2/=64.0; metrics->bounds.y2/=64.0; metrics->origin.x/=64.0; metrics->origin.y/=64.0; + metrics->width/=64.0; /* Relinquish resources. */ @@ -1570,41 +1802,48 @@ static MagickBooleanType RenderFreetype( % */ -static inline size_t MagickMin(const size_t x,const size_t y) -{ - if (x < y) - return(x); - return(y); -} - -static char *EscapeParenthesis(const char *text) +static char *EscapeParenthesis(const char *source) { char - *buffer; + *destination; register char - *p; + *q; - register ssize_t - i; + register const char + *p; size_t - escapes; + length; - escapes=0; - buffer=AcquireString(text); - p=buffer; - for (i=0; i < (ssize_t) MagickMin(strlen(text),MaxTextExtent-escapes-1); i++) + assert(source != (const char *) NULL); + length=0; + for (p=source; *p != '\0'; p++) { - if ((text[i] == '(') || (text[i] == ')')) + if ((*p == '\\') || (*p == '(') || (*p == ')')) { - *p++='\\'; - escapes++; + if (~length < 1) + ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString"); + length++; } - *p++=text[i]; + length++; + } + destination=(char *) NULL; + if (~length >= (MaxTextExtent-1)) + destination=(char *) AcquireQuantumMemory(length+MaxTextExtent, + sizeof(*destination)); + if (destination == (char *) NULL) + ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString"); + *destination='\0'; + q=destination; + for (p=source; *p != '\0'; p++) + { + if ((*p == '\\') || (*p == '(') || (*p == ')')) + *q++='\\'; + *q++=(*p); } - *p='\0'; - return(buffer); + *q='\0'; + return(destination); } static MagickBooleanType RenderPostscript(Image *image,
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor