diff --git a/MANIFEST b/MANIFEST index 886bfd414..11399b77c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -507,6 +507,7 @@ win32/clip.c win32/cursor.c win32/dev.c win32/dnd.c +win32/dwrite.c win32/files.c win32/gdiplus.c win32/global.c diff --git a/Makefile.PL b/Makefile.PL index e2520ad6f..add94a39a 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1074,7 +1074,10 @@ MSCVER 'include/generic', ); - push @LIBS, qw(usp10 gdi32 gdiplus mpr winspool comdlg32 msimg32 ole32 uuid) if $Win32; # add more when appropriate + push @LIBS, qw( + usp10 gdi32 gdiplus mpr winspool comdlg32 msimg32 ole32 uuid + d2d1 dwrite + ) if $Win32; # add more when appropriate push @LIBPATH, '/usr/lib/w32api' if $cygwin; if ($^O eq 'solaris') { push @LIBPATH, '/opt/csw/lib'; diff --git a/Prima/Classes.pm b/Prima/Classes.pm index 6060545cc..3d76e1836 100644 --- a/Prima/Classes.pm +++ b/Prima/Classes.pm @@ -728,6 +728,7 @@ sub profile_default region => undef, rop => rop::CopyPut, rop2 => rop::NoOper, + textColored => 0, textOutBaseline => 0, textOpaque => 0, ); diff --git a/Prima/Drawable/Metafile.pm b/Prima/Drawable/Metafile.pm index 7677c2ef2..e95fb3393 100644 --- a/Prima/Drawable/Metafile.pm +++ b/Prima/Drawable/Metafile.pm @@ -32,7 +32,7 @@ my @props = qw( alpha antialias color backColor fillMode fillPattern lineEnd lineJoin linePattern lineWidth rop rop2 miterLimit - textOpaque textOutBaseline + textOpaque textOutBaseline textColored ); for my $prop_name (@props) { diff --git a/Prima/Drawable/Subcanvas.pm b/Prima/Drawable/Subcanvas.pm index 3d7410b93..90f3ee885 100644 --- a/Prima/Drawable/Subcanvas.pm +++ b/Prima/Drawable/Subcanvas.pm @@ -20,7 +20,7 @@ sub profile_default { # needs to be handled with a tied hash at some point. my @easy_props = qw(color backColor fillMode fillPattern font lineEnd lineJoin linePattern lineWidth rop rop2 miterLimit - textOpaque textOutBaseline + textOpaque textOutBaseline textColored ); sub init { diff --git a/Prima/PS/Drawable.pm b/Prima/PS/Drawable.pm index d93cff1a0..4a44960be 100644 --- a/Prima/PS/Drawable.pm +++ b/Prima/PS/Drawable.pm @@ -56,7 +56,7 @@ sub save_state $self-> {save_state} = {}; $self-> {save_state}-> {$_} = $self-> $_() for qw( color backColor fillPattern lineEnd linePattern lineWidth miterLimit - rop rop2 textOpaque textOutBaseline font lineJoin fillMode + rop rop2 textOpaque textColored textOutBaseline font lineJoin fillMode ); $self->{save_state}->{fpType} = $self->{fpType}; $self-> {save_state}-> {$_} = [$self-> $_()] for qw( @@ -70,7 +70,7 @@ sub restore_state { my $self = $_[0]; for ( qw( color backColor fillPattern lineEnd linePattern lineWidth miterLimit - rop rop2 textOpaque textOutBaseline font lineJoin fillMode)) { + rop rop2 textColored textOpaque textOutBaseline font lineJoin fillMode)) { $self-> $_( $self-> {save_state}-> {$_}); } $self->{fpType} = $self->{save_state}->{fpType}; diff --git a/Prima/VB/Classes.pm b/Prima/VB/Classes.pm index c8d7bfa26..15a3cafe6 100644 --- a/Prima/VB/Classes.pm +++ b/Prima/VB/Classes.pm @@ -961,7 +961,7 @@ sub prf_types linePattern => ['linePattern'], lineWidth => ['lineWidth'], rop => ['rop', 'rop2'], - bool => ['textOutBaseline', 'textOpaque', 'fillMode'], + bool => ['textOutBaseline', 'textOpaque', 'fillMode', 'textColored'], point => ['translate', 'fillPatternOffset'], palette => ['palette'], image => ['region'], diff --git a/class/Drawable.c b/class/Drawable.c index 09ee600dd..34a4785a8 100644 --- a/class/Drawable.c +++ b/class/Drawable.c @@ -39,6 +39,7 @@ Drawable_init( Handle self, HV * profile) my-> set_region ( self, pget_H ( region)); my-> set_rop ( self, pget_i ( rop)); my-> set_rop2 ( self, pget_i ( rop2)); + my-> set_textColored ( self, pget_B ( textColored)); my-> set_textOpaque ( self, pget_B ( textOpaque)); my-> set_textOutBaseline( self, pget_B ( textOutBaseline)); if ( pexist( fillPatternOffset)) @@ -677,6 +678,14 @@ Drawable_rop2( Handle self, Bool set, int rop2) return rop2; } +Bool +Drawable_textColored( Handle self, Bool set, Bool colored) +{ + if (!set) return apc_gp_get_text_colored( self); + apc_gp_set_text_colored( self, colored); + return colored; +} + Bool Drawable_textOpaque( Handle self, Bool set, Bool opaque) { diff --git a/class/Drawable.cls b/class/Drawable.cls index 5dc8476f8..7281c7129 100644 --- a/class/Drawable.cls +++ b/class/Drawable.cls @@ -36,6 +36,7 @@ object Prima::Drawable ( Prima::Component) property int rop; property int rop2; property Point size; + property Bool textColored; property Bool textOpaque; property Bool textOutBaseline; property int width; @@ -107,5 +108,7 @@ object Prima::Drawable ( Prima::Component) c_only void calculate_text_box( int advance, Bool text_out_baseline, Point overhangs, Point * pt); c_only int* do_text_wrap( TextWrapRec * tw, GlyphWrapRec * gw, uint16_t * log2vis); c_only Bool assert_drawing_mode( int mode ); - + c_only void save_font( SaveFont *f); + c_only void restore_font( SaveFont *f); + c_only Bool switch_font( SaveFont *f, uint16_t fid); } diff --git a/class/Drawable/mapper.c b/class/Drawable/mapper.c index 18731e69f..2730fdec6 100644 --- a/class/Drawable/mapper.c +++ b/class/Drawable/mapper.c @@ -399,14 +399,14 @@ Drawable_save_font( Handle self, SaveFont *f) } void -Drawable_restore_font( Handle self, SaveFont *f) +Drawable_restore_font_internal( Handle self, SaveFont *f, Bool quick) { if ( !f->restore ) return; f-> last_fid = 0; f->restore = false; - if ( Drawable_set_font == my->set_font && (is_opt(optSystemDrawable) || is_opt(optInFontQuery) )) { + if ( quick ) { opt_clear(optFontTrigCache); apc_gp_set_font( self, &f->font); } else @@ -414,7 +414,7 @@ Drawable_restore_font( Handle self, SaveFont *f) } Bool -Drawable_switch_font( Handle self, SaveFont *f, uint16_t fid) +Drawable_switch_font_internal( Handle self, SaveFont *f, uint16_t fid, Bool quick) { Font src, dst; @@ -427,22 +427,20 @@ Drawable_switch_font( Handle self, SaveFont *f, uint16_t fid) } src = PASSIVE_FONT(fid)->font; - if ( Drawable_set_font == my->set_font && (is_opt(optSystemDrawable) || is_opt(optInFontQuery) )) { - dst = var->font; - src.size = dst.size; + dst = quick ? + var->font : + my->get_font(self); + src.size = dst.size; + if ( ( src.undef.size = dst.undef.size )) { src.height = dst.height; - src.undef.size = dst.undef.size; src.undef.height = dst.undef.height; + } + if ( quick ) { apc_font_pick( self, &src, &dst); if ( strcmp(dst.name, src.name) != 0 ) return false; apc_gp_set_font( self, &dst); } else { - dst = my->get_font(self); - src.size = dst.size; - src.height = dst.height; - src.undef.size = dst.undef.size; - src.undef.height = dst.undef.height; my->set_font(self, src); } f-> restore = true; @@ -450,6 +448,21 @@ Drawable_switch_font( Handle self, SaveFont *f, uint16_t fid) return true; } +Bool +Drawable_switch_font( Handle self, SaveFont *f, uint16_t fid) +{ + return Drawable_switch_font_internal(self, f, fid, + Drawable_set_font == my->set_font && (is_opt(optSystemDrawable) || is_opt(optInFontQuery) ) + ); +} + +void +Drawable_restore_font( Handle self, SaveFont *f) +{ + Drawable_restore_font_internal(self, f, + Drawable_set_font == my->set_font && (is_opt(optSystemDrawable) || is_opt(optInFontQuery) ) + ); +} #ifdef __cplusplus } diff --git a/class/Drawable/shape.c b/class/Drawable/shape.c index ec8828b8e..b11bfbed6 100644 --- a/class/Drawable/shape.c +++ b/class/Drawable/shape.c @@ -431,7 +431,7 @@ shape_unicode(Handle self, PTextShapeRec t, PTextShapeFunc shaper, t-> analysis = analysis; save_fonts = t->fonts; if ( t->fonts ) t-> fonts = fonts; - Drawable_save_font(self, &savefont); + my->save_font(self, &savefont); while (( run_len = run_next(t, &brr)) > 0) { TextShapeRec run; run_alloc(t, run_offs, run_len, glyph_mapper_only ^ reorder_swaps_rtl, &run); @@ -448,7 +448,7 @@ shape_unicode(Handle self, PTextShapeRec t, PTextShapeFunc shaper, } #endif if ( t-> fonts ) { - if ( Drawable_switch_font(self, &savefont, run.fonts[0])) { + if ( my->switch_font(self, &savefont, run.fonts[0])) { #ifdef _DEBUG printf("%d: set font #%d\n", run_offs, run.fonts[0]); #endif @@ -494,7 +494,7 @@ shape_unicode(Handle self, PTextShapeRec t, PTextShapeFunc shaper, semistatic_done( &p_fonts); semistatic_done( &p_l2v); - Drawable_restore_font( self, &savefont); + my->restore_font( self, &savefont); return ok; } diff --git a/class/Drawable/text.c b/class/Drawable/text.c index 04558365e..0c7f05be8 100644 --- a/class/Drawable/text.c +++ b/class/Drawable/text.c @@ -342,10 +342,10 @@ Drawable_get_glyphs_box( Handle self, PGlyphsOutRec t, Point * pt) l = Drawable_get_glyphs_width(self, t, false); if ( t->fonts ) - Drawable_save_font(self, &savefont); + my->save_font(self, &savefont); if ( t-> fonts ) - Drawable_switch_font( self, &savefont, t-> fonts[0]); + my->switch_font( self, &savefont, t-> fonts[0]); if (( abc = Drawable_call_get_font_abc( self, t->glyphs[0], t->glyphs[0], toGlyphs)) != NULL) { int l = t->len - 1; @@ -363,7 +363,7 @@ Drawable_get_glyphs_box( Handle self, PGlyphsOutRec t, Point * pt) } if ( t->fonts ) - Drawable_restore_font(self, &savefont); + my->restore_font(self, &savefont); Drawable_calculate_text_box(self, l, text_out_baseline, ovx, pt); } diff --git a/class/Drawable/wrap.c b/class/Drawable/wrap.c index 2d243738f..2cb2cd7d5 100644 --- a/class/Drawable/wrap.c +++ b/class/Drawable/wrap.c @@ -211,7 +211,7 @@ query_abc_range_glyphs( Handle self, GlyphWrapRec * t, unsigned int base) used_fonts[0] = 0x01; /* fid = 0 */ key = Drawable_font_key(var->font.name, var->font.style); i = PTR2IV(hash_fetch(font_substitutions, key, strlen(key))); - Drawable_save_font(self, &savefont); + my->save_font(self, &savefont); if ( i > 0 ) { /* copy ranges from subst table */ pfe = PASSIVE_FONT(i); @@ -250,7 +250,7 @@ query_abc_range_glyphs( Handle self, GlyphWrapRec * t, unsigned int base) used_fonts[fid >> 3] |= 1 << (fid & 7); pfe = PASSIVE_FONT(fid); - if ( !Drawable_switch_font(self, &savefont, fid)) + if ( !my->switch_font(self, &savefont, fid)) continue; if ( !pfe-> ranges_queried ) @@ -273,7 +273,7 @@ query_abc_range_glyphs( Handle self, GlyphWrapRec * t, unsigned int base) free(abc2); } - Drawable_restore_font( self, &savefont ); + my->restore_font( self, &savefont ); } NO_FONT_ABC: diff --git a/class/Image.cls b/class/Image.cls index 7403945c8..9b5a5e39b 100644 --- a/class/Image.cls +++ b/class/Image.cls @@ -98,4 +98,6 @@ object Prima::Image( Prima::Drawable) c_only Bool assert_drawing_mode( int mode ); c_only void begin_preserve_type( PImagePreserveTypeRec save); c_only void end_preserve_type( PImagePreserveTypeRec save); + c_only void restore_font( SaveFont *f); + c_only Bool switch_font( SaveFont *f, uint16_t fid); } diff --git a/class/Image/text.c b/class/Image/text.c index 65e78cf4d..a93833308 100644 --- a/class/Image/text.c +++ b/class/Image/text.c @@ -50,7 +50,7 @@ Image_font_match( SV * dummy, Font * source, Font * dest, Bool pick) Font Image_get_font( Handle self) { - if ( !is_opt(optInFontQuery)) + if ( !opt_InPaint && !is_opt(optInFontQuery)) my-> begin_font_query(self); return var-> font; @@ -67,7 +67,7 @@ Image_set_font( Handle self, Font font) return; } - if ( !is_opt(optInFontQuery)) + if ( !opt_InPaint && !is_opt(optInFontQuery)) my-> begin_font_query(self); inherited set_font(self, font); @@ -569,6 +569,22 @@ Image_font_encodings( Handle self) return Application_font_encodings( self); } +Bool +Image_switch_font( Handle self, SaveFont *f, uint16_t fid) +{ + return Drawable_switch_font_internal(self, f, fid, + Image_set_font == my->set_font && (is_opt(optSystemDrawable) || is_opt(optInFontQuery) ) + ); +} + +void +Image_restore_font( Handle self, SaveFont *f) +{ + Drawable_restore_font_internal(self, f, + Image_set_font == my->set_font && (is_opt(optSystemDrawable) || is_opt(optInFontQuery) ) + ); +} + #ifdef __cplusplus } #endif diff --git a/examples/fontdlg.pl b/examples/fontdlg.pl index 63ddb7199..1e1348a3c 100644 --- a/examples/fontdlg.pl +++ b/examples/fontdlg.pl @@ -606,6 +606,7 @@ sub create_info_window itemHeight => $ih, gridColor => cl::Back, hScroll => 1, + textColored => 1, onSelectItem => sub { my ( $self, $item, $sel) = @_; if ( defined( my $c = $charmap{$item->[0]} )) { @@ -633,7 +634,7 @@ sub create_info_window } $self-> draw_item_background( $canvas, $x, $y + 1, $x2, $y2, $prelight ); if ( defined( my $c = $charmap{$itemIndex} )) { - $canvas-> text_out( chr($c), $x + $ih / 4, $y + $ih / 4); + $canvas-> text_shape_out( chr($c), $x + $ih / 4, $y + $ih / 4); } $canvas-> set( color => $cs[0], backColor => $cs[1]) if $focused || $prelight; }, diff --git a/include/Drawable_private.h b/include/Drawable_private.h index 4011926e0..eadc94ee0 100644 --- a/include/Drawable_private.h +++ b/include/Drawable_private.h @@ -85,20 +85,11 @@ Drawable_query_ranges(PPassiveFontEntry pfe); Bool Drawable_read_glyphs( PGlyphsOutRec t, SV * text, Bool indexes_required, const char * caller); -typedef struct { - Font font; - Bool restore; - uint16_t last_fid; -} SaveFont; - -void -Drawable_save_font( Handle self, SaveFont *f); - void -Drawable_restore_font( Handle self, SaveFont *f); +Drawable_restore_font_internal( Handle self, SaveFont *f, Bool quick); Bool -Drawable_switch_font( Handle self, SaveFont *f, uint16_t fid); +Drawable_switch_font_internal( Handle self, SaveFont *f, uint16_t fid, Bool quick); Bool Drawable_read_line_ends(SV *lineEnd, DrawablePaintState *state); diff --git a/include/apricot.h b/include/apricot.h index 0301f5a7e..febf6e193 100644 --- a/include/apricot.h +++ b/include/apricot.h @@ -6,7 +6,7 @@ #define POLLUTE_NAME_SPACE 1 #endif -#define PRIMA_CORE_VERSION 2024111201 +#define PRIMA_CORE_VERSION 2024111801 #define PRIMA_VERSION_BOOTCHECK \ if(apc_get_core_version()!=PRIMA_CORE_VERSION) \ @@ -3359,7 +3359,9 @@ FV(Outline) FV(Default) #define fvScalableBitmap 0x0003 FV(ScalableBitmap) -#define fvMask 0x0003 +#define fvColorOutline 0x0005 +FV(ColorOutline) +#define fvMask 0x0007 END_TABLE(fv,UV) #undef FV @@ -3840,6 +3842,12 @@ typedef struct { PList * cache; } GlyphWrapRec; +typedef struct { + Font font; + Bool restore; + uint16_t last_fid; +} SaveFont; + /* regions */ #define rgnSorted 0x1 @@ -4151,6 +4159,9 @@ apc_gp_get_rop2( Handle self); extern Point* apc_gp_get_text_box( Handle self, const char * text, int len, int flags); +extern Bool +apc_gp_get_text_colored( Handle self); + extern Bool apc_gp_get_text_opaque( Handle self); @@ -4228,6 +4239,9 @@ apc_gp_set_rop( Handle self, int rop); extern Bool apc_gp_set_rop2( Handle self, int rop); +extern Bool +apc_gp_set_text_colored( Handle self, Bool colored); + extern Bool apc_gp_set_text_matrix( Handle self, Matrix matrix); diff --git a/include/unix/guts.h b/include/unix/guts.h index 7c2653c9a..2f2076195 100644 --- a/include/unix/guts.h +++ b/include/unix/guts.h @@ -957,6 +957,7 @@ typedef struct _drawable_sys_data unsigned sizemax_set : 1; unsigned sync_paint : 1; unsigned task_listed : 1; + unsigned text_colored : 1; unsigned title_utf8 : 1; unsigned transparent : 1; unsigned transparent_busy : 1; @@ -1015,7 +1016,7 @@ typedef struct _PaintState XGCValues gcv; } nonpaint; int alpha, fill_mode, n_dashes, rop, rop2; - Bool antialias, text_opaque, text_baseline, null_hatch; + Bool antialias, text_opaque, text_baseline, null_hatch, text_colored; Point fill_pattern_offset; Handle fill_image; FillPattern fill_pattern; diff --git a/include/win32/win32guts.h b/include/win32/win32guts.h index f16455fac..0be241ace 100644 --- a/include/win32/win32guts.h +++ b/include/win32/win32guts.h @@ -169,6 +169,7 @@ typedef struct _HandleOptions_ { unsigned aptEnabled : 1; // enabled flag unsigned aptTextOpaque : 1; // gp text drawing flag unsigned aptTextOutBaseline : 1; // gp text drawing flag + unsigned aptTextColored : 1; // draw color font with colors unsigned aptWinPosDetermined : 1; // 0 when size is set, but position is not unsigned aptOnTop : 1; // HWND_TOPMOST is set unsigned aptLayered : 1; // WS_EX_LAYERED @@ -352,7 +353,7 @@ typedef struct _PaintSaveData Point fill_pattern_offset; int rop, rop2; Font font; - Bool text_opaque, text_out_baseline; + Bool text_opaque, text_out_baseline, text_colored; } PaintSaveData, *PPaintSaveData; typedef struct @@ -374,6 +375,8 @@ typedef struct _DCFont Font font; int refcnt; HFONT hfont; + void * dw_colorface; + Bool dw_checked; } DCFont, *PDCFont; #define DCO_PEN 0 @@ -673,9 +676,6 @@ LRESULT CALLBACK generic_frame_handler ( HWND win, UINT msg, WPARAM mp1, LRESULT CALLBACK layered_frame_handler ( HWND win, UINT msg, WPARAM mp1, LPARAM mp2); LRESULT CALLBACK generic_view_handler ( HWND win, UINT msg, WPARAM mp1, LPARAM mp2); -extern Bool aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide); -extern Bool aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, HFONT font); -extern void aa_free_arena(Handle self, Bool for_reuse); extern WCHAR * alloc_utf8_to_wchar( const char * utf8, int length, int * mb_len); extern WCHAR * alloc_utf8_to_wchar_visual( const char * utf8, int length, int * mb_len); extern WCHAR * alloc_ascii_to_wchar( const char * text, int *length); @@ -705,6 +705,11 @@ extern Bool dnd_clipboard_get_data( Handle id, PClipboardDataRec c); extern Bool dnd_clipboard_has_format( Handle id); extern Bool dnd_clipboard_set_data( Handle id, PClipboardDataRec c); extern PList dnd_clipboard_get_formats(); +extern Bool dwrite_font_init(void); +extern void dwrite_font_done(void); +extern void dwrite_free_face(void *face); +extern Bool dwrite_logfont_colored( LOGFONTW *lf ); +extern Bool dwrite_color_text_out(Handle self, PDCFont dc, PGlyphsOutRec t, int x, int y); extern void dpi_change(void); extern char * err_msg( DWORD errId, char * buffer); extern char * err_msg_gplus( GpStatus errId, char * buffer); @@ -774,6 +779,14 @@ extern void stylus_release( Handle self ); extern GpPen* stylus_gp_get_pen(int line_width, uint32_t color); extern HPEN stylus_get_pen( DWORD style, DWORD line_width, COLORREF color ); extern HBRUSH stylus_get_solid_brush( COLORREF color ); +extern Bool text_aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, HFONT font); +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 void wchar2char( char * dest, WCHAR * src, int lim); extern Bool yield( Bool wait_for_event ); diff --git a/unix/graphics.c b/unix/graphics.c index df9361bc6..0c653645d 100644 --- a/unix/graphics.c +++ b/unix/graphics.c @@ -1510,6 +1510,12 @@ apc_gp_get_text_opaque( Handle self) return X(self)-> flags. opaque ? true : false; } +Bool +apc_gp_get_text_colored( Handle self) +{ + return X(self)-> flags. text_colored ? true : false; +} + Bool apc_gp_get_text_out_baseline( Handle self) { @@ -1798,6 +1804,13 @@ apc_gp_set_rop2( Handle self, int rop) return true; } +Bool +apc_gp_set_text_colored( Handle self, Bool colored) +{ + X(self)-> flags. colored = !!colored; + return true; +} + Bool apc_gp_set_text_opaque( Handle self, Bool opaque) { @@ -1850,6 +1863,7 @@ apc_gp_push(Handle self, GCStorageFunction * destructor, void * user_data, unsig state->rop2 = XX->rop2; state->text_baseline = XX->flags.base_line; state->text_opaque = XX->flags.opaque; + state->text_colored = XX->flags.colored; if ( state-> in_paint ) { state->paint.fore = XX->fore; state->paint.back = XX->back; @@ -1909,6 +1923,7 @@ apc_gp_pop( Handle self, void * user_data) XX->rop2 = state->rop2; XX->flags. base_line = state->text_baseline; XX->flags. opaque = state->text_opaque; + XX->flags. colored = state->text_colored; if ( state-> in_paint ) { XX->fore = state->paint.fore; XX->back = state->paint.back; diff --git a/win32/dwfont.c b/win32/dwfont.c new file mode 100644 index 000000000..62d70ec03 --- /dev/null +++ b/win32/dwfont.c @@ -0,0 +1,423 @@ +/* DirectWrite-based fonts */ + +#define INITGUID +#include "win32\win32guts.h" + +#include +#include +#include + +#include "Widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define sys (( PDrawableData)(( PComponent) self)-> sysData)-> +#define dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)-> +#define var (( PWidget) self)-> +#define HANDLE sys handle +#define DHANDLE(x) dsys(x) handle + + +static Bool dw_ok = false; + +static ID2D1Factory *d2d_factory = NULL; +static IDWriteFactory4 *factory = NULL; +static IDWriteFontCollection1 *collection = NULL; +static IDWriteGdiInterop *gdi = NULL; + +Bool +dwrite_font_init(void) +{ + HRESULT hr; + + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, (REFIID) &IID_ID2D1Factory, NULL, (void**) &d2d_factory); + if ( hr != S_OK ) + apiHErrRet(hr); + + hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory4, (IUnknown**) &factory); + if ( hr != S_OK ) + apiHErrRet(hr); + + hr = factory->lpVtbl->IDWriteFactory3_GetSystemFontCollection( factory, 1, &collection, 1 ); + if ( hr != S_OK ) + apiHErrRet(hr); + + hr = factory->lpVtbl->GetGdiInterop( factory, &gdi ); + if ( hr != S_OK ) + apiHErrRet(hr); + + dw_ok = true; + return true; +} + +void +dwrite_font_done(void) +{ + if ( gdi ) gdi ->lpVtbl->Release(gdi); + if ( collection ) collection ->lpVtbl->Release(collection); + if ( factory ) factory ->lpVtbl->Release(factory); + if ( d2d_factory) d2d_factory->lpVtbl->Base.Release((IUnknown*)d2d_factory); + + d2d_factory = NULL; + factory = NULL; + collection = NULL; + + dw_ok = false; +} + +Bool +dwrite_logfont_colored( LOGFONTW *lf ) +{ + HRESULT hr; + IDWriteFont2 *font; + Bool ok = false; + + if (!dw_ok) return ok; + + hr = gdi->lpVtbl->CreateFontFromLOGFONT(gdi, lf, (IDWriteFont**) &font); + if ( hr != S_OK ) + apiHErrRet(hr); + + if ( font->lpVtbl->IsColorFont(font)) + ok = true; + + font->lpVtbl->Release(font); + return ok; +} + +static IDWriteColorGlyphRunEnumerator1* +get_enumerator(Handle self, PDCFont dc, PGlyphsOutRec t, int x, int y) +{ + int i, j, n; + HRESULT hr; + DWRITE_GLYPH_RUN run; + Byte *buf; + FLOAT advances[256], *p_advances; + DWRITE_GLYPH_OFFSET offsets[256], *p_offsets; + D2D1_POINT_2F offset = {x, y}; + IDWriteColorGlyphRunEnumerator1 *enumerator; + + if (!dw_ok) + return NULL; + if ( dc-> dw_checked && !dc->dw_colorface ) + return NULL; + + if ( !dc->dw_checked ) { + HRESULT hr; + hr = gdi->lpVtbl->CreateFontFaceFromHdc(gdi, sys ps, (IDWriteFontFace**) &dc-> dw_colorface); + dc->dw_checked = true; + if ( hr != S_OK ) + return dc-> dw_colorface = NULL; + } + n = t->len; + if ( n > 256 && (t->advances || t->positions)) { + if ( !( buf = malloc((sizeof(FLOAT) + sizeof(DWRITE_GLYPH_OFFSET)) * n))) + return NULL; + p_advances = (FLOAT*) buf; + p_offsets = (DWRITE_GLYPH_OFFSET*) (buf + sizeof(FLOAT) * n); + } else { + p_advances = advances; + p_offsets = offsets; + buf = NULL; + } + + if ( t-> advances ) { + for ( i = 0; i < n; i++) + p_advances[i] = t->advances[i]; + } else + p_advances = NULL; + + if ( t-> positions ) { + for ( i = j = 0; i < n; i++) { + offsets[i].advanceOffset = t->positions[j++]; + offsets[i].ascenderOffset = t->positions[j++]; + } + } else + p_offsets = NULL; + + run.fontFace = ( IDWriteFontFace *) dc->dw_colorface; + run.fontEmSize = var font.size; + run.glyphCount = t->len; + run.glyphIndices = t->glyphs; + run.glyphAdvances = p_advances; + run.glyphOffsets = p_offsets; + run.isSideways = 0; + run.bidiLevel = 0; + + hr = factory->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun( + factory, offset, &run, NULL, + DWRITE_GLYPH_IMAGE_FORMATS_COLR, + DWRITE_MEASURING_MODE_NATURAL, + NULL, 0, + &enumerator + ); + + if ( buf ) + free(buf); + + if ( hr == DWRITE_E_NOCOLOR ) + return NULL; + if ( hr != S_OK ) { + apiHErr(hr); + return NULL; + } + + return enumerator; +} + +typedef struct { + GlyphsOutRec g; + Bool has_color; + COLORREF colorref; + Point baseline; + int format; +} GlyphColorRec; + +static GlyphColorRec* +run2glyphs( const DWRITE_COLOR_GLYPH_RUN1 *run) +{ + GlyphColorRec *t; + Byte *ptr; + unsigned int size; + + size = + sizeof(GlyphColorRec) + + sizeof(uint16_t) * run->glyphRun.glyphCount * ( + 1 + + (run->glyphRun.glyphAdvances ? 1 : 0) + + (run->glyphRun.glyphOffsets ? 2 : 0) + ); + if ( !( ptr = malloc(size))) + return NULL; + t = (GlyphColorRec*) ptr; + + memset( t, 0, size); + t-> g.len = run-> glyphRun.glyphCount; + t-> format = run-> glyphImageFormat; + ptr += sizeof(GlyphColorRec); + + t->baseline.x = run->baselineOriginX; + t->baseline.y = run->baselineOriginY; + if ( run-> paletteIndex != 65535 ) { + t->colorref = + (int) (run->runColor.r * 255.0 + .5) | + ((int) (run->runColor.g * 255.0 + .5)) * 256 | + ((int) (run->runColor.b * 255.0 + .5)) * 65536; + t->has_color = true; + } + + t->g.glyphs = (uint16_t*) ptr; + memcpy( t->g.glyphs, run->glyphRun.glyphIndices, sizeof(uint16_t) * t->g.len); + ptr += sizeof(uint16_t) * t->g.len; + + if ( run->glyphRun.glyphAdvances) { + int i; + uint16_t *a; + int16_t *o; + + a = t->g.advances = t->g.glyphs + t->g.len; + for ( i = 0; i < run->glyphRun.glyphCount; i++) + *(a++) = (run->glyphRun.glyphAdvances[i] > 65535.0) ? + 65535 : + (run->glyphRun.glyphAdvances[i] + .5); + ptr += sizeof(uint16_t) * t->g.len; + + if ( run->glyphRun.glyphOffsets ) { + o = t->g.positions = (int16_t*)t->g.advances + t->g.len; + for ( i = 0; i < run->glyphRun.glyphCount; i++) { + *(o++) = + (run->glyphRun.glyphOffsets[i].advanceOffset > -32767.0) ? ( + (run->glyphRun.glyphOffsets[i].advanceOffset > 32767.0) ? 32767 : + (run->glyphRun.glyphOffsets[i].advanceOffset + .5) + ) : -32767; + *(o++) = + (run->glyphRun.glyphOffsets[i].ascenderOffset > -32767.0) ? ( + (run->glyphRun.glyphOffsets[i].ascenderOffset > 32767.0) ? 32767 : + (run->glyphRun.glyphOffsets[i].ascenderOffset + .5) + ) : -32767; + } + ptr += sizeof(int16_t) * 2 * t->g.len; + } + } + + return t; +} + +static PList +enumerate_colorrun(IDWriteColorGlyphRunEnumerator1 *enumerator, unsigned int seed_glyphs) +{ + PList l; + + if ( seed_glyphs < 16 ) seed_glyphs = 16; + seed_glyphs *= 2; + if ( !( l = plist_create( seed_glyphs, seed_glyphs ))) + return NULL; + + while (1) { + BOOL ok; + HRESULT hr; + const DWRITE_COLOR_GLYPH_RUN1 *run; + GlyphColorRec *t; + + if ( enumerator->lpVtbl->IDWriteColorGlyphRunEnumerator1_GetCurrentRun( enumerator, &run) != S_OK ) + break; + if (( t = run2glyphs( run )) != NULL ) + list_add(l, (Handle) t); + hr = enumerator->lpVtbl->MoveNext( enumerator, &ok); + if ( hr != S_OK ) { + apiHErr(hr); + break; + } + } + + if ( l-> count == 0 ) { + plist_destroy(l); + return NULL; + } + + return l; +} + +static Bool +is_aa_colr( Handle self, PList l) +{ + int i; + Bool has_no_advances = false, has_colr = false; + + if ( sys alpha == 255 ) return false; + + for ( i = 0; i < l->count; i++) { + GlyphColorRec *t = (GlyphColorRec*) l->items[i]; + if (t-> format == DWRITE_GLYPH_IMAGE_FORMATS_COLR) + has_colr = true; + if (!t->g.advances) + has_no_advances = true; + } + + return has_colr && !has_no_advances; +} + +static void +draw_colorglyphs( Handle self, HFONT hfont, PList l ) +{ + int i; + + for ( i = 0; i < l->count; i++) { + GlyphColorRec *t = (GlyphColorRec*) l->items[i]; + + switch (t-> format) { + case 0: + STYLUS_USE_TEXT; + if ( sys alpha < 255 ) + text_aa_glyphs_out( self, &t->g, t->baseline.x, t->baseline.y, NULL, hfont); + else + text_gp_glyphs_out( self, &t->g, t->baseline.x, t->baseline.y, 0); + break; + case DWRITE_GLYPH_IMAGE_FORMATS_COLR: + if ( t->has_color ) { + SetTextColor( sys ps, t->colorref ); + STYLUS_FREE_TEXT; + } else + STYLUS_USE_TEXT; + + text_gp_glyphs_out( self, &t->g, t->baseline.x, t->baseline.y, 0); + break; + } + } +} + +static void +draw_aa_colr( Handle self, HFONT hfont, PList l, int xx, int yy ) +{ + NPoint delta = {0,0}; + int i, j, x = MININT; + + if ( !text_aa_init(self, hfont, false)) + return; + + while ( 1 ) { + int next_x = x, advance = -1; + Point offset = {0,0}; + + for ( i = 0; i < l->count; i++) { + GlyphColorRec *t = (GlyphColorRec*) l->items[i]; + int dx = t->baseline.x; + for ( j = 0; j < t->g.len; j++) { + if ( dx > x && (next_x == x || dx < next_x)) + next_x = dx; + dx += t->g.advances[j]; + } + } + if ( next_x == x ) + break; + x = next_x; + + text_aa_begin_render(self, false); + for ( i = 0; i < l->count; i++) { + GlyphColorRec *t = (GlyphColorRec*) l->items[i]; + int dx = t->baseline.x, idx = -1; + for ( j = 0; j < t->g.len; j++) { + uint16_t a = t->g.advances[j]; + if ( dx == next_x ) { + if ( advance < 0 ) { + advance = a; + if ( t->g.positions ){ + int16_t *p = t->g.positions + j * 2; + offset.x = *(p++); + offset.y = *(p++); + } + } + idx = j; + break; + } else + dx += a; + } + if ( idx < 0 ) + continue; + + SetTextColor( sys alpha_arena_dc, t->has_color ? t->colorref : sys rq_pen.logpen.lopnColor); + text_aa_render( self, t->g.glyphs[idx]); + } + + if ( !text_aa_end_render(self, xx, yy, &delta, NULL, advance, offset.x, offset.y, false)) + break; + } +} + +Bool +dwrite_color_text_out(Handle self, PDCFont dc, PGlyphsOutRec t, int x, int y) +{ + PList l; + IDWriteColorGlyphRunEnumerator1 *enumerator; + + if ( !dw_ok ) return false; + + if ( !( enumerator = get_enumerator(self, dc, t, x, y))) + return false; + l = enumerate_colorrun( enumerator, t->len ); + enumerator->lpVtbl->Release(enumerator); + if ( !l ) + return false; + + if ( is_aa_colr( self, l )) + draw_aa_colr( self, dc->hfont, l, x, y ); + else + draw_colorglyphs( self, dc->hfont, l ); + + list_delete_all( l, true ); + plist_destroy( l ); + + return true; +} + +void +dwrite_free_face(void *face) +{ + ((IDWriteFontFace*)face)->lpVtbl->Release((IDWriteFontFace*)face); +} + +#ifdef __cplusplus +} +#endif diff --git a/win32/gdiplus.c b/win32/gdiplus.c index d568d85ed..2eb9a8dba 100644 --- a/win32/gdiplus.c +++ b/win32/gdiplus.c @@ -284,7 +284,7 @@ apc_gp_aa_fill_poly( Handle self, int numPts, NPoint * points) #define GRAD 57.29577951 void -aa_free_arena(Handle self, Bool for_reuse) +text_aa_free_arena(Handle self, Bool for_reuse) { if ( !for_reuse && sys alpha_arena_palette ) { free(sys alpha_arena_palette); @@ -320,7 +320,7 @@ aa_make_arena(Handle self) if ( w < sys alpha_arena_size.x || h < sys alpha_arena_size.y || !sys alpha_arena_dc ) { HDC dc; if ( sys alpha_arena_bitmap ) { - aa_free_arena(self, true); + text_aa_free_arena(self, true); } else { if (!( sys alpha_arena_dc = CreateCompatibleDC(0))) return false; @@ -356,8 +356,8 @@ aa_make_arena(Handle self) return true; } -static Bool -aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance, int dx, int dy) +Bool +text_aa_end_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance, int dx, int dy, Bool use_palette) { BLENDFUNCTION bf; float xx, yy, shift; @@ -365,6 +365,7 @@ aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance int i, j, miny, maxy, maxx, minx; Point sz; NPoint cs = CDrawable(self)->trig_cache(self); + uint32_t alpha = sys alpha; /* replace white to our color + alpha, calculate minimal affected box */ p = sys alpha_arena_ptr; @@ -377,13 +378,29 @@ aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance i++ ) { Bool match = false; - for ( j = 0; j < sys alpha_arena_size.x; j++, p++) { - if (1 || *p != 0) { - register Byte *argb = (Byte*) p; - *p = palette[argb[0] + argb[1] + argb[2]]; - if ( minx > j ) minx = j; - if ( maxx < j ) maxx = j; - match = true; + if ( use_palette ) { + for ( j = 0; j < sys alpha_arena_size.x; j++, p++) { + if (*p != 0) { + register Byte *argb = (Byte*) p; + *p = palette[argb[0] + argb[1] + argb[2]]; + if ( minx > j ) minx = j; + if ( maxx < j ) maxx = j; + match = true; + } + } + } else { + for ( j = 0; j < sys alpha_arena_size.x; j++, p++) { + if (*p != 0xffffffff) { + register Byte *argb = (Byte*) p; + argb[0] = argb[0] * alpha / 255; + argb[1] = argb[1] * alpha / 255; + argb[2] = argb[2] * alpha / 255; + argb[3] = alpha; + if ( minx > j ) minx = j; + if ( maxx < j ) maxx = j; + match = true; + } else + *p = 0; } } if ( match ) { @@ -391,7 +408,6 @@ aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance if ( maxy < i ) maxy = i; } } - if ( maxy < miny ) return true; /* calculate advance for the next glyph and the position, if needed, for this one */ if ( advance >= 0 ) { @@ -417,6 +433,8 @@ aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance delta->x += shift; } + if ( maxy < miny ) return true; + /* calculate the aperture */ sz = sys alpha_arena_size; x -= sz.x/2; @@ -453,7 +471,7 @@ aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance } /* precalculate alpha map */ -Bool +static Bool aa_fill_palette(Handle self) { int i,j,r,g,b; @@ -486,7 +504,7 @@ aa_fill_palette(Handle self) } Bool -aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide) +text_aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide) { int i; NPoint delta = { 0, 0 }; @@ -507,42 +525,66 @@ aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide) } 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 ( !aa_render(self, x, y, &delta, &abc, -1, 0, 0)) + if ( !text_aa_end_render(self, x, y, &delta, &abc, -1, 0, 0, true)) return false; } return true; } Bool -aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, HFONT font) +text_aa_init( Handle self, HFONT font, Bool use_palette) { - int i; - NPoint delta = { 0, 0 }; - uint16_t *advances = t->advances; - int16_t *positions = t->positions; HFONT f; - - if ( !(aa_fill_palette(self) && aa_make_arena(self))) + if ( use_palette && !aa_fill_palette(self)) + return false; + if ( !aa_make_arena(self)) return false; - - if ( text_advance ) - *text_advance = 0; f = SelectObject( sys alpha_arena_dc, font ); if ( !sys alpha_arena_stock_font ) sys alpha_arena_stock_font = f; sys alpha_arena_font_changed = false; + return true; +} + +void +text_aa_begin_render( Handle self, Bool use_palette) +{ + memset(sys alpha_arena_ptr, use_palette ? 0 : 0xff, sys alpha_arena_size.x * sys alpha_arena_size.y * 4); +} + +Bool +text_aa_render( Handle self, uint16_t glyph) +{ + if ( !ExtTextOutW(sys alpha_arena_dc, + sys alpha_arena_size.x/2, sys alpha_arena_size.y/2, + ETO_GLYPH_INDEX, NULL, (LPCWSTR)(&glyph), 1, + NULL + )) + apiErrRet; + return true; +} + +Bool +text_aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, HFONT font) +{ + int i; + NPoint delta = {0,0}; + uint16_t *advances = t->advances; + int16_t *positions = t->positions; + + if ( !text_aa_init(self, font, true)) + return false; + if ( text_advance ) + *text_advance = 0; + for ( i = 0; i < t->len; i++) { ABCFLOAT abc, *pabc; int adv, dx, dy; - memset(sys alpha_arena_ptr, 0, sys alpha_arena_size.x * sys alpha_arena_size.y * 4); - if ( !ExtTextOutW(sys alpha_arena_dc, - sys alpha_arena_size.x/2, sys alpha_arena_size.y/2, - ETO_GLYPH_INDEX, NULL, (LPCWSTR)(t->glyphs) + i, 1, - NULL - )) - apiErrRet; + text_aa_begin_render(self, true); + if ( !text_aa_render( self, t->glyphs[i])) + return false; if ( advances ) { adv = *(advances++); @@ -552,7 +594,7 @@ aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, H dx = *(positions++); dy = *(positions++); } else { - ABC abci; + ABC abci = {0,0,0}; adv = -1; pabc = &abc; dx = dy = 0; @@ -563,7 +605,7 @@ aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, H abc.abcfB = abci.abcB; abc.abcfC = abci.abcC; } - if ( !aa_render(self, x, y, &delta, pabc, adv, dx, dy)) + if ( !text_aa_end_render(self, x, y, &delta, pabc, adv, dx, dy, true)) return false; } diff --git a/win32/global.c b/win32/global.c index ce3d8776f..0423ebf4d 100644 --- a/win32/global.c +++ b/win32/global.c @@ -424,6 +424,8 @@ window_subsystem_init( char * error_buf) if ( !file_subsystem_init()) return false; + dwrite_font_init(); + return true; } @@ -465,6 +467,7 @@ menu_bitmap_cleaner( void * value, int keyLen, void * key, void * dummy) void window_subsystem_done() { + dwrite_font_done(); if (guts. ole_initialized) OleUninitialize(); free( time_defs); diff --git a/win32/gp.c b/win32/gp.c index 205d5be65..55b5d31c2 100644 --- a/win32/gp.c +++ b/win32/gp.c @@ -30,7 +30,7 @@ apc_gp_done( Handle self) { objCheck false; cleanup_gc_stack(self, 1); - aa_free_arena(self, 0); + text_aa_free_arena(self, 0); if ( sys bm) if ( !DeleteObject( sys bm)) apiErr; if ( sys pal) @@ -1284,6 +1284,7 @@ apc_gp_push(Handle self, GCStorageFunction * destructor, void * user_data, unsig state->common.font = var font; state->common.text_out_baseline = is_apt( aptTextOutBaseline); state->common.text_opaque = is_apt( aptTextOpaque); + state->common.text_colored = is_apt( aptTextColored); if ( var fillPatternImage ) protect_object( state->fill_image = var fillPatternImage ); return true; @@ -1361,6 +1362,7 @@ apc_gp_pop( Handle self, void * user_data) var fillPatternImage = state-> fill_image; apt_assign(aptTextOutBaseline, state->common.text_out_baseline); apt_assign(aptTextOpaque, state->common.text_opaque); + apt_assign(aptTextColored, state->common.text_colored); if ( sys alpha_arena_palette ) { free(sys alpha_arena_palette); sys alpha_arena_palette = NULL; diff --git a/win32/stock.c b/win32/stock.c index 906935f4b..2af9c01b8 100644 --- a/win32/stock.c +++ b/win32/stock.c @@ -801,8 +801,8 @@ font_alloc( Font * data) ret = ( PDCFont) malloc( sizeof( DCFont)); if ( !ret) return NULL; + memset( ret, 0, sizeof(DCFont)); memcpy( f = &ret-> font, data, sizeof( Font)); - ret-> refcnt = 0; font_font2logfont( f, &logfont); if ( !( ret-> hfont = CreateFontIndirectW( &logfont))) { LOGFONTW lf; @@ -828,6 +828,10 @@ font_free( PDCFont res, Bool permanent) res-> refcnt = 0; return; } + if ( res-> dw_colorface) { + dwrite_free_face(res->dw_colorface); + res->dw_colorface = NULL; + } if ( res-> hfont) { DeleteObject( res-> hfont); res-> hfont = NULL; @@ -1209,6 +1213,7 @@ typedef struct _FEnumStruc int fType; Bool useWidth; Bool wantOutline; + Bool wantColored; Bool useVector; Bool usePitch; Bool forceSize; @@ -1242,8 +1247,13 @@ fep( ENUMLOGFONTEXW FAR *e, NEWTEXTMETRICEXW FAR *t, DWORD type, LPARAM _es) } if ( font-> vector != fvDefault) { - int fvector = (( t-> ntmTm. tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE)) ? fvOutline : fvBitmap); - if ( fvector != font-> vector) + int src = (( t-> ntmTm. tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE)) ? fvOutline : fvBitmap); + if ( es-> wantColored ) { + if ( src == fvOutline && !dwrite_logfont_colored( &e->elfLogFont )) + return 1; + src = fvColorOutline; + } + if ( src != font-> vector) return 1; // so this font cannot be selected due quality pickup failure } @@ -1336,6 +1346,7 @@ font_font2gp_internal( PFont font, Point res, Bool forceSize, HDC theDC) HDC dc = theDC ? theDC : dc_alloc(); Bool useNameSubplacing = false; LOGFONTW elf; + Font savefont = *font; if ( !dc) return fvBitmap; @@ -1343,14 +1354,18 @@ font_font2gp_internal( PFont font, Point res, Bool forceSize, HDC theDC) es. resValue = es. heiValue = es. widValue = INT_MAX; es. useWidth = font-> width != 0; es. useVector = font->vector != fvDefault; - es. wantOutline = (font-> vector == fvDefault && fabs(font-> direction) > 0.0001) || font->vector == fvOutline; + es. wantColored = font->vector == fvColorOutline; + es. wantOutline = + (font-> vector == fvDefault && fabs(font-> direction) > 0.0001) || + font->vector == fvOutline || + font->vector == fvColorOutline; es. usePitch = font-> pitch != fpDefault; es. res = res; es. forceSize = forceSize; es. font = font; es. matchILead = forceSize ? ( font-> size >= 0) : ( font-> height >= 0); - useNameSubplacing = es. usePitch || es. useVector; + useNameSubplacing = es. usePitch || es. useVector; if ( font-> height < 0) font-> height *= -1; if ( font-> size < 0) font-> size *= -1; memset(&font->undef, 0xff, sizeof(font->undef)); @@ -1465,12 +1480,21 @@ font_font2gp_internal( PFont font, Point res, Bool forceSize, HDC theDC) font_logfontname2font( &lpf, font); font_textmetric2font( &tm, font, true); if ( have_otm ) font_otm2font( &otm, font ); + if ( es.wantColored && font->vector == fvOutline && dwrite_logfont_colored(&es.lf)) + font-> vector = fvColorOutline; strlcpy( font-> family, es. family, LF_FULLFACESIZE); font-> is_utf8.family = es.is_utf8_family; - out( fvOutline); + out( font->vector ); } } + // if colored request is too strict + if ( es.wantColored && es.count == 0 ) { + *font = savefont; + font-> vector = fvOutline; + return font_font2gp_internal( font, res, forceSize, theDC); + } + // if strict match not found, use subplacing if ( useNameSubplacing && recursiveFFPitch == 0) { @@ -1618,6 +1642,8 @@ fep2( ENUMLOGFONTEXW FAR *e, NEWTEXTMETRICEXW FAR *t, DWORD type, LPARAM _f) if ( !fm) return 1; memset( fm, 0, sizeof(Font)); font_textmetric2font(( TEXTMETRICW*) &t-> ntmTm, fm, false); + if ( fm->vector == fvOutline && dwrite_logfont_colored(&e->elfLogFont)) + fm-> vector = fvColorOutline; if ( f-> hash) { /* multi-encoding format */ char ** enc = (char**) fm-> encoding; unsigned char * shift = (unsigned char*)enc + sizeof(char *) - 1; @@ -2046,6 +2072,7 @@ hwnd_enter_paint( Handle self) apc_gp_set_alpha( self, sys alpha); apc_gp_set_antialias( self, is_apt( aptGDIPlus)); + apc_gp_set_text_colored( self, is_apt( aptTextColored)); apc_gp_set_text_opaque( self, is_apt( aptTextOpaque)); apc_gp_set_text_out_baseline( self, is_apt( aptTextOutBaseline)); apc_gp_set_fill_mode( self, sys fill_mode); diff --git a/win32/text.c b/win32/text.c index 164e7deff..75aa9790f 100644 --- a/win32/text.c +++ b/win32/text.c @@ -4,6 +4,8 @@ #include #include "guts.h" #include "win32\win32guts.h" +#include "DeviceBitmap.h" +#include "Image.h" #include "Widget.h" #ifdef __cplusplus @@ -25,7 +27,7 @@ typedef struct { Bool fixed_pitch, orig_fixed_pitch; Handle self; HFONT orig, saved, curr; - PDCFont nondefault_font; + PDCFont nondefault_font, curr_dc, orig_dc; uint32_t nondefault_fid; uint16_t *fonts; } FontContext; @@ -40,11 +42,14 @@ font_context_init( FontContext * fc, Handle self, PGlyphsOutRec t) fc->len = t->len; fc->dc = sys ps; fc->fixed_pitch = fc->orig_fixed_pitch = (sys tmPitchAndFamily & TMPF_FIXED_PITCH) ? 0 : 1; + fc->orig_dc = fc->curr_dc = sys dc_font; + fc->orig_dc->refcnt++; } static void font_context_done( FontContext * fc ) { + fc->orig_dc->refcnt--; if ( fc-> nondefault_font ) font_free(fc-> nondefault_font, false); if ( fc-> saved ) @@ -66,6 +71,7 @@ font_context_next( FontContext * fc ) int start, len; HFONT hfont, selected; Bool fixed_pitch; + PDCFont dc; if ( fc-> stop ) return 0; @@ -94,12 +100,15 @@ font_context_next( FontContext * fc ) if ( nfid == 0 ) { hfont = fc->orig; fixed_pitch = fc->orig_fixed_pitch; + dc = fc->orig_dc; } else if ( nfid == fc->nondefault_fid ) { hfont = fc->nondefault_font->hfont; fixed_pitch = fc->nondefault_font->font.pitch == fpFixed; + dc = fc->nondefault_font; } else if ( !( _src = prima_font_mapper_get_font(nfid))) { hfont = fc->orig; fixed_pitch = fc->orig_fixed_pitch; + dc = fc->orig_dc; } else { dst = (( PWidget) fc->self)-> font; src = *_src; @@ -116,14 +125,17 @@ font_context_next( FontContext * fc ) fc->nondefault_fid = nfid; hfont = fc->nondefault_font->hfont; fixed_pitch = fc->nondefault_font->font.pitch == fpFixed; + dc = fc->nondefault_font; } else { hfont = fc->orig; fixed_pitch = fc->orig_fixed_pitch; + dc = fc->orig_dc; } } - fc->curr = hfont; + fc->curr = hfont; fc->fixed_pitch = fixed_pitch; + fc->curr_dc = dc; selected = SelectObject(fc->dc, fc->curr); if ( !fc->saved ) fc->saved = selected; @@ -403,7 +415,6 @@ paint_text_background( Handle self, const char * text, int len, int flags) sys alpha_arena_palette = palette; } - Bool apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flags ) {objCheck false;{ @@ -445,7 +456,7 @@ apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flag if ( use_alpha ) { if ( is_apt( aptTextOpaque)) paint_text_background(self, (char*)text, len, flags & toUTF8); - ok = aa_text_out( self, 0, 0, (void*)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) : @@ -506,8 +517,8 @@ fix_combiners_pdx( Handle self, PGlyphsOutRec t, INT *pdx) } } -static Bool -gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, Bool fixed_pitch) +Bool +text_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, Bool fixed_pitch) { Bool ok; if ( t-> advances ) { @@ -516,8 +527,6 @@ gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, B int16_t *goffsets = t->positions; uint16_t *advances = t->advances; - if ( text_advance ) *text_advance = 0; - n = t-> len * 2; if ( n > SZ) { if ( !( pdx = malloc(sizeof(INT) * n))) @@ -531,8 +540,6 @@ gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, B int adv = *(advances++); pdx[i] = adv; pdx[i + 1] = 0; - if ( text_advance ) - *text_advance += adv; if ( i == 0 ) { x += gx; @@ -552,16 +559,27 @@ gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, B #undef SZ } else { ok = ExtTextOutW(sys ps, x, y, ETO_GLYPH_INDEX, NULL, (LPCWSTR) t->glyphs, t->len, NULL); - if ( text_advance ) { - SIZE sz; - if ( !GetTextExtentPointI( sys ps, (WCHAR*) t->glyphs, t->len, &sz)) apiErr; - *text_advance += sz.cx; - } } if ( !ok ) apiErr; return ok; } +static int +calc_advance( Handle self, PGlyphsOutRec t ) +{ + int ret = 0; + if ( t->advances) { + int i; + for ( i = 0; i < t->len; i++) + ret += t->advances[i]; + } else { + SIZE sz = {0,0}; + if ( !GetTextExtentPointI( sys ps, (WCHAR*) t->glyphs, t->len, &sz)) apiErr; + ret = sz.cx; + } + return ret; +} + Bool apc_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y) {objCheck false;{ @@ -574,6 +592,7 @@ apc_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y) FontContext fc; float fxx, fyy; NPoint cs = CDrawable(self)->trig_cache(self); + Bool want_color = false; select_world_transform(self, true); SHIFT_XY(x,y); @@ -597,13 +616,33 @@ apc_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y) fyy = yy = 0; savelen = t->len; font_context_init(&fc, self, t); + + if ( is_apt( aptTextColored )) + want_color = !( + ( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtBitmap) || + ( is_apt(aptImage) && ((PImage)self)-> type == imBW ) + ); + while (( t-> len = font_context_next(&fc)) > 0 ) { int advance = 0; - if ( !( ok = use_alpha ? - aa_glyphs_out(self, t, xx, yy, fc.stop ? NULL : &advance, fc.curr) : - gp_glyphs_out(self, t, xx, yy, fc.stop ? NULL : &advance, fc.fixed_pitch) - )) - break; + + if ( want_color && dwrite_color_text_out(self, fc.curr_dc, t, xx, yy) ) { + if ( !fc.stop ) + advance = calc_advance(self, t); + ok = true; + } else { + STYLUS_USE_TEXT; + if ( use_alpha ) { + ok = text_aa_glyphs_out(self, t, xx, yy, fc.stop ? NULL : &advance, fc.curr); + } else { + ok = text_gp_glyphs_out(self, t, xx, yy, fc.fixed_pitch); + if ( !fc.stop ) + advance = calc_advance(self, t); + } + if ( !ok ) + break; + } + if ( !fc.stop ) { fxx += (float)advance * cs.y; fyy -= (float)advance * cs.x; @@ -1999,6 +2038,21 @@ apc_gp_get_text_out_baseline( Handle self) return is_apt( aptTextOutBaseline); } +Bool +apc_gp_get_text_colored( Handle self) +{ + objCheck false; + return is_apt( aptTextColored); +} + +Bool +apc_gp_set_text_colored( Handle self, Bool colored) +{ + objCheck false; + apt_assign( aptTextColored, colored); + return true; +} + Bool apc_gp_get_text_opaque( Handle self) {