From f3a9664f769b36981526403d9868d5d4aba59b2b Mon Sep 17 00:00:00 2001 From: Dmitry Karasik Date: Sat, 23 Nov 2024 13:58:59 +0100 Subject: [PATCH] fix underlines on GDI+; text_out with alpha/color uses shaping --- api/utf8.c | 45 +++++++ class/Drawable/shape.c | 42 +----- class/Drawable/text.c | 3 +- include/apricot.h | 10 +- include/unix/guts.h | 4 +- include/win32/win32guts.h | 2 +- unix/fontquery.c | 8 +- unix/text.c | 8 +- unix/xft.c | 12 +- win32/gdiplus.c | 28 ---- win32/text.c | 275 +++++++++++++++++++++++++------------- 11 files changed, 251 insertions(+), 186 deletions(-) diff --git a/api/utf8.c b/api/utf8.c index 6ddf3d97b..d40464d44 100644 --- a/api/utf8.c +++ b/api/utf8.c @@ -55,6 +55,51 @@ prima_utf8_uvchr_end(const char * text, const char * end, unsigned int *charlen) return uv; } +uint32_t* +prima_string2uint32( register const char * src, unsigned int dlen, Bool is_utf8, unsigned int * size) +{ + uint32_t *ret; + + *size = is_utf8 ? prima_utf8_length(src, dlen) : dlen; + if (!(ret = ( uint32_t*) malloc(sizeof(uint32_t) * (*size)))) { + warn("Not enough memory: %ld bytes", (unsigned long int)(sizeof(uint32_t) * (*size))); + return NULL; + } + + if (is_utf8) { + uint32_t *dst = ret; + while ( dlen > 0 && dst - ret < *size) { + UV uv; + unsigned int charlen; + uv = prima_utf8_uvchr(src, dlen, &charlen); + if ( uv > 0x10FFFF ) uv = 0x10FFFF; + *(dst++) = uv; + if ( charlen == 0 ) break; + src += charlen; + dlen -= charlen; + } + *size = dst - ret; + } else { + register int i = *size; + register uint32_t *dst = ret; + while (i-- > 0) *(dst++) = *((unsigned char*) src++); + } + + return ret; +} + +uint32_t* +prima_sv2uint32( SV * text, unsigned int * size, unsigned int * flags) +{ + STRLEN dlen; + const char * src; + + src = (const char*) SvPV(text, dlen); + if (prima_is_utf8_sv(text)) + *flags |= toUTF8; + return prima_string2uint32( src, dlen, *flags & toUTF8, size); +} + #ifdef __cplusplus } #endif diff --git a/class/Drawable/shape.c b/class/Drawable/shape.c index b11bfbed6..127ea570b 100644 --- a/class/Drawable/shape.c +++ b/class/Drawable/shape.c @@ -23,46 +23,6 @@ warn_malloc(ssize_t size) return ret; } -static uint32_t* -sv2uint32( SV * text, unsigned int * size, unsigned int * flags) -{ - STRLEN dlen; - register char * src; - uint32_t *ret; - - src = SvPV(text, dlen); - if (prima_is_utf8_sv(text)) { - *flags |= toUTF8; - *size = prima_utf8_length(src, dlen); - } else { - *size = dlen; - } - - if (!(ret = ( uint32_t*) warn_malloc(sizeof(uint32_t) * (*size)))) - return NULL; - - if (*flags & toUTF8 ) { - uint32_t *dst = ret; - while ( dlen > 0 && dst - ret < *size) { - UV uv; - unsigned int charlen; - uv = prima_utf8_uvchr(src, dlen, &charlen); - if ( uv > 0x10FFFF ) uv = 0x10FFFF; - *(dst++) = uv; - if ( charlen == 0 ) break; - src += charlen; - dlen -= charlen; - } - *size = dst - ret; - } else { - register int i = *size; - register uint32_t *dst = ret; - while (i-- > 0) *(dst++) = *((unsigned char*) src++); - } - - return ret; -} - /* Iterator for individual shaper runs. Each run has same direction and its indexes are increasing/decreasing monotonically. The latter is @@ -631,7 +591,7 @@ Drawable_text_shape( Handle self, SV * text_sv, HV * profile) } /* allocate buffers */ - if (!(t.text = sv2uint32(text_sv, &t.len, &t.flags))) + if (!(t.text = prima_sv2uint32(text_sv, &t.len, &t.flags))) goto EXIT; if ( replace_tabs >= 0 ) { int i; diff --git a/class/Drawable/text.c b/class/Drawable/text.c index 0c7f05be8..b106f6688 100644 --- a/class/Drawable/text.c +++ b/class/Drawable/text.c @@ -265,7 +265,7 @@ Drawable_get_text_width( Handle self, SV * text, int flags, int from, int len) if (t.advances) return Drawable_get_glyphs_width(self, &t, flags & toAddOverhangs); dmENTER(0); - res = apc_gp_get_glyphs_width( self, &t); + res = apc_gp_get_glyphs_width( self, &t, flags); dmLEAVE; } else { SV * ret; @@ -335,7 +335,6 @@ Drawable_get_glyphs_box( Handle self, PGlyphsOutRec t, Point * pt) SaveFont savefont; FontABC *abc; - t-> flags = 0; text_out_baseline = ( my-> textOutBaseline == Drawable_textOutBaseline) ? apc_gp_get_text_out_baseline(self) : my-> get_textOutBaseline(self); diff --git a/include/apricot.h b/include/apricot.h index febf6e193..2d0e34d04 100644 --- a/include/apricot.h +++ b/include/apricot.h @@ -1833,6 +1833,12 @@ list_index_of( PList self, Handle item); extern int prima_utf8_length( const char * utf8, int length); +extern uint32_t* +prima_sv2uint32( SV * text, unsigned int * size, unsigned int * flags); + +extern uint32_t* +prima_string2uint32( const char * text, unsigned int dlen, Bool is_utf8, unsigned int * size); + extern Bool prima_is_utf8_sv( SV * sv); @@ -4068,7 +4074,7 @@ typedef Bool TextShapeFunc( Handle self, PTextShapeRec rec); typedef TextShapeFunc *PTextShapeFunc; typedef struct { - unsigned int len, flags, text_len; + unsigned int len, text_len; uint16_t *glyphs, *indexes, *advances; int16_t *positions; uint16_t *fonts; @@ -4130,7 +4136,7 @@ extern Point* apc_gp_get_glyphs_box( Handle self, PGlyphsOutRec text); extern int -apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec text); +apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec text, int flags); extern ApiHandle apc_gp_get_handle( Handle self); diff --git a/include/unix/guts.h b/include/unix/guts.h index 2f2076195..3929b30ae 100644 --- a/include/unix/guts.h +++ b/include/unix/guts.h @@ -1595,7 +1595,7 @@ prima_xft_get_text_width( PCachedFont self, const char * text, int len, extern int prima_xft_get_glyphs_width( Handle self, PCachedFont selfxx, PGlyphsOutRec glyphs, - Point * overhangs); + int flags, Point * overhangs); extern Point * prima_xft_get_text_box( Handle self, const char * text, int len, int flags); @@ -1896,7 +1896,7 @@ extern int prima_fq_get_text_width( Handle self, const char * text, int len, int flags, Point * overhangs); extern int -prima_fq_get_glyphs_width( Handle self, PGlyphsOutRec t, Point * overhangs); +prima_fq_get_glyphs_width( Handle self, PGlyphsOutRec t, Point * overhangs, int flags); extern Point * prima_fq_get_text_box( Handle self, const char * text, int len, int flags); diff --git a/include/win32/win32guts.h b/include/win32/win32guts.h index 0be241ace..a3dc4f7d1 100644 --- a/include/win32/win32guts.h +++ b/include/win32/win32guts.h @@ -784,9 +784,9 @@ extern Bool text_aa_init( Handle self, HFONT font, Bool use_palette); extern void text_aa_begin_render( Handle self, Bool use_palette); extern Bool text_aa_render( Handle self, uint16_t glyph); extern Bool text_aa_end_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance, int dx, int dy, Bool use_palette); -extern Bool text_aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide); extern void text_aa_free_arena(Handle self, Bool for_reuse); extern Bool text_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, Bool fixed_pitch); +extern int text_gp_get_glyphs_width( Handle self, PGlyphsOutRec t, int flags); extern void wchar2char( char * dest, WCHAR * src, int lim); extern Bool yield( Bool wait_for_event ); diff --git a/unix/fontquery.c b/unix/fontquery.c index 79a7b9d33..89477cf63 100644 --- a/unix/fontquery.c +++ b/unix/fontquery.c @@ -469,7 +469,7 @@ prima_fq_get_text_width( Handle self, const char * text, int len, int flags, Poi } int -prima_fq_get_glyphs_width( Handle self, PGlyphsOutRec t, Point * overhangs) +prima_fq_get_glyphs_width( Handle self, PGlyphsOutRec t, int flags, Point * overhangs) { DEFXX; int i, ret = 0; @@ -486,8 +486,8 @@ prima_fq_get_glyphs_width( Handle self, PGlyphsOutRec t, Point * overhangs) continue; g = fc.current->glyph; ret += FT266_to_short(g->advance.x); - if ( (t->flags & toAddOverhangs ) || overhangs) { - UPDATE_OVERHANGS(t->len,t->flags) + if ( (flags & toAddOverhangs ) || overhangs) { + UPDATE_OVERHANGS(t->len,flags) } } return ret; @@ -505,7 +505,7 @@ Point * prima_fq_get_glyphs_box( Handle self, PGlyphsOutRec t) { Point ovx; - int w = prima_fq_get_glyphs_width(self, t, &ovx); + int w = prima_fq_get_glyphs_width(self, t, toAddOverhangs, &ovx); return prima_get_text_box(self, ovx, w); } diff --git a/unix/text.c b/unix/text.c index ea51f44db..bba692a01 100644 --- a/unix/text.c +++ b/unix/text.c @@ -826,7 +826,7 @@ apc_gp_get_text_width( Handle self, const char * text, int len, int flags) } int -apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec t) +apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec t, int flags) { int ret; if ( t->len > 65535 ) t->len = 65535; @@ -834,18 +834,18 @@ apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec t) #ifdef USE_FONTQUERY if ( is_opt(optInFontQuery) ) { if ( X(self)->font) - return prima_fq_get_glyphs_width( self, t, NULL); + return prima_fq_get_glyphs_width( self, t, flags, NULL); return 0; } #endif #ifdef USE_XFT if ( X(self)-> font-> xft) - return prima_xft_get_glyphs_width( self, X(self)-> font, t, NULL); + return prima_xft_get_glyphs_width( self, X(self)-> font, t, flags, NULL); #endif SWAP_BYTES(t->glyphs,t->len); - ret = gp_get_text_width( self, (char*) t->glyphs, t->len, toUTF8 ); + ret = gp_get_text_width( self, (char*) t->glyphs, t->len, flags | toUTF8 ); SWAP_BYTES(t->glyphs,t->len); return ret; } diff --git a/unix/xft.c b/unix/xft.c index dc34bd79e..07af18d90 100644 --- a/unix/xft.c +++ b/unix/xft.c @@ -606,7 +606,7 @@ prima_xft_get_text_width( } int -prima_xft_get_glyphs_width( Handle self, PCachedFont selfxx, PGlyphsOutRec t, Point * overhangs) +prima_xft_get_glyphs_width( Handle self, PCachedFont selfxx, PGlyphsOutRec t, int flags, Point * overhangs) { int i, ret = 0; FontContext fc; @@ -622,8 +622,8 @@ prima_xft_get_glyphs_width( Handle self, PCachedFont selfxx, PGlyphsOutRec t, Po font_context_next(&fc); XftGlyphExtents( DISP, fc.xft_font, &ft_index, 1, &glyph); ret += glyph. xOff * fc.width_factor + .5; - if ( (t->flags & toAddOverhangs ) || overhangs) { - UPDATE_OVERHANGS(t->len,t->flags,fc.width_factor) + if ( (flags & toAddOverhangs ) || overhangs) { + UPDATE_OVERHANGS(t->len,flags,fc.width_factor) } } return ret; @@ -643,7 +643,7 @@ prima_xft_get_glyphs_box( Handle self, PGlyphsOutRec t) { DEFXX; Point ovx; - int p = prima_xft_get_glyphs_width(self, XX-> font, t, &ovx); + int p = prima_xft_get_glyphs_width(self, XX-> font, t, toAddOverhangs, &ovx); return prima_get_text_box(self, ovx, p); } @@ -1234,7 +1234,7 @@ prima_xft_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y) /* emulate rops by blitting the text */ int dx; TextBlit tb; - dx = prima_xft_get_glyphs_width( self, XX-> font, t, NULL); + dx = prima_xft_get_glyphs_width( self, XX-> font, t, toAddOverhangs, NULL); if (!open_text_blit(self, x - baseline.x, y - baseline.y, dx, rop, &tb)) goto COPY_PUT; xft_draw_glyphs(self, XX, &xftcolor, @@ -1251,7 +1251,7 @@ prima_xft_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y) int l; Point ovx; t-> flags |= toAddOverhangs; - l = prima_xft_get_glyphs_width( self, XX-> font, t, &ovx); + l = prima_xft_get_glyphs_width( self, XX-> font, t, toAddOverhangs, &ovx); overstrike(self, x, y, &ovx, l - ovx.x - ovx.y - 1); } XFLUSH; diff --git a/win32/gdiplus.c b/win32/gdiplus.c index 2eb9a8dba..6063dfbb9 100644 --- a/win32/gdiplus.c +++ b/win32/gdiplus.c @@ -503,34 +503,6 @@ aa_fill_palette(Handle self) return true; } -Bool -text_aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide) -{ - int i; - NPoint delta = { 0, 0 }; - - if ( !(aa_fill_palette(self) && aa_make_arena(self))) - return false; - - for ( i = 0; i < len; i++) { - ABCFLOAT abc; - memset(sys alpha_arena_ptr, 0, sys alpha_arena_size.x * sys alpha_arena_size.y * 4); - if ( wide ) { - if (!GetCharABCWidthsFloatW( sys ps, ((WCHAR*)text)[i], ((WCHAR*)text)[i], &abc)) apiErrRet; - } else { - if (!GetCharABCWidthsFloatA( sys ps, ((char *)text)[i], ((char *)text)[i], &abc)) apiErrRet; - } - if ( wide ) { - if (!TextOutW( sys alpha_arena_dc, sys alpha_arena_size.x/2, sys alpha_arena_size.y/2, ((WCHAR*)text) + i, 1)) apiErrRet; - } else { - if (!TextOutA( sys alpha_arena_dc, sys alpha_arena_size.x/2, sys alpha_arena_size.y/2, ((char *)text) + i, 1)) apiErrRet; - } - if ( !text_aa_end_render(self, x, y, &delta, &abc, -1, 0, 0, true)) - return false; - } - return true; -} - Bool text_aa_init( Handle self, HFONT font, Bool use_palette) { diff --git a/win32/text.c b/win32/text.c index f56d5616e..7c519483e 100644 --- a/win32/text.c +++ b/win32/text.c @@ -142,66 +142,98 @@ font_context_next( FontContext * fc ) return len; } +static void +draw_underline( Handle self, int x1, int y1, int x2, int y2, int width, int Y, Bool use_alpha, GpPen *gppen) +{ + int n_points = 2; + NPoint pt[4] = { + {0,-Y}, + {width,-Y}, + {0,-Y}, + {width,-Y}, + }; + + if ( is_apt(aptGDIPlus) ) { + int lw = var font. underlineThickness; + pt[0].y -= lw; + pt[1].y -= lw; + pt[2].y += lw; + pt[3].y += lw; + n_points = 4; + } + + if ( var font. direction != 0) { + int i; + NPoint cs = CDrawable(self)->trig_cache(self); + for ( i = 0; i < n_points; i++) { + double x = pt[i].x * cs.y - pt[i].y * cs.x; + double y = pt[i].x * cs.x + pt[i].y * cs.y; + pt[i].x = x; + pt[i].y = y; + } + } + + if ( use_alpha || is_apt(aptGDIPlus) ) { + prima_matrix_apply2( var current_state.matrix, pt, pt, n_points); + if ( is_apt(aptGDIPlus)) { + GpPointF p[4] = { + {x2 + pt[0].x, y2 - pt[0].y}, + {x2 + pt[2].x, y2 - pt[2].y}, + {x2 + pt[1].x, y2 - pt[1].y}, + {x2 + pt[3].x, y2 - pt[3].y}, + }; + STYLUS_USE_GP_BRUSH; + if ( !CURRENT_GP_BRUSH ) goto NO_AA; + GdipFillPolygon( sys graphics, CURRENT_GP_BRUSH, p, 4, FillModeWinding); + } else { + NO_AA: + GdipDrawLine(sys graphics, gppen, x2 + pt[0].x, y2 - pt[0].y, x2 + pt[1].x, y2 - pt[1].y); + } + } else { + Point ix[2]; + prima_array_convert( 4, pt, 'd', ix, 'i'); + MoveToEx( sys ps, x1 + ix[0].x, y1 - ix[0].y, NULL); + LineTo( sys ps, x1 + ix[1].x, y1 - ix[1].y); + } +} + /* emulate underscore and strikeout because ExtTextOutW with ETO_PDY underlines each glyph separately . Also, Gdip ignores viewport, specify params in parallel */ static void -underscore_font( Handle self, int x1, int y1, int x2, int y2, int width, Bool use_alpha) +text_underscore_font( Handle self, int x1, int y1, int x2, int y2, int width, Bool use_alpha) { - HDC dc = sys ps; GpPen * gppen = NULL; - NPoint cs = CDrawable(self)->trig_cache(self); if ( var font. style & (fsUnderlined|fsStruckOut)) { int line_width = 1; COLORREF fg = sys rq_pen.logpen.lopnColor; line_width = var font. underlineThickness; if ( use_alpha ) { - gppen = stylus_gp_get_pen(line_width, - ( sys alpha << 24) | - (fg >> 16) | - (fg & 0xff00) | - ((fg & 0xff) << 16) - ); + if ( !is_apt(aptGDIPlus)) + gppen = stylus_gp_get_pen(line_width, + ( sys alpha << 24) | + (fg >> 16) | + (fg & 0xff00) | + ((fg & 0xff) << 16) + ); } else { - SelectObject( dc, stylus_get_pen(PS_SOLID, line_width, fg)); + SelectObject( sys ps, stylus_get_pen(PS_SOLID, line_width, fg)); STYLUS_FREE_PEN; } } if ( var font. style & fsUnderlined ) { - int i, Y = 0; - Point pt[2]; - + int Y = 0; if ( !is_apt( aptTextOutBaseline)) Y -= var font. descent; Y -= var font. underlinePosition; - - pt[0].x = 0; - pt[0].y = -Y; - pt[1].x = width; - pt[1].y = -Y; - if ( var font. direction != 0) { - for ( i = 0; i < 2; i++) { - float x = pt[i].x * cs.y - pt[i].y * cs.x; - float y = pt[i].x * cs.x + pt[i].y * cs.y; - pt[i].x = x + (( x > 0) ? 0.5 : -0.5); - pt[i].y = y + (( y > 0) ? 0.5 : -0.5); - } - } - - if ( use_alpha ) { - GdipDrawLineI(sys graphics, gppen, x2 + pt[0].x, y2 - pt[0].y, x2 + pt[1].x, y2 - pt[1].y); - } else { - MoveToEx( dc, x1 + pt[0].x, y1 - pt[0].y, NULL); - LineTo( dc, x1 + pt[1].x, y1 - pt[1].y); - } + draw_underline( self, x1, y1, x2, y2, width, Y, use_alpha, gppen); } if ( var font. style & fsStruckOut ) { - int i, Y = 0; - Point pt[2]; + int Y = 0; if ( !is_apt( aptTextOutBaseline)) Y -= var font. descent; @@ -209,26 +241,7 @@ underscore_font( Handle self, int x1, int y1, int x2, int y2, int width, Bool us Y -= sys otmsStrikeoutPosition; else Y -= (var font. ascent - var font. internalLeading) / 3; - - pt[0].x = 0; - pt[0].y = -Y; - pt[1].x = width; - pt[1].y = -Y; - if ( var font. direction != 0) { - for ( i = 0; i < 2; i++) { - float x = pt[i].x * cs.y - pt[i].y * cs.x; - float y = pt[i].x * cs.x + pt[i].y * cs.y; - pt[i].x = x + (( x > 0) ? 0.5 : -0.5); - pt[i].y = y + (( y > 0) ? 0.5 : -0.5); - } - } - - if ( use_alpha ) { - GdipDrawLineI(sys graphics, gppen, x2 + pt[0].x, y2 - pt[0].y, x2 + pt[1].x, y2 - pt[1].y); - } else { - MoveToEx( dc, x1 + pt[0].x, y1 - pt[0].y, NULL); - LineTo( dc, x1 + pt[1].x, y1 - pt[1].y); - } + draw_underline( self, x1, y1, x2, y2, width, Y, use_alpha, gppen); } } @@ -300,18 +313,22 @@ gp_get_polyfont_widths( Handle self, const PGlyphsOutRec t, int flags, ABC * ext if ( t->advances ) { int i; - ABC abc; + for ( i = 0; i < t->len; i++) extents->abcB += t->advances[i]; - GetCharABCWidthsI( sys ps, t->glyphs[0], 1, NULL, &abc); - extents->abcA = abc.abcA; - if ( t->fonts[0] != t->fonts[t->len - 1] ) { - font_context_rewind(&fc, t->len - 1); - font_context_next(&fc); + + if ( flags & toAddOverhangs ){ + ABC abc; + GetCharABCWidthsI( sys ps, t->glyphs[0], 1, NULL, &abc); + extents->abcA = abc.abcA; + if ( t->fonts[0] != t->fonts[t->len - 1] ) { + font_context_rewind(&fc, t->len - 1); + font_context_next(&fc); + } + GetCharABCWidthsI( sys ps, t->glyphs[t->len-1], 1, NULL, &abc); + extents->abcC = abc.abcC; + font_context_done(&fc); } - GetCharABCWidthsI( sys ps, t->glyphs[t->len-1], 1, NULL, &abc); - extents->abcC = abc.abcC; - font_context_done(&fc); return; } @@ -329,12 +346,14 @@ gp_get_polyfont_widths( Handle self, const PGlyphsOutRec t, int flags, ABC * ext local_offset += div; extents-> abcB += sz.cx; } - if ( offset == 0 ) { - GetCharABCWidthsI( sys ps, t->glyphs[0], 1, NULL, &abc); - extents->abcA = abc.abcA; - } else if ( fc.stop ) { - GetCharABCWidthsI( sys ps, t->glyphs[len-1], 1, NULL, &abc); - extents->abcC = abc.abcC; + if ( flags & toAddOverhangs ) { + if ( offset == 0 ) { + GetCharABCWidthsI( sys ps, t->glyphs[0], 1, NULL, &abc); + extents->abcA = abc.abcA; + } else if ( fc.stop ) { + GetCharABCWidthsI( sys ps, t->glyphs[len-1], 1, NULL, &abc); + extents->abcC = abc.abcC; + } } offset += len; } @@ -353,16 +372,21 @@ gp_get_text_width( Handle self, const char* text, int len, int flags) return abc.abcB; } -static int -gp_get_glyphs_width( Handle self, PGlyphsOutRec t, int flags) +int +text_gp_get_glyphs_width( Handle self, PGlyphsOutRec t, int flags) { ABC abc; + if ( t-> fonts ) gp_get_polyfont_widths(self,t,flags,&abc); else - gp_get_text_widths( self, (const char*)t->glyphs, t->len, t->flags | toGlyphs, &abc); - if ( abc.abcA < 0) abc.abcB -= abc.abcA; - if ( abc.abcC < 0) abc.abcB -= abc.abcC; + gp_get_text_widths( self, (const char*)t->glyphs, t->len, flags | toGlyphs, &abc); + + if ( flags & toAddOverhangs ) { + if ( abc.abcA < 0) abc.abcB -= abc.abcA; + if ( abc.abcC < 0) abc.abcB -= abc.abcC; + } + return abc.abcB; } @@ -384,7 +408,7 @@ paint_text_background( Handle self, const char * text, int len, int flags) if ( t-> fonts ) gp_get_polyfont_widths(self,t,toAddOverhangs,&abc); else - gp_get_text_widths( self, (const char*)t->glyphs, t->len, t->flags | toGlyphs | toAddOverhangs, &abc); + gp_get_text_widths( self, (const char*)t->glyphs, t->len, toGlyphs | toAddOverhangs, &abc); } else { gp_get_text_widths(self, text, len, flags | toAddOverhangs, &abc); } @@ -415,6 +439,64 @@ paint_text_background( Handle self, const char * text, int len, int flags) sys alpha_arena_palette = palette; } +static Bool +shaped_text_out( Handle self, const char * text, int x, int y, int len, int flags ) +{ + int ok = 0, shaper_type; + PTextShapeFunc shaper; + TextShapeRec t; + +#define SZ 256 + unsigned int size, bytelen; + uint16_t storage[SZ*5], *p_storage; + + shaper_type = tsFull; + shaper = apc_font_get_text_shaper( self, &shaper_type); + + memset( &t, 0, sizeof(t)); + size = len * 2; + if ( size > SZ ) { + if ( !( p_storage = malloc( size * 5 * sizeof(uint16_t)))) + return false; + } else + p_storage = storage; + + if ( flags & toUTF8 ) { + int x = len; + char *p = (char*) text; + while ( x-- ) p = (char*)utf8_hop((U8*)p, 1); + bytelen = p - text; + } else + bytelen = len; + + if ( !( t.text = prima_string2uint32( text, bytelen, flags & toUTF8, &bytelen))) + goto EXIT; + + t.len = bytelen; + t.n_glyphs_max = size; + t.glyphs = p_storage; + t.indexes = p_storage + size; + t.advances = p_storage + size * 2; + t.positions = (int16_t*) p_storage + size * 3; + if (( ok = shaper( self, &t))) { + GlyphsOutRec g; + memset(&g, 0, sizeof(g)); + g.len = t.n_glyphs; + g.glyphs = t.glyphs; + g.advances = t.advances; + g.positions = t.positions; + ok = apc_gp_glyphs_out( self, &g, x, y); + } + +EXIT: + if ( t.text ) + free( t.text ); + if ( p_storage != storage ) + free(storage); +#undef SZ + return ok; +} + Bool apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flags ) {objCheck false;{ @@ -422,7 +504,7 @@ apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flag HDC ps = sys ps; int bk = GetBkMode( ps); int opa = is_apt( aptTextOpaque) ? OPAQUE : TRANSPARENT; - Bool use_path, use_alpha; + Bool use_path, want_color = false; int div = 32768L / (var font. maximalWidth ? var font. maximalWidth : 1); if ( div <= 0) div = 1; @@ -433,6 +515,14 @@ apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flag their geometrical limits. */ if ( len > div) len = div; + if ( is_apt( aptTextColored )) + want_color = !( + ( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtBitmap) || + ( is_apt(aptImage) && ((PImage)self)-> type == imBW ) + ); + if ( want_color || sys alpha < 255 ) + return shaped_text_out( self, text, x, y, len, flags); + if ( flags & toUTF8 ) { int mb_len; if ( !( text = ( char *) guts.alloc_utf8_to_wchar_visual( text, len, &mb_len))) return false; @@ -443,34 +533,27 @@ apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flag SHIFT_XY(x, y); SetViewportOrgEx( sys ps, x, y, NULL ); - use_alpha = sys alpha < 255; - use_path = (GetROP2( sys ps) != R2_COPYPEN) && !use_alpha; + use_path = GetROP2( sys ps) != R2_COPYPEN; if ( use_path ) { STYLUS_USE_BRUSH; BeginPath(ps); - } else if ( !use_alpha ) { + } else { STYLUS_USE_TEXT; if ( opa != bk) SetBkMode( ps, opa); } - if ( use_alpha ) { - if ( is_apt( aptTextOpaque)) - paint_text_background(self, (char*)text, len, flags & toUTF8); - ok = text_aa_text_out( self, 0, 0, (void*)text, len, flags & toUTF8); - } else { - ok = ( flags & toUTF8 ) ? - TextOutW( ps, 0, 0, ( U16*)text, len) : - TextOutA( ps, 0, 0, text, len); - if ( !ok ) apiErr; - } + ok = ( flags & toUTF8 ) ? + TextOutW( ps, 0, 0, ( U16*)text, len) : + TextOutA( ps, 0, 0, text, len); + if ( !ok ) apiErr; if ( var font. style & (fsUnderlined | fsStruckOut)) - underscore_font( self, 0, 0, x, y, gp_get_text_width( self, text, len, flags), use_alpha); + text_underscore_font( self, 0, 0, x, y, gp_get_text_width( self, text, len, flags), false); if ( use_path ) { EndPath(ps); FillPath(ps); - } else if ( !use_alpha ) { + } else { if ( opa != bk) SetBkMode( ps, bk); } @@ -660,7 +743,7 @@ apc_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y) t->len = savelen; if ( var font. style & (fsUnderlined | fsStruckOut)) - underscore_font( self, 0, yy, x, y + yy, gp_get_glyphs_width( self, t, 0), use_alpha); + text_underscore_font( self, 0, yy, x, y + yy, text_gp_get_glyphs_width( self, t, 0), use_alpha); if ( use_path ) { EndPath(ps); @@ -1864,9 +1947,9 @@ apc_gp_get_text_width( Handle self, const char* text, int len, int flags) } int -apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec t) +apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec t, int flags) { - return gp_get_glyphs_width( self, t, t->flags); + return text_gp_get_glyphs_width( self, t, flags); } void @@ -1911,7 +1994,7 @@ apc_gp_get_glyphs_box( Handle self, PGlyphsOutRec t) if ( t-> fonts ) gp_get_polyfont_widths(self,t,toAddOverhangs,&abc); else - gp_get_text_widths( self, (const char*)t->glyphs, t->len, t->flags | toGlyphs | toAddOverhangs, &abc); + gp_get_text_widths( self, (const char*)t->glyphs, t->len, toGlyphs | toAddOverhangs, &abc); gp_get_text_box(self, &abc, pt); return pt;