diff options
| author | Gerd Möllmann | 2024-11-16 04:31:46 +0100 |
|---|---|---|
| committer | Gerd Möllmann | 2024-11-16 04:31:46 +0100 |
| commit | 36c81859f6c3d798fa1c1d9eb45cf730e0237e04 (patch) | |
| tree | 3710ea1733b746f420836fc892b7a1e52b28cb66 /src | |
| parent | f62d70f52f4f6b7ed158d618bf790df21f171172 (diff) | |
| parent | 29098a291f535c8e2be114171308169f025de43f (diff) | |
| download | emacs-36c81859f6c3d798fa1c1d9eb45cf730e0237e04.tar.gz emacs-36c81859f6c3d798fa1c1d9eb45cf730e0237e04.zip | |
Merge branch 'master' into scratch/tty-child-frames
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffer.c | 13 | ||||
| -rw-r--r-- | src/charset.c | 3 | ||||
| -rw-r--r-- | src/data.c | 12 | ||||
| -rw-r--r-- | src/dispextern.h | 1 | ||||
| -rw-r--r-- | src/emacs.c | 1 | ||||
| -rw-r--r-- | src/fns.c | 23 | ||||
| -rw-r--r-- | src/ftcrfont.c | 11 | ||||
| -rw-r--r-- | src/image.c | 10 | ||||
| -rw-r--r-- | src/itree.c | 52 | ||||
| -rw-r--r-- | src/itree.h | 18 | ||||
| -rw-r--r-- | src/lread.c | 2 | ||||
| -rw-r--r-- | src/nsterm.m | 35 | ||||
| -rw-r--r-- | src/pdumper.c | 11 | ||||
| -rw-r--r-- | src/w32dwrite.c | 1110 | ||||
| -rw-r--r-- | src/w32fns.c | 38 | ||||
| -rw-r--r-- | src/w32font.c | 39 | ||||
| -rw-r--r-- | src/w32font.h | 31 | ||||
| -rw-r--r-- | src/w32gdiplus.h | 139 | ||||
| -rw-r--r-- | src/w32gui.h | 2 | ||||
| -rw-r--r-- | src/w32image.c | 129 | ||||
| -rw-r--r-- | src/w32menu.c | 5 | ||||
| -rw-r--r-- | src/w32select.c | 198 | ||||
| -rw-r--r-- | src/w32term.c | 78 | ||||
| -rw-r--r-- | src/w32term.h | 5 | ||||
| -rw-r--r-- | src/w32uniscribe.c | 29 | ||||
| -rw-r--r-- | src/window.c | 2 | ||||
| -rw-r--r-- | src/xdisp.c | 2 |
27 files changed, 1771 insertions, 228 deletions
diff --git a/src/buffer.c b/src/buffer.c index 90c5efdfbf7..2955ee6399b 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -111,7 +111,7 @@ static int last_per_buffer_idx; | |||
| 111 | static void call_overlay_mod_hooks (Lisp_Object list, Lisp_Object overlay, | 111 | static void call_overlay_mod_hooks (Lisp_Object list, Lisp_Object overlay, |
| 112 | bool after, Lisp_Object arg1, | 112 | bool after, Lisp_Object arg1, |
| 113 | Lisp_Object arg2, Lisp_Object arg3); | 113 | Lisp_Object arg2, Lisp_Object arg3); |
| 114 | static void reset_buffer_local_variables (struct buffer *, bool); | 114 | static void reset_buffer_local_variables (struct buffer *, int); |
| 115 | 115 | ||
| 116 | /* Alist of all buffer names vs the buffers. This used to be | 116 | /* Alist of all buffer names vs the buffers. This used to be |
| 117 | a Lisp-visible variable, but is no longer, to prevent lossage | 117 | a Lisp-visible variable, but is no longer, to prevent lossage |
| @@ -1110,10 +1110,11 @@ reset_buffer (register struct buffer *b) | |||
| 1110 | Instead, use Fkill_all_local_variables. | 1110 | Instead, use Fkill_all_local_variables. |
| 1111 | 1111 | ||
| 1112 | If PERMANENT_TOO, reset permanent buffer-local variables. | 1112 | If PERMANENT_TOO, reset permanent buffer-local variables. |
| 1113 | If not, preserve those. */ | 1113 | If not, preserve those. PERMANENT_TOO = 2 means ignore |
| 1114 | the permanent-local property of non-builtin variables. */ | ||
| 1114 | 1115 | ||
| 1115 | static void | 1116 | static void |
| 1116 | reset_buffer_local_variables (struct buffer *b, bool permanent_too) | 1117 | reset_buffer_local_variables (struct buffer *b, int permanent_too) |
| 1117 | { | 1118 | { |
| 1118 | int offset, i; | 1119 | int offset, i; |
| 1119 | 1120 | ||
| @@ -1139,7 +1140,7 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) | |||
| 1139 | bset_invisibility_spec (b, Qt); | 1140 | bset_invisibility_spec (b, Qt); |
| 1140 | 1141 | ||
| 1141 | /* Reset all (or most) per-buffer variables to their defaults. */ | 1142 | /* Reset all (or most) per-buffer variables to their defaults. */ |
| 1142 | if (permanent_too) | 1143 | if (permanent_too == 1) |
| 1143 | bset_local_var_alist (b, Qnil); | 1144 | bset_local_var_alist (b, Qnil); |
| 1144 | else | 1145 | else |
| 1145 | { | 1146 | { |
| @@ -1168,7 +1169,7 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) | |||
| 1168 | swap_in_global_binding (XSYMBOL (sym)); | 1169 | swap_in_global_binding (XSYMBOL (sym)); |
| 1169 | } | 1170 | } |
| 1170 | 1171 | ||
| 1171 | if (!NILP (prop)) | 1172 | if (!NILP (prop) && !permanent_too) |
| 1172 | { | 1173 | { |
| 1173 | /* If permanent-local, keep it. */ | 1174 | /* If permanent-local, keep it. */ |
| 1174 | last = tmp; | 1175 | last = tmp; |
| @@ -3006,7 +3007,7 @@ the normal hook `change-major-mode-hook'. */) | |||
| 3006 | 3007 | ||
| 3007 | /* Actually eliminate all local bindings of this buffer. */ | 3008 | /* Actually eliminate all local bindings of this buffer. */ |
| 3008 | 3009 | ||
| 3009 | reset_buffer_local_variables (current_buffer, !NILP (kill_permanent)); | 3010 | reset_buffer_local_variables (current_buffer, !NILP (kill_permanent) ? 2 : 0); |
| 3010 | 3011 | ||
| 3011 | /* Force mode-line redisplay. Useful here because all major mode | 3012 | /* Force mode-line redisplay. Useful here because all major mode |
| 3012 | commands call this function. */ | 3013 | commands call this function. */ |
diff --git a/src/charset.c b/src/charset.c index e8d0826f4c2..f7d80cc3f3e 100644 --- a/src/charset.c +++ b/src/charset.c | |||
| @@ -1007,7 +1007,8 @@ usage: (define-charset-internal ...) */) | |||
| 1007 | 1007 | ||
| 1008 | i = CODE_POINT_TO_INDEX (&charset, charset.max_code); | 1008 | i = CODE_POINT_TO_INDEX (&charset, charset.max_code); |
| 1009 | if (MAX_CHAR - charset.code_offset < i) | 1009 | if (MAX_CHAR - charset.code_offset < i) |
| 1010 | error ("Unsupported max char: %d", charset.max_char); | 1010 | error ("Unsupported max char: %d + %ud > MAX_CHAR (%d)", |
| 1011 | i, charset.max_code, MAX_CHAR); | ||
| 1011 | charset.max_char = i + charset.code_offset; | 1012 | charset.max_char = i + charset.code_offset; |
| 1012 | i = CODE_POINT_TO_INDEX (&charset, charset.min_code); | 1013 | i = CODE_POINT_TO_INDEX (&charset, charset.min_code); |
| 1013 | charset.min_char = i + charset.code_offset; | 1014 | charset.min_char = i + charset.code_offset; |
diff --git a/src/data.c b/src/data.c index fd2d9705642..66cf34c1e60 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -756,7 +756,7 @@ global value outside of any lexical scope. */) | |||
| 756 | breaking backward compatibility, as some users of fboundp may | 756 | breaking backward compatibility, as some users of fboundp may |
| 757 | expect t in particular, rather than any true value. */ | 757 | expect t in particular, rather than any true value. */ |
| 758 | DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, | 758 | DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, |
| 759 | doc: /* Return t if SYMBOL's function definition is not void. */) | 759 | doc: /* Return t if SYMBOL's function definition is not nil. */) |
| 760 | (Lisp_Object symbol) | 760 | (Lisp_Object symbol) |
| 761 | { | 761 | { |
| 762 | CHECK_SYMBOL (symbol); | 762 | CHECK_SYMBOL (symbol); |
| @@ -782,12 +782,12 @@ See also `fmakunbound'. */) | |||
| 782 | } | 782 | } |
| 783 | 783 | ||
| 784 | DEFUN ("fmakunbound", Ffmakunbound, Sfmakunbound, 1, 1, 0, | 784 | DEFUN ("fmakunbound", Ffmakunbound, Sfmakunbound, 1, 1, 0, |
| 785 | doc: /* Make SYMBOL's function definition be void. | 785 | doc: /* Make SYMBOL's function definition be nil. |
| 786 | Return SYMBOL. | 786 | Return SYMBOL. |
| 787 | 787 | ||
| 788 | If a function definition is void, trying to call a function by that | 788 | If a function definition is nil, trying to call a function by |
| 789 | name will cause a `void-function' error. For more details, see Info | 789 | that name will cause a `void-function' error. For more details, see |
| 790 | node `(elisp) Function Cells'. | 790 | Info node `(elisp) Function Cells'. |
| 791 | 791 | ||
| 792 | See also `makunbound'. */) | 792 | See also `makunbound'. */) |
| 793 | (register Lisp_Object symbol) | 793 | (register Lisp_Object symbol) |
| @@ -800,7 +800,7 @@ See also `makunbound'. */) | |||
| 800 | } | 800 | } |
| 801 | 801 | ||
| 802 | DEFUN ("symbol-function", Fsymbol_function, Ssymbol_function, 1, 1, 0, | 802 | DEFUN ("symbol-function", Fsymbol_function, Ssymbol_function, 1, 1, 0, |
| 803 | doc: /* Return SYMBOL's function definition, or nil if that is void. */) | 803 | doc: /* Return SYMBOL's function definition. */) |
| 804 | (Lisp_Object symbol) | 804 | (Lisp_Object symbol) |
| 805 | { | 805 | { |
| 806 | CHECK_SYMBOL (symbol); | 806 | CHECK_SYMBOL (symbol); |
diff --git a/src/dispextern.h b/src/dispextern.h index 4a013236432..47afc48bb60 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -3177,6 +3177,7 @@ struct image | |||
| 3177 | #endif /* HAVE_ANDROID */ | 3177 | #endif /* HAVE_ANDROID */ |
| 3178 | #ifdef HAVE_NTGUI | 3178 | #ifdef HAVE_NTGUI |
| 3179 | XFORM xform; | 3179 | XFORM xform; |
| 3180 | bool smoothing; | ||
| 3180 | #endif | 3181 | #endif |
| 3181 | #ifdef HAVE_HAIKU | 3182 | #ifdef HAVE_HAIKU |
| 3182 | /* The affine transformation to apply to this image. */ | 3183 | /* The affine transformation to apply to this image. */ |
diff --git a/src/emacs.c b/src/emacs.c index b0d1f2f53e8..bdd9eee10c4 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -2472,6 +2472,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2472 | #ifdef HAVE_W32NOTIFY | 2472 | #ifdef HAVE_W32NOTIFY |
| 2473 | syms_of_w32notify (); | 2473 | syms_of_w32notify (); |
| 2474 | #endif /* HAVE_W32NOTIFY */ | 2474 | #endif /* HAVE_W32NOTIFY */ |
| 2475 | syms_of_w32dwrite (); | ||
| 2475 | #endif /* WINDOWSNT */ | 2476 | #endif /* WINDOWSNT */ |
| 2476 | 2477 | ||
| 2477 | syms_of_xwidget (); | 2478 | syms_of_xwidget (); |
| @@ -2823,8 +2823,8 @@ static ptrdiff_t hash_lookup_with_hash (struct Lisp_Hash_Table *h, | |||
| 2823 | if EQUAL_KIND == EQUAL_NO_QUIT. */ | 2823 | if EQUAL_KIND == EQUAL_NO_QUIT. */ |
| 2824 | 2824 | ||
| 2825 | static bool | 2825 | static bool |
| 2826 | internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | 2826 | internal_equal_1 (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, |
| 2827 | int depth, Lisp_Object ht) | 2827 | int depth, Lisp_Object *ht) |
| 2828 | { | 2828 | { |
| 2829 | tail_recurse: | 2829 | tail_recurse: |
| 2830 | if (depth > 10) | 2830 | if (depth > 10) |
| @@ -2832,13 +2832,13 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | |||
| 2832 | eassert (equal_kind != EQUAL_NO_QUIT); | 2832 | eassert (equal_kind != EQUAL_NO_QUIT); |
| 2833 | if (depth > 200) | 2833 | if (depth > 200) |
| 2834 | error ("Stack overflow in equal"); | 2834 | error ("Stack overflow in equal"); |
| 2835 | if (NILP (ht)) | 2835 | if (NILP (*ht)) |
| 2836 | ht = CALLN (Fmake_hash_table, QCtest, Qeq); | 2836 | *ht = CALLN (Fmake_hash_table, QCtest, Qeq); |
| 2837 | switch (XTYPE (o1)) | 2837 | switch (XTYPE (o1)) |
| 2838 | { | 2838 | { |
| 2839 | case Lisp_Cons: case Lisp_Vectorlike: | 2839 | case Lisp_Cons: case Lisp_Vectorlike: |
| 2840 | { | 2840 | { |
| 2841 | struct Lisp_Hash_Table *h = XHASH_TABLE (ht); | 2841 | struct Lisp_Hash_Table *h = XHASH_TABLE (*ht); |
| 2842 | hash_hash_t hash = hash_from_key (h, o1); | 2842 | hash_hash_t hash = hash_from_key (h, o1); |
| 2843 | ptrdiff_t i = hash_lookup_with_hash (h, o1, hash); | 2843 | ptrdiff_t i = hash_lookup_with_hash (h, o1, hash); |
| 2844 | if (i >= 0) | 2844 | if (i >= 0) |
| @@ -2888,8 +2888,8 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | |||
| 2888 | { | 2888 | { |
| 2889 | if (! CONSP (o2)) | 2889 | if (! CONSP (o2)) |
| 2890 | return false; | 2890 | return false; |
| 2891 | if (! internal_equal (XCAR (o1), XCAR (o2), | 2891 | if (! internal_equal_1 (XCAR (o1), XCAR (o2), |
| 2892 | equal_kind, depth + 1, ht)) | 2892 | equal_kind, depth + 1, ht)) |
| 2893 | return false; | 2893 | return false; |
| 2894 | o2 = XCDR (o2); | 2894 | o2 = XCDR (o2); |
| 2895 | if (EQ (XCDR (o1), o2)) | 2895 | if (EQ (XCDR (o1), o2)) |
| @@ -2964,7 +2964,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | |||
| 2964 | Lisp_Object v1, v2; | 2964 | Lisp_Object v1, v2; |
| 2965 | v1 = AREF (o1, i); | 2965 | v1 = AREF (o1, i); |
| 2966 | v2 = AREF (o2, i); | 2966 | v2 = AREF (o2, i); |
| 2967 | if (!internal_equal (v1, v2, equal_kind, depth + 1, ht)) | 2967 | if (!internal_equal_1 (v1, v2, equal_kind, depth + 1, ht)) |
| 2968 | return false; | 2968 | return false; |
| 2969 | } | 2969 | } |
| 2970 | return true; | 2970 | return true; |
| @@ -2985,6 +2985,13 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | |||
| 2985 | return false; | 2985 | return false; |
| 2986 | } | 2986 | } |
| 2987 | 2987 | ||
| 2988 | static bool | ||
| 2989 | internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | ||
| 2990 | int depth, Lisp_Object ht) | ||
| 2991 | { | ||
| 2992 | return internal_equal_1 (o1, o2, equal_kind, depth, &ht); | ||
| 2993 | } | ||
| 2994 | |||
| 2988 | /* Return -1/0/1 for the </=/> lexicographic relation between bool-vectors. */ | 2995 | /* Return -1/0/1 for the </=/> lexicographic relation between bool-vectors. */ |
| 2989 | static int | 2996 | static int |
| 2990 | bool_vector_cmp (Lisp_Object a, Lisp_Object b) | 2997 | bool_vector_cmp (Lisp_Object a, Lisp_Object b) |
diff --git a/src/ftcrfont.c b/src/ftcrfont.c index 3700154e44a..2ef85d4d566 100644 --- a/src/ftcrfont.c +++ b/src/ftcrfont.c | |||
| @@ -708,6 +708,17 @@ ftcrhbfont_end_hb_font (struct font *font, hb_font_t *hb_font) | |||
| 708 | struct font_info *ftcrfont_info = (struct font_info *) font; | 708 | struct font_info *ftcrfont_info = (struct font_info *) font; |
| 709 | cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; | 709 | cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; |
| 710 | 710 | ||
| 711 | eassert (hb_font == ftcrfont_info->hb_font); | ||
| 712 | /* ftcrfont_info->hb_font holds a reference to the FT_Face returned by | ||
| 713 | cairo_ft_scaled_font_lock_face. Keeping it around after the matching | ||
| 714 | unlock call would violate the API contract, and cause corrupted | ||
| 715 | display of composed characters (Bug#73752). We destroy and NULLify | ||
| 716 | hb_font here, which will then cause fthbfont_begin_hb_font, called by | ||
| 717 | ftcrhbfont_begin_hb_font, to recreate hb_font anew, taking into | ||
| 718 | consideration any scale changes in FT_Face. */ | ||
| 719 | hb_font_destroy (ftcrfont_info->hb_font); | ||
| 720 | ftcrfont_info->hb_font = NULL; | ||
| 721 | |||
| 711 | cairo_ft_scaled_font_unlock_face (scaled_font); | 722 | cairo_ft_scaled_font_unlock_face (scaled_font); |
| 712 | ftcrfont_info->ft_size = NULL; | 723 | ftcrfont_info->ft_size = NULL; |
| 713 | } | 724 | } |
diff --git a/src/image.c b/src/image.c index 34936977a40..db7f6acd171 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -3049,12 +3049,10 @@ image_set_transform (struct frame *f, struct image *img) | |||
| 3049 | flip = !NILP (image_spec_value (img->spec, QCflip, NULL)); | 3049 | flip = !NILP (image_spec_value (img->spec, QCflip, NULL)); |
| 3050 | 3050 | ||
| 3051 | # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU \ | 3051 | # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU \ |
| 3052 | || defined HAVE_ANDROID | 3052 | || defined HAVE_ANDROID || defined HAVE_NTGUI |
| 3053 | /* We want scale up operations to use a nearest neighbor filter to | 3053 | /* We want scale up operations to use a nearest neighbor filter to |
| 3054 | show real pixels instead of munging them, but scale down | 3054 | show real pixels instead of munging them, but scale down |
| 3055 | operations to use a blended filter, to avoid aliasing and the like. | 3055 | operations to use a blended filter, to avoid aliasing and the like. */ |
| 3056 | |||
| 3057 | TODO: implement for Windows. */ | ||
| 3058 | bool smoothing; | 3056 | bool smoothing; |
| 3059 | Lisp_Object s = image_spec_value (img->spec, QCtransform_smoothing, NULL); | 3057 | Lisp_Object s = image_spec_value (img->spec, QCtransform_smoothing, NULL); |
| 3060 | if (NILP (s)) | 3058 | if (NILP (s)) |
| @@ -3067,6 +3065,10 @@ image_set_transform (struct frame *f, struct image *img) | |||
| 3067 | img->use_bilinear_filtering = smoothing; | 3065 | img->use_bilinear_filtering = smoothing; |
| 3068 | #endif | 3066 | #endif |
| 3069 | 3067 | ||
| 3068 | #ifdef HAVE_NTGUI | ||
| 3069 | img->smoothing = smoothing; | ||
| 3070 | #endif | ||
| 3071 | |||
| 3070 | /* Perform scale transformation. */ | 3072 | /* Perform scale transformation. */ |
| 3071 | 3073 | ||
| 3072 | matrix3x3 matrix | 3074 | matrix3x3 matrix |
diff --git a/src/itree.c b/src/itree.c index 749e65c2eed..f35226ad226 100644 --- a/src/itree.c +++ b/src/itree.c | |||
| @@ -378,9 +378,9 @@ itree_inherit_offset (uintmax_t otick, struct itree_node *node) | |||
| 378 | node->right->offset += node->offset; | 378 | node->right->offset += node->offset; |
| 379 | node->offset = 0; | 379 | node->offset = 0; |
| 380 | } | 380 | } |
| 381 | /* The only thing that matters about `otick` is whether it's equal to | 381 | /* The only thing that matters about 'otick' is whether it's equal to |
| 382 | that of the tree. We could also "blindly" inherit from parent->otick, | 382 | that of the tree. We could also "blindly" inherit from parent->otick, |
| 383 | but we need to tree's `otick` anyway for when there's no parent. */ | 383 | but we need to tree's 'otick' anyway for when there's no parent. */ |
| 384 | if (node->parent == NULL || node->parent->otick == otick) | 384 | if (node->parent == NULL || node->parent->otick == otick) |
| 385 | node->otick = otick; | 385 | node->otick = otick; |
| 386 | } | 386 | } |
| @@ -683,7 +683,7 @@ itree_insert_node (struct itree_tree *tree, struct itree_node *node) | |||
| 683 | struct itree_node *parent = NULL; | 683 | struct itree_node *parent = NULL; |
| 684 | struct itree_node *child = tree->root; | 684 | struct itree_node *child = tree->root; |
| 685 | uintmax_t otick = tree->otick; | 685 | uintmax_t otick = tree->otick; |
| 686 | /* It's the responsibility of the caller to set `otick` on the node, | 686 | /* It's the responsibility of the caller to set 'otick' on the node, |
| 687 | to "confirm" that the begin/end fields are up to date. */ | 687 | to "confirm" that the begin/end fields are up to date. */ |
| 688 | eassert (node->otick == otick); | 688 | eassert (node->otick == otick); |
| 689 | 689 | ||
| @@ -913,8 +913,8 @@ itree_total_offset (struct itree_node *node) | |||
| 913 | link the tree root. | 913 | link the tree root. |
| 914 | 914 | ||
| 915 | Warning: DEST is left unmodified. SOURCE's child links are | 915 | Warning: DEST is left unmodified. SOURCE's child links are |
| 916 | unchanged. Caller is responsible for recalculation of `limit`. | 916 | unchanged. Caller is responsible for recalculation of 'limit'. |
| 917 | Requires both nodes to be using the same effective `offset`. */ | 917 | Requires both nodes to be using the same effective 'offset'. */ |
| 918 | static void | 918 | static void |
| 919 | itree_replace_child (struct itree_tree *tree, | 919 | itree_replace_child (struct itree_tree *tree, |
| 920 | struct itree_node *source, | 920 | struct itree_node *source, |
| @@ -939,8 +939,8 @@ itree_replace_child (struct itree_tree *tree, | |||
| 939 | parent, left and right in surrounding nodes to point to SOURCE. | 939 | parent, left and right in surrounding nodes to point to SOURCE. |
| 940 | 940 | ||
| 941 | Warning: DEST is left unmodified. Caller is responsible for | 941 | Warning: DEST is left unmodified. Caller is responsible for |
| 942 | recalculation of `limit`. Requires both nodes to be using the same | 942 | recalculation of 'limit'. Requires both nodes to be using the same |
| 943 | effective `offset`. */ | 943 | effective 'offset'. */ |
| 944 | static void | 944 | static void |
| 945 | itree_transplant (struct itree_tree *tree, | 945 | itree_transplant (struct itree_tree *tree, |
| 946 | struct itree_node *source, | 946 | struct itree_node *source, |
| @@ -964,38 +964,38 @@ itree_remove (struct itree_tree *tree, struct itree_node *node) | |||
| 964 | eassert (itree_contains (tree, node)); | 964 | eassert (itree_contains (tree, node)); |
| 965 | eassert (check_tree (tree, true)); /* FIXME: Too expensive. */ | 965 | eassert (check_tree (tree, true)); /* FIXME: Too expensive. */ |
| 966 | 966 | ||
| 967 | /* Find `splice`, the leaf node to splice out of the tree. When | 967 | /* Find 'splice', the leaf node to splice out of the tree. When |
| 968 | `node` has at most one child this is `node` itself. Otherwise, | 968 | 'node' has at most one child this is 'node' itself. Otherwise, |
| 969 | it is the in order successor of `node`. */ | 969 | it is the in order successor of 'node'. */ |
| 970 | itree_inherit_offset (tree->otick, node); | 970 | itree_inherit_offset (tree->otick, node); |
| 971 | struct itree_node *splice | 971 | struct itree_node *splice |
| 972 | = (node->left == NULL || node->right == NULL) | 972 | = (node->left == NULL || node->right == NULL) |
| 973 | ? node | 973 | ? node |
| 974 | : itree_subtree_min (tree->otick, node->right); | 974 | : itree_subtree_min (tree->otick, node->right); |
| 975 | 975 | ||
| 976 | /* Find `subtree`, the only child of `splice` (may be NULL). Note: | 976 | /* Find 'subtree', the only child of 'splice' (may be NULL). Note: |
| 977 | `subtree` will not be modified other than changing its parent to | 977 | 'subtree' will not be modified other than changing its parent to |
| 978 | `splice`. */ | 978 | 'splice'. */ |
| 979 | eassert (splice->left == NULL || splice->right == NULL); | 979 | eassert (splice->left == NULL || splice->right == NULL); |
| 980 | struct itree_node *subtree | 980 | struct itree_node *subtree |
| 981 | = (splice->left != NULL) ? splice->left : splice->right; | 981 | = (splice->left != NULL) ? splice->left : splice->right; |
| 982 | 982 | ||
| 983 | /* Save a pointer to the parent of where `subtree` will eventually | 983 | /* Save a pointer to the parent of where 'subtree' will eventually |
| 984 | be in `subtree_parent`. */ | 984 | be in 'subtree_parent'. */ |
| 985 | struct itree_node *subtree_parent | 985 | struct itree_node *subtree_parent |
| 986 | = (splice->parent != node) ? splice->parent : splice; | 986 | = (splice->parent != node) ? splice->parent : splice; |
| 987 | 987 | ||
| 988 | /* If `splice` is black removing it may violate Red-Black | 988 | /* If 'splice' is black removing it may violate Red-Black |
| 989 | invariants, so note this for later. */ | 989 | invariants, so note this for later. */ |
| 990 | 990 | ||
| 991 | /* Replace `splice` with `subtree` under subtree's parent. If | 991 | /* Replace 'splice' with 'subtree' under subtree's parent. If |
| 992 | `splice` is black, this creates a red-red violation, so remember | 992 | 'splice' is black, this creates a red-red violation, so remember |
| 993 | this now as the field can be overwritten when splice is | 993 | this now as the field can be overwritten when splice is |
| 994 | transplanted below. */ | 994 | transplanted below. */ |
| 995 | itree_replace_child (tree, subtree, splice); | 995 | itree_replace_child (tree, subtree, splice); |
| 996 | bool removed_black = !splice->red; | 996 | bool removed_black = !splice->red; |
| 997 | 997 | ||
| 998 | /* Replace `node` with `splice` in the tree and propagate limit | 998 | /* Replace 'node' with 'splice' in the tree and propagate limit |
| 999 | upwards, if necessary. Note: Limit propagation can stabilize at | 999 | upwards, if necessary. Note: Limit propagation can stabilize at |
| 1000 | any point, so we must call from bottom to top for every node that | 1000 | any point, so we must call from bottom to top for every node that |
| 1001 | has a new child. */ | 1001 | has a new child. */ |
| @@ -1054,8 +1054,8 @@ itree_insert_gap (struct itree_tree *tree, | |||
| 1054 | 1054 | ||
| 1055 | /* Nodes with front_advance starting at pos may mess up the tree | 1055 | /* Nodes with front_advance starting at pos may mess up the tree |
| 1056 | order, so we need to remove them first. This doesn't apply for | 1056 | order, so we need to remove them first. This doesn't apply for |
| 1057 | `before_markers` since in that case, all positions move identically | 1057 | 'before_markers' since in that case, all positions move identically |
| 1058 | regardless of `front_advance` or `rear_advance`. */ | 1058 | regardless of 'front_advance' or 'rear_advance'. */ |
| 1059 | struct itree_stack *saved = itree_stack_create (0); | 1059 | struct itree_stack *saved = itree_stack_create (0); |
| 1060 | struct itree_node *node = NULL; | 1060 | struct itree_node *node = NULL; |
| 1061 | if (!before_markers) | 1061 | if (!before_markers) |
| @@ -1208,7 +1208,7 @@ itree_node_intersects (const struct itree_node *node, | |||
| 1208 | 1208 | ||
| 1209 | Note that this should return all the nodes that we need to traverse | 1209 | Note that this should return all the nodes that we need to traverse |
| 1210 | in order to traverse the nodes selected by the current narrowing (i.e. | 1210 | in order to traverse the nodes selected by the current narrowing (i.e. |
| 1211 | `ITER->begin..ITER->end`) so it will also return some nodes which aren't in | 1211 | 'ITER->begin..ITER->end') so it will also return some nodes which aren't in |
| 1212 | that narrowing simply because they may have children which are. | 1212 | that narrowing simply because they may have children which are. |
| 1213 | 1213 | ||
| 1214 | The code itself is very unsatisfactory because the code of each one | 1214 | The code itself is very unsatisfactory because the code of each one |
| @@ -1221,8 +1221,8 @@ itree_iter_next_in_subtree (struct itree_node *node, | |||
| 1221 | struct itree_iterator *iter) | 1221 | struct itree_iterator *iter) |
| 1222 | { | 1222 | { |
| 1223 | /* FIXME: Like in the previous version of the iterator, we | 1223 | /* FIXME: Like in the previous version of the iterator, we |
| 1224 | prune based on `limit` only when moving to a left child, | 1224 | prune based on 'limit' only when moving to a left child, |
| 1225 | but `limit` can also get smaller when moving to a right child | 1225 | but 'limit' can also get smaller when moving to a right child |
| 1226 | It's actually fairly common, so maybe it would be worthwhile | 1226 | It's actually fairly common, so maybe it would be worthwhile |
| 1227 | to prune a bit more aggressively here. */ | 1227 | to prune a bit more aggressively here. */ |
| 1228 | struct itree_node *next; | 1228 | struct itree_node *next; |
| @@ -1387,10 +1387,10 @@ itree_iterator_start (struct itree_iterator *iter, | |||
| 1387 | iter->end = end; | 1387 | iter->end = end; |
| 1388 | iter->otick = tree->otick; | 1388 | iter->otick = tree->otick; |
| 1389 | iter->order = order; | 1389 | iter->order = order; |
| 1390 | /* Beware: the `node` field always holds "the next" node to consider. | 1390 | /* Beware: the 'node' field always holds "the next" node to consider. |
| 1391 | so it's always "one node ahead" of what the iterator loop sees. | 1391 | so it's always "one node ahead" of what the iterator loop sees. |
| 1392 | In most respects this makes no difference, but we depend on this | 1392 | In most respects this makes no difference, but we depend on this |
| 1393 | detail in `delete_all_overlays` where this allows us to modify | 1393 | detail in 'delete_all_overlays' where this allows us to modify |
| 1394 | the current node knowing that the iterator will not need it to | 1394 | the current node knowing that the iterator will not need it to |
| 1395 | find the next. */ | 1395 | find the next. */ |
| 1396 | iter->node = itree_iterator_first_node (tree, iter); | 1396 | iter->node = itree_iterator_first_node (tree, iter); |
diff --git a/src/itree.h b/src/itree.h index f54dbd7f07e..23e1105a05d 100644 --- a/src/itree.h +++ b/src/itree.h | |||
| @@ -41,7 +41,7 @@ INLINE_HEADER_BEGIN | |||
| 41 | struct itree_node | 41 | struct itree_node |
| 42 | { | 42 | { |
| 43 | /* The normal parent, left and right links found in binary trees. | 43 | /* The normal parent, left and right links found in binary trees. |
| 44 | See also `red`, below, which completes the Red-Black tree | 44 | See also 'red', below, which completes the Red-Black tree |
| 45 | representation. */ | 45 | representation. */ |
| 46 | struct itree_node *parent; | 46 | struct itree_node *parent; |
| 47 | struct itree_node *left; | 47 | struct itree_node *left; |
| @@ -147,13 +147,13 @@ struct itree_iterator | |||
| 147 | struct itree_node *node; | 147 | struct itree_node *node; |
| 148 | ptrdiff_t begin; | 148 | ptrdiff_t begin; |
| 149 | ptrdiff_t end; | 149 | ptrdiff_t end; |
| 150 | uintmax_t otick; /* A copy of the tree's `otick`. */ | 150 | uintmax_t otick; /* A copy of the tree's 'otick'. */ |
| 151 | enum itree_order order; | 151 | enum itree_order order; |
| 152 | }; | 152 | }; |
| 153 | 153 | ||
| 154 | /* Iterate over the intervals between BEG and END in the tree T. | 154 | /* Iterate over the intervals between BEG and END in the tree T. |
| 155 | N will hold successive nodes. ORDER can be one of : `ASCENDING`, | 155 | N will hold successive nodes. ORDER can be one of : 'ASCENDING', |
| 156 | `DESCENDING`, `POST_ORDER`, or `PRE_ORDER`. | 156 | 'DESCENDING', 'POST_ORDER', or 'PRE_ORDER'. |
| 157 | It should be used as: | 157 | It should be used as: |
| 158 | 158 | ||
| 159 | ITREE_FOREACH (n, t, beg, end, order) | 159 | ITREE_FOREACH (n, t, beg, end, order) |
| @@ -167,12 +167,12 @@ struct itree_iterator | |||
| 167 | - Don't modify the tree during the iteration. | 167 | - Don't modify the tree during the iteration. |
| 168 | */ | 168 | */ |
| 169 | #define ITREE_FOREACH(n, t, beg, end, order) \ | 169 | #define ITREE_FOREACH(n, t, beg, end, order) \ |
| 170 | /* FIXME: We'd want to declare `n` right here, but I can't figure out | 170 | /* FIXME: We'd want to declare 'n' right here, but I can't figure out |
| 171 | how to make that work here: the `for` syntax only allows a single | 171 | how to make that work here: the 'for' syntax only allows a single |
| 172 | clause for the var declarations where we need 2 different types. | 172 | clause for the var declarations where we need 2 different types. |
| 173 | We could use the `struct {foo x; bar y; } p;` trick to declare two | 173 | We could use the 'struct {foo x; bar y; } p;' trick to declare two |
| 174 | vars `p.x` and `p.y` of unrelated types, but then none of the names | 174 | vars 'p.x' and 'p.y' of unrelated types, but then none of the names |
| 175 | of the vars matches the `n` we receive :-(. */ \ | 175 | of the vars matches the 'n' we receive :-(. */ \ |
| 176 | if (!t) \ | 176 | if (!t) \ |
| 177 | { } \ | 177 | { } \ |
| 178 | else \ | 178 | else \ |
diff --git a/src/lread.c b/src/lread.c index 95c6891c205..ea0398196e3 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -3911,6 +3911,8 @@ read_stack_reset (intmax_t sp) | |||
| 3911 | 3911 | ||
| 3912 | #define READ_AND_BUFFER(c) \ | 3912 | #define READ_AND_BUFFER(c) \ |
| 3913 | c = READCHAR; \ | 3913 | c = READCHAR; \ |
| 3914 | if (c < 0) \ | ||
| 3915 | INVALID_SYNTAX_WITH_BUFFER (); \ | ||
| 3914 | if (multibyte) \ | 3916 | if (multibyte) \ |
| 3915 | p += CHAR_STRING (c, (unsigned char *) p); \ | 3917 | p += CHAR_STRING (c, (unsigned char *) p); \ |
| 3916 | else \ | 3918 | else \ |
diff --git a/src/nsterm.m b/src/nsterm.m index 7ad794b6bdb..ffc0693ab98 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -2961,24 +2961,28 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, | |||
| 2961 | NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d", | 2961 | NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d", |
| 2962 | p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh); | 2962 | p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh); |
| 2963 | 2963 | ||
| 2964 | /* Work out the rectangle we will need to clear. */ | 2964 | /* Clear screen unless overlay. */ |
| 2965 | clearRect = NSMakeRect (p->x, p->y, p->wd, p->h); | 2965 | if (!p->overlay_p) |
| 2966 | { | ||
| 2967 | /* Work out the rectangle we will need to clear. */ | ||
| 2968 | clearRect = NSMakeRect (p->x, p->y, p->wd, p->h); | ||
| 2966 | 2969 | ||
| 2967 | if (p->bx >= 0 && !p->overlay_p) | 2970 | if (p->bx >= 0) |
| 2968 | clearRect = NSUnionRect (clearRect, NSMakeRect (p->bx, p->by, p->nx, p->ny)); | 2971 | clearRect = NSUnionRect (clearRect, NSMakeRect (p->bx, p->by, p->nx, p->ny)); |
| 2969 | 2972 | ||
| 2970 | /* Handle partially visible rows. */ | 2973 | /* Handle partially visible rows. */ |
| 2971 | clearRect = NSIntersectionRect (clearRect, rowRect); | 2974 | clearRect = NSIntersectionRect (clearRect, rowRect); |
| 2972 | 2975 | ||
| 2973 | /* The visible portion of imageRect will always be contained within | 2976 | /* The visible portion of imageRect will always be contained |
| 2974 | clearRect. */ | 2977 | within clearRect. */ |
| 2975 | ns_focus (f, &clearRect, 1); | 2978 | ns_focus (f, &clearRect, 1); |
| 2976 | if (! NSIsEmptyRect (clearRect)) | 2979 | if (!NSIsEmptyRect (clearRect)) |
| 2977 | { | 2980 | { |
| 2978 | NSTRACE_RECT ("clearRect", clearRect); | 2981 | NSTRACE_RECT ("clearRect", clearRect); |
| 2979 | 2982 | ||
| 2980 | [[NSColor colorWithUnsignedLong:face->background] set]; | 2983 | [[NSColor colorWithUnsignedLong:face->background] set]; |
| 2981 | NSRectFill (clearRect); | 2984 | NSRectFill (clearRect); |
| 2985 | } | ||
| 2982 | } | 2986 | } |
| 2983 | 2987 | ||
| 2984 | NSBezierPath *bmp = [fringe_bmp objectForKey:[NSNumber numberWithInt:p->which]]; | 2988 | NSBezierPath *bmp = [fringe_bmp objectForKey:[NSNumber numberWithInt:p->which]]; |
| @@ -7895,6 +7899,9 @@ ns_in_echo_area (void) | |||
| 7895 | 7899 | ||
| 7896 | NSTRACE_RETURN_SIZE (frameSize); | 7900 | NSTRACE_RETURN_SIZE (frameSize); |
| 7897 | 7901 | ||
| 7902 | /* Trigger `move-frame-functions' (Bug#74074). */ | ||
| 7903 | [self windowDidMove:(NSNotification *)sender]; | ||
| 7904 | |||
| 7898 | return frameSize; | 7905 | return frameSize; |
| 7899 | } | 7906 | } |
| 7900 | 7907 | ||
diff --git a/src/pdumper.c b/src/pdumper.c index c888b659dde..c0b36b1ca44 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -4853,11 +4853,14 @@ struct dump_memory_map_heap_control_block | |||
| 4853 | static void | 4853 | static void |
| 4854 | dump_mm_heap_cb_release (struct dump_memory_map_heap_control_block *cb) | 4854 | dump_mm_heap_cb_release (struct dump_memory_map_heap_control_block *cb) |
| 4855 | { | 4855 | { |
| 4856 | eassert (cb->refcount > 0); | 4856 | if (cb) |
| 4857 | if (--cb->refcount == 0) | ||
| 4858 | { | 4857 | { |
| 4859 | free (cb->mem); | 4858 | eassert (cb->refcount > 0); |
| 4860 | free (cb); | 4859 | if (--cb->refcount == 0) |
| 4860 | { | ||
| 4861 | free (cb->mem); | ||
| 4862 | free (cb); | ||
| 4863 | } | ||
| 4861 | } | 4864 | } |
| 4862 | } | 4865 | } |
| 4863 | 4866 | ||
diff --git a/src/w32dwrite.c b/src/w32dwrite.c new file mode 100644 index 00000000000..29f9d5f1fed --- /dev/null +++ b/src/w32dwrite.c | |||
| @@ -0,0 +1,1110 @@ | |||
| 1 | /* Support for using DirectWrite on MS-Windows to draw text. This | ||
| 2 | allows for color fonts. | ||
| 3 | Copyright (C) 2024 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | /* This requires the HarfBuzz font backend to be available. | ||
| 21 | |||
| 22 | It works by modifying the HarfBuzz backend to use DirectWrite at | ||
| 23 | some points, if it is available: | ||
| 24 | |||
| 25 | - When encoding characters: w32hb_encode_char | ||
| 26 | - When measuring text: w32font_text_extents | ||
| 27 | - When drawing text: w32font_draw | ||
| 28 | |||
| 29 | DirectWrite is setup by calling w32_initialize_direct_write. From | ||
| 30 | that point, the function w32_use_direct_write will return true if | ||
| 31 | DirectWrite is to be used. | ||
| 32 | |||
| 33 | DirectWrite is available since Windows 7, but we don't activate it on | ||
| 34 | versions before 8.1, because color fonts are only available since that. */ | ||
| 35 | |||
| 36 | #include <config.h> | ||
| 37 | #include <math.h> | ||
| 38 | #include <windows.h> | ||
| 39 | |||
| 40 | #if !defined MINGW_W64 && !defined CYGWIN | ||
| 41 | # define INITGUID | ||
| 42 | #endif | ||
| 43 | #include <initguid.h> | ||
| 44 | #include <ole2.h> | ||
| 45 | #include <unknwn.h> | ||
| 46 | |||
| 47 | #include "frame.h" | ||
| 48 | #include "w32font.h" | ||
| 49 | #include "w32common.h" | ||
| 50 | #include "w32term.h" | ||
| 51 | |||
| 52 | #ifndef MINGW_W64 | ||
| 53 | |||
| 54 | /* The following definitions would be included from dwrite_3.h, but it | ||
| 55 | is not available when building with mingw.org's MinGW. Methods that | ||
| 56 | we don't use are declared with the EMACS_DWRITE_UNUSED macro, to | ||
| 57 | avoid bringing in more types that would need to be declared. */ | ||
| 58 | |||
| 59 | #define EMACS_DWRITE_UNUSED(name) void (STDMETHODCALLTYPE *name) (void) | ||
| 60 | |||
| 61 | #define DWRITE_E_NOCOLOR _HRESULT_TYPEDEF_(0x8898500CL) | ||
| 62 | |||
| 63 | typedef enum DWRITE_PIXEL_GEOMETRY { | ||
| 64 | DWRITE_PIXEL_GEOMETRY_FLAT = 0, | ||
| 65 | DWRITE_PIXEL_GEOMETRY_RGB = 1, | ||
| 66 | DWRITE_PIXEL_GEOMETRY_BGR = 2 | ||
| 67 | } DWRITE_PIXEL_GEOMETRY; | ||
| 68 | |||
| 69 | typedef enum DWRITE_RENDERING_MODE { | ||
| 70 | DWRITE_RENDERING_MODE_DEFAULT = 0, | ||
| 71 | DWRITE_RENDERING_MODE_ALIASED = 1, | ||
| 72 | DWRITE_RENDERING_MODE_GDI_CLASSIC = 2, | ||
| 73 | DWRITE_RENDERING_MODE_GDI_NATURAL = 3, | ||
| 74 | DWRITE_RENDERING_MODE_NATURAL = 4, | ||
| 75 | DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC = 5, | ||
| 76 | DWRITE_RENDERING_MODE_OUTLINE = 6 | ||
| 77 | } DWRITE_RENDERING_MODE; | ||
| 78 | |||
| 79 | typedef enum DWRITE_MEASURING_MODE { | ||
| 80 | DWRITE_MEASURING_MODE_NATURAL = 0, | ||
| 81 | DWRITE_MEASURING_MODE_GDI_CLASSIC = 1, | ||
| 82 | DWRITE_MEASURING_MODE_GDI_NATURAL = 2 | ||
| 83 | } DWRITE_MEASURING_MODE; | ||
| 84 | |||
| 85 | typedef enum DWRITE_TEXT_ANTIALIAS_MODE { | ||
| 86 | DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE = 0, | ||
| 87 | DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE = 1 | ||
| 88 | } DWRITE_TEXT_ANTIALIAS_MODE; | ||
| 89 | |||
| 90 | typedef enum DWRITE_FACTORY_TYPE { | ||
| 91 | DWRITE_FACTORY_TYPE_SHARED = 0, | ||
| 92 | DWRITE_FACTORY_TYPE_ISOLATED = 1 | ||
| 93 | } DWRITE_FACTORY_TYPE; | ||
| 94 | |||
| 95 | typedef struct DWRITE_FONT_METRICS { | ||
| 96 | UINT16 designUnitsPerEm; | ||
| 97 | UINT16 ascent; | ||
| 98 | UINT16 descent; | ||
| 99 | INT16 lineGap; | ||
| 100 | UINT16 capHeight; | ||
| 101 | UINT16 xHeight; | ||
| 102 | INT16 underlinePosition; | ||
| 103 | UINT16 underlineThickness; | ||
| 104 | INT16 strikethroughPosition; | ||
| 105 | UINT16 strikethroughThickness; | ||
| 106 | } DWRITE_FONT_METRICS; | ||
| 107 | |||
| 108 | typedef struct DWRITE_GLYPH_METRICS { | ||
| 109 | INT32 leftSideBearing; | ||
| 110 | UINT32 advanceWidth; | ||
| 111 | INT32 rightSideBearing; | ||
| 112 | INT32 topSideBearing; | ||
| 113 | UINT32 advanceHeight; | ||
| 114 | INT32 bottomSideBearing; | ||
| 115 | INT32 verticalOriginY; | ||
| 116 | } DWRITE_GLYPH_METRICS; | ||
| 117 | |||
| 118 | typedef interface IDWriteRenderingParams IDWriteRenderingParams; | ||
| 119 | typedef interface IDWriteFont IDWriteFont; | ||
| 120 | typedef interface IDWriteGdiInterop IDWriteGdiInterop; | ||
| 121 | typedef interface IDWriteFactory IDWriteFactory; | ||
| 122 | typedef interface IDWriteFactory2 IDWriteFactory2; | ||
| 123 | typedef interface IDWriteFontFace IDWriteFontFace; | ||
| 124 | typedef interface IDWriteBitmapRenderTarget IDWriteBitmapRenderTarget; | ||
| 125 | typedef interface IDWriteBitmapRenderTarget1 IDWriteBitmapRenderTarget1; | ||
| 126 | typedef interface IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator; | ||
| 127 | |||
| 128 | DEFINE_GUID (IID_IDWriteBitmapRenderTarget1, 0x791e8298, 0x3ef3, 0x4230, 0x98, | ||
| 129 | 0x80, 0xc9, 0xbd, 0xec, 0xc4, 0x20, 0x64); | ||
| 130 | DEFINE_GUID (IID_IDWriteFactory2, 0x0439fc60, 0xca44, 0x4994, 0x8d, 0xee, | ||
| 131 | 0x3a, 0x9a, 0xf7, 0xb7, 0x32, 0xec); | ||
| 132 | DEFINE_GUID (IID_IDWriteFactory, 0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, | ||
| 133 | 0xdc, 0x7d, 0x93, 0xdb, 0x48); | ||
| 134 | |||
| 135 | typedef struct DWRITE_GLYPH_OFFSET { | ||
| 136 | FLOAT advanceOffset; | ||
| 137 | FLOAT ascenderOffset; | ||
| 138 | } DWRITE_GLYPH_OFFSET; | ||
| 139 | |||
| 140 | typedef struct DWRITE_GLYPH_RUN { | ||
| 141 | IDWriteFontFace *fontFace; | ||
| 142 | FLOAT fontEmSize; | ||
| 143 | UINT32 glyphCount; | ||
| 144 | const UINT16 *glyphIndices; | ||
| 145 | const FLOAT *glyphAdvances; | ||
| 146 | const DWRITE_GLYPH_OFFSET *glyphOffsets; | ||
| 147 | WINBOOL isSideways; | ||
| 148 | UINT32 bidiLevel; | ||
| 149 | } DWRITE_GLYPH_RUN; | ||
| 150 | |||
| 151 | typedef struct _D3DCOLORVALUE { | ||
| 152 | float r; | ||
| 153 | float g; | ||
| 154 | float b; | ||
| 155 | float a; | ||
| 156 | } D3DCOLORVALUE; | ||
| 157 | |||
| 158 | typedef D3DCOLORVALUE DWRITE_COLOR_F; | ||
| 159 | |||
| 160 | typedef struct DWRITE_COLOR_GLYPH_RUN { | ||
| 161 | DWRITE_GLYPH_RUN glyphRun; | ||
| 162 | void *glyphRunDescription; | ||
| 163 | FLOAT baselineOriginX; | ||
| 164 | FLOAT baselineOriginY; | ||
| 165 | DWRITE_COLOR_F runColor; | ||
| 166 | UINT16 paletteIndex; | ||
| 167 | } DWRITE_COLOR_GLYPH_RUN; | ||
| 168 | |||
| 169 | typedef struct IDWriteFontFaceVtbl { | ||
| 170 | BEGIN_INTERFACE | ||
| 171 | |||
| 172 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 173 | (IDWriteFontFace *This, REFIID riid, void **ppvObject); | ||
| 174 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteFontFace *This); | ||
| 175 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteFontFace *This); | ||
| 176 | |||
| 177 | EMACS_DWRITE_UNUSED (GetType); | ||
| 178 | EMACS_DWRITE_UNUSED (GetFiles); | ||
| 179 | EMACS_DWRITE_UNUSED (GetIndex); | ||
| 180 | EMACS_DWRITE_UNUSED (GetSimulations); | ||
| 181 | EMACS_DWRITE_UNUSED (IsSymbolFont); | ||
| 182 | |||
| 183 | void (STDMETHODCALLTYPE *GetMetrics) | ||
| 184 | (IDWriteFontFace *This, DWRITE_FONT_METRICS *metrics); | ||
| 185 | |||
| 186 | EMACS_DWRITE_UNUSED (GetGlyphCount); | ||
| 187 | EMACS_DWRITE_UNUSED (GetDesignGlyphMetrics); | ||
| 188 | |||
| 189 | HRESULT (STDMETHODCALLTYPE *GetGlyphIndices) | ||
| 190 | (IDWriteFontFace *This, const UINT32 *codepoints, UINT32 count, | ||
| 191 | UINT16 *glyph_indices); | ||
| 192 | |||
| 193 | EMACS_DWRITE_UNUSED (TryGetFontTable); | ||
| 194 | EMACS_DWRITE_UNUSED (ReleaseFontTable); | ||
| 195 | EMACS_DWRITE_UNUSED (GetGlyphRunOutline); | ||
| 196 | EMACS_DWRITE_UNUSED (GetRecommendedRenderingMode); | ||
| 197 | EMACS_DWRITE_UNUSED (GetGdiCompatibleMetrics); | ||
| 198 | |||
| 199 | HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleGlyphMetrics) | ||
| 200 | (IDWriteFontFace *This, | ||
| 201 | FLOAT emSize, | ||
| 202 | FLOAT pixels_per_dip, | ||
| 203 | void *transform, | ||
| 204 | WINBOOL use_gdi_natural, | ||
| 205 | const UINT16 *glyph_indices, | ||
| 206 | UINT32 glyph_count, | ||
| 207 | DWRITE_GLYPH_METRICS *metrics, | ||
| 208 | WINBOOL is_sideways); | ||
| 209 | END_INTERFACE | ||
| 210 | } IDWriteFontFaceVtbl; | ||
| 211 | |||
| 212 | interface IDWriteFontFace { | ||
| 213 | CONST_VTBL IDWriteFontFaceVtbl *lpVtbl; | ||
| 214 | }; | ||
| 215 | |||
| 216 | typedef struct IDWriteRenderingParamsVtbl { | ||
| 217 | BEGIN_INTERFACE | ||
| 218 | |||
| 219 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 220 | (IDWriteRenderingParams *This, REFIID riid, void **ppvObject); | ||
| 221 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteRenderingParams *This); | ||
| 222 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteRenderingParams *This); | ||
| 223 | |||
| 224 | FLOAT (STDMETHODCALLTYPE *GetGamma) | ||
| 225 | (IDWriteRenderingParams *This); | ||
| 226 | FLOAT (STDMETHODCALLTYPE *GetEnhancedContrast) | ||
| 227 | (IDWriteRenderingParams *This); | ||
| 228 | FLOAT (STDMETHODCALLTYPE *GetClearTypeLevel) | ||
| 229 | (IDWriteRenderingParams *This); | ||
| 230 | int (STDMETHODCALLTYPE *GetPixelGeometry) | ||
| 231 | (IDWriteRenderingParams *This); | ||
| 232 | END_INTERFACE | ||
| 233 | } IDWriteRenderingParamsVtbl; | ||
| 234 | |||
| 235 | interface IDWriteRenderingParams { | ||
| 236 | CONST_VTBL IDWriteRenderingParamsVtbl *lpVtbl; | ||
| 237 | }; | ||
| 238 | |||
| 239 | typedef struct IDWriteFontVtbl { | ||
| 240 | BEGIN_INTERFACE | ||
| 241 | |||
| 242 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 243 | (IDWriteFont *This, REFIID riid, void **ppvObject); | ||
| 244 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteFont *This); | ||
| 245 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteFont *This); | ||
| 246 | |||
| 247 | EMACS_DWRITE_UNUSED (GetFontFamily); | ||
| 248 | EMACS_DWRITE_UNUSED (GetWeight); | ||
| 249 | EMACS_DWRITE_UNUSED (GetStretch); | ||
| 250 | EMACS_DWRITE_UNUSED (GetStyle); | ||
| 251 | EMACS_DWRITE_UNUSED (IsSymbolFont); | ||
| 252 | EMACS_DWRITE_UNUSED (GetFaceNames); | ||
| 253 | EMACS_DWRITE_UNUSED (GetInformationalStrings); | ||
| 254 | EMACS_DWRITE_UNUSED (GetSimulations); | ||
| 255 | |||
| 256 | void (STDMETHODCALLTYPE *GetMetrics) | ||
| 257 | (IDWriteFont *This, DWRITE_FONT_METRICS *metrics); | ||
| 258 | |||
| 259 | EMACS_DWRITE_UNUSED (HasCharacter); | ||
| 260 | |||
| 261 | HRESULT (STDMETHODCALLTYPE *CreateFontFace) | ||
| 262 | (IDWriteFont *This, IDWriteFontFace **face); | ||
| 263 | |||
| 264 | END_INTERFACE | ||
| 265 | } IDWriteFontVtbl; | ||
| 266 | |||
| 267 | interface IDWriteFont { | ||
| 268 | CONST_VTBL IDWriteFontVtbl *lpVtbl; | ||
| 269 | }; | ||
| 270 | |||
| 271 | typedef struct IDWriteBitmapRenderTargetVtbl { | ||
| 272 | BEGIN_INTERFACE | ||
| 273 | |||
| 274 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 275 | (IDWriteBitmapRenderTarget *This, REFIID riid, void **ppvObject); | ||
| 276 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteBitmapRenderTarget *This); | ||
| 277 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteBitmapRenderTarget *This); | ||
| 278 | |||
| 279 | HRESULT (STDMETHODCALLTYPE *DrawGlyphRun) | ||
| 280 | (IDWriteBitmapRenderTarget *This, | ||
| 281 | FLOAT baselineOriginX, | ||
| 282 | FLOAT baselineOriginY, | ||
| 283 | DWRITE_MEASURING_MODE measuring_mode, | ||
| 284 | const DWRITE_GLYPH_RUN *glyph_run, | ||
| 285 | IDWriteRenderingParams *params, | ||
| 286 | COLORREF textColor, | ||
| 287 | RECT *blackbox_rect); | ||
| 288 | |||
| 289 | HDC (STDMETHODCALLTYPE *GetMemoryDC) (IDWriteBitmapRenderTarget *This); | ||
| 290 | |||
| 291 | EMACS_DWRITE_UNUSED (GetPixelsPerDip); | ||
| 292 | |||
| 293 | HRESULT (STDMETHODCALLTYPE *SetPixelsPerDip) | ||
| 294 | (IDWriteBitmapRenderTarget *This, FLOAT pixels_per_dip); | ||
| 295 | |||
| 296 | EMACS_DWRITE_UNUSED (GetCurrentTransform); | ||
| 297 | EMACS_DWRITE_UNUSED (SetCurrentTransform); | ||
| 298 | EMACS_DWRITE_UNUSED (GetSize); | ||
| 299 | EMACS_DWRITE_UNUSED (Resize); | ||
| 300 | END_INTERFACE | ||
| 301 | } IDWriteBitmapRenderTargetVtbl; | ||
| 302 | |||
| 303 | interface IDWriteBitmapRenderTarget { | ||
| 304 | CONST_VTBL IDWriteBitmapRenderTargetVtbl *lpVtbl; | ||
| 305 | }; | ||
| 306 | |||
| 307 | typedef struct IDWriteBitmapRenderTarget1Vtbl { | ||
| 308 | BEGIN_INTERFACE | ||
| 309 | |||
| 310 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 311 | (IDWriteBitmapRenderTarget1 *This, REFIID riid, void **ppvObject); | ||
| 312 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteBitmapRenderTarget1 *This); | ||
| 313 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteBitmapRenderTarget1 *This); | ||
| 314 | |||
| 315 | EMACS_DWRITE_UNUSED (DrawGlyphRun); | ||
| 316 | EMACS_DWRITE_UNUSED (GetMemoryDC); | ||
| 317 | EMACS_DWRITE_UNUSED (GetPixelsPerDip); | ||
| 318 | EMACS_DWRITE_UNUSED (SetPixelsPerDip); | ||
| 319 | EMACS_DWRITE_UNUSED (GetCurrentTransform); | ||
| 320 | EMACS_DWRITE_UNUSED (SetCurrentTransform); | ||
| 321 | EMACS_DWRITE_UNUSED (GetSize); | ||
| 322 | EMACS_DWRITE_UNUSED (Resize); | ||
| 323 | EMACS_DWRITE_UNUSED (GetTextAntialiasMode); | ||
| 324 | |||
| 325 | HRESULT (STDMETHODCALLTYPE *SetTextAntialiasMode) | ||
| 326 | (IDWriteBitmapRenderTarget1 *This, DWRITE_TEXT_ANTIALIAS_MODE mode); | ||
| 327 | |||
| 328 | END_INTERFACE | ||
| 329 | } IDWriteBitmapRenderTarget1Vtbl; | ||
| 330 | |||
| 331 | interface IDWriteBitmapRenderTarget1 { | ||
| 332 | CONST_VTBL IDWriteBitmapRenderTarget1Vtbl *lpVtbl; | ||
| 333 | }; | ||
| 334 | |||
| 335 | typedef struct IDWriteGdiInteropVtbl { | ||
| 336 | BEGIN_INTERFACE | ||
| 337 | |||
| 338 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 339 | (IDWriteGdiInterop *This, REFIID riid, void **ppvObject); | ||
| 340 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteGdiInterop *This); | ||
| 341 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteGdiInterop *This); | ||
| 342 | |||
| 343 | HRESULT (STDMETHODCALLTYPE *CreateFontFromLOGFONT) | ||
| 344 | (IDWriteGdiInterop *This, const LOGFONTW *logfont, | ||
| 345 | IDWriteFont **font); | ||
| 346 | |||
| 347 | EMACS_DWRITE_UNUSED (ConvertFontToLOGFONT); | ||
| 348 | EMACS_DWRITE_UNUSED (ConvertFontFaceToLOGFONT); | ||
| 349 | EMACS_DWRITE_UNUSED (CreateFontFaceFromHdc); | ||
| 350 | |||
| 351 | HRESULT (STDMETHODCALLTYPE *CreateBitmapRenderTarget) | ||
| 352 | (IDWriteGdiInterop *This, HDC hdc, UINT32 width, UINT32 height, | ||
| 353 | IDWriteBitmapRenderTarget **target); | ||
| 354 | END_INTERFACE | ||
| 355 | } IDWriteGdiInteropVtbl; | ||
| 356 | |||
| 357 | interface IDWriteGdiInterop { | ||
| 358 | CONST_VTBL IDWriteGdiInteropVtbl *lpVtbl; | ||
| 359 | }; | ||
| 360 | |||
| 361 | typedef struct IDWriteFactoryVtbl { | ||
| 362 | BEGIN_INTERFACE | ||
| 363 | |||
| 364 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 365 | (IDWriteFactory *This, REFIID riid, void **ppvObject); | ||
| 366 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteFactory *This); | ||
| 367 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteFactory *This); | ||
| 368 | |||
| 369 | EMACS_DWRITE_UNUSED (GetSystemFontCollection); | ||
| 370 | EMACS_DWRITE_UNUSED (CreateCustomFontCollection); | ||
| 371 | EMACS_DWRITE_UNUSED (RegisterFontCollectionLoader); | ||
| 372 | EMACS_DWRITE_UNUSED (UnregisterFontCollectionLoader); | ||
| 373 | EMACS_DWRITE_UNUSED (CreateFontFileReference); | ||
| 374 | EMACS_DWRITE_UNUSED (CreateCustomFontFileReference); | ||
| 375 | EMACS_DWRITE_UNUSED (CreateFontFace); | ||
| 376 | HRESULT (STDMETHODCALLTYPE *CreateRenderingParams) | ||
| 377 | (IDWriteFactory *This, IDWriteRenderingParams **params); | ||
| 378 | EMACS_DWRITE_UNUSED (CreateMonitorRenderingParams); | ||
| 379 | HRESULT (STDMETHODCALLTYPE *CreateCustomRenderingParams) | ||
| 380 | (IDWriteFactory *This, FLOAT gamma, FLOAT enhancedContrast, | ||
| 381 | FLOAT cleartype_level, DWRITE_PIXEL_GEOMETRY geometry, | ||
| 382 | DWRITE_RENDERING_MODE mode, IDWriteRenderingParams **params); | ||
| 383 | EMACS_DWRITE_UNUSED (RegisterFontFileLoader); | ||
| 384 | EMACS_DWRITE_UNUSED (UnregisterFontFileLoader); | ||
| 385 | EMACS_DWRITE_UNUSED (CreateTextFormat); | ||
| 386 | EMACS_DWRITE_UNUSED (CreateTypography); | ||
| 387 | HRESULT (STDMETHODCALLTYPE *GetGdiInterop) | ||
| 388 | (IDWriteFactory *This, IDWriteGdiInterop **gdi_interop); | ||
| 389 | EMACS_DWRITE_UNUSED (CreateTextLayout); | ||
| 390 | EMACS_DWRITE_UNUSED (CreateGdiCompatibleTextLayout); | ||
| 391 | EMACS_DWRITE_UNUSED (CreateEllipsisTrimmingSign); | ||
| 392 | EMACS_DWRITE_UNUSED (CreateTextAnalyzer); | ||
| 393 | EMACS_DWRITE_UNUSED (CreateNumberSubstitution); | ||
| 394 | EMACS_DWRITE_UNUSED (CreateGlyphRunAnalysis); | ||
| 395 | END_INTERFACE | ||
| 396 | } IDWriteFactoryVtbl; | ||
| 397 | |||
| 398 | interface IDWriteFactory { CONST_VTBL IDWriteFactoryVtbl *lpVtbl; }; | ||
| 399 | |||
| 400 | typedef struct IDWriteColorGlyphRunEnumeratorVtbl { | ||
| 401 | BEGIN_INTERFACE | ||
| 402 | |||
| 403 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 404 | (IDWriteColorGlyphRunEnumerator *This, REFIID riid, void **ppvObject); | ||
| 405 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteColorGlyphRunEnumerator *This); | ||
| 406 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteColorGlyphRunEnumerator *This); | ||
| 407 | |||
| 408 | HRESULT (STDMETHODCALLTYPE *MoveNext) (IDWriteColorGlyphRunEnumerator *This, | ||
| 409 | WINBOOL *hasRun); | ||
| 410 | |||
| 411 | HRESULT (STDMETHODCALLTYPE *GetCurrentRun) (IDWriteColorGlyphRunEnumerator *This, | ||
| 412 | const DWRITE_COLOR_GLYPH_RUN **run); | ||
| 413 | |||
| 414 | END_INTERFACE | ||
| 415 | } IDWriteColorGlyphRunEnumeratorVtbl; | ||
| 416 | |||
| 417 | interface IDWriteColorGlyphRunEnumerator { | ||
| 418 | CONST_VTBL IDWriteColorGlyphRunEnumeratorVtbl *lpVtbl; | ||
| 419 | }; | ||
| 420 | |||
| 421 | typedef struct IDWriteFactory2Vtbl { | ||
| 422 | BEGIN_INTERFACE | ||
| 423 | HRESULT (STDMETHODCALLTYPE *QueryInterface) | ||
| 424 | (IDWriteFactory2 *This, REFIID riid, void **ppvObject); | ||
| 425 | ULONG (STDMETHODCALLTYPE *AddRef) (IDWriteFactory2 *This); | ||
| 426 | ULONG (STDMETHODCALLTYPE *Release) (IDWriteFactory2 *This); | ||
| 427 | EMACS_DWRITE_UNUSED (GetSystemFontCollection); | ||
| 428 | EMACS_DWRITE_UNUSED (CreateCustomFontCollection); | ||
| 429 | EMACS_DWRITE_UNUSED (RegisterFontCollectionLoader); | ||
| 430 | EMACS_DWRITE_UNUSED (UnregisterFontCollectionLoader); | ||
| 431 | EMACS_DWRITE_UNUSED (CreateFontFileReference); | ||
| 432 | EMACS_DWRITE_UNUSED (CreateCustomFontFileReference); | ||
| 433 | EMACS_DWRITE_UNUSED (CreateFontFace); | ||
| 434 | EMACS_DWRITE_UNUSED (CreateRenderingParams); | ||
| 435 | EMACS_DWRITE_UNUSED (CreateMonitorRenderingParams); | ||
| 436 | EMACS_DWRITE_UNUSED (CreateCustomRenderingParams); | ||
| 437 | EMACS_DWRITE_UNUSED (RegisterFontFileLoader); | ||
| 438 | EMACS_DWRITE_UNUSED (UnregisterFontFileLoader); | ||
| 439 | EMACS_DWRITE_UNUSED (CreateTextFormat); | ||
| 440 | EMACS_DWRITE_UNUSED (CreateTypography); | ||
| 441 | EMACS_DWRITE_UNUSED (GetGdiInterop); | ||
| 442 | EMACS_DWRITE_UNUSED (CreateTextLayout); | ||
| 443 | EMACS_DWRITE_UNUSED (CreateGdiCompatibleTextLayout); | ||
| 444 | EMACS_DWRITE_UNUSED (CreateEllipsisTrimmingSign); | ||
| 445 | EMACS_DWRITE_UNUSED (CreateTextAnalyzer); | ||
| 446 | EMACS_DWRITE_UNUSED (CreateNumberSubstitution); | ||
| 447 | EMACS_DWRITE_UNUSED (CreateGlyphRunAnalysis); | ||
| 448 | |||
| 449 | EMACS_DWRITE_UNUSED (GetEudcFontCollection); | ||
| 450 | EMACS_DWRITE_UNUSED (IDWriteFactory1_CreateCustomRenderingParams); | ||
| 451 | |||
| 452 | EMACS_DWRITE_UNUSED (GetSystemFontFallback); | ||
| 453 | EMACS_DWRITE_UNUSED (CreateFontFallbackBuilder); | ||
| 454 | HRESULT (STDMETHODCALLTYPE *TranslateColorGlyphRun) | ||
| 455 | (IDWriteFactory2 *This, | ||
| 456 | FLOAT originX, | ||
| 457 | FLOAT originY, | ||
| 458 | const DWRITE_GLYPH_RUN *run, | ||
| 459 | void *rundescr, | ||
| 460 | DWRITE_MEASURING_MODE mode, | ||
| 461 | void *transform, | ||
| 462 | UINT32 palette_index, | ||
| 463 | IDWriteColorGlyphRunEnumerator **colorlayers); | ||
| 464 | |||
| 465 | EMACS_DWRITE_UNUSED (IDWriteFactory2_CreateCustomRenderingParams); | ||
| 466 | EMACS_DWRITE_UNUSED (IDWriteFactory2_CreateGlyphRunAnalysis); | ||
| 467 | END_INTERFACE | ||
| 468 | } IDWriteFactory2Vtbl; | ||
| 469 | |||
| 470 | interface IDWriteFactory2 { | ||
| 471 | CONST_VTBL IDWriteFactory2Vtbl *lpVtbl; | ||
| 472 | }; | ||
| 473 | #else /* MINGW_W64 */ | ||
| 474 | # include <dwrite_3.h> | ||
| 475 | #endif | ||
| 476 | |||
| 477 | /* User configurable variables. If they are smaller than 0, use | ||
| 478 | DirectWrite's defaults, or our defaults. To set them, the user calls | ||
| 479 | 'w32-dwrite-reinit' */ | ||
| 480 | static float config_enhanced_contrast = -1.0f; | ||
| 481 | static float config_clear_type_level = -1.0f; | ||
| 482 | static float config_gamma = -1.0f; | ||
| 483 | |||
| 484 | /* Values to use for DirectWrite rendering. */ | ||
| 485 | #define MEASURING_MODE DWRITE_MEASURING_MODE_NATURAL | ||
| 486 | #define RENDERING_MODE DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC | ||
| 487 | #define ANTIALIAS_MODE DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE | ||
| 488 | |||
| 489 | static void | ||
| 490 | release_com (IUnknown **i) | ||
| 491 | { | ||
| 492 | if ( *i ) | ||
| 493 | { | ||
| 494 | ((IUnknown *) (*i))->lpVtbl->Release (*i); | ||
| 495 | *i = NULL; | ||
| 496 | } | ||
| 497 | } | ||
| 498 | |||
| 499 | #define RELEASE_COM(i) release_com ((IUnknown **) &i) | ||
| 500 | |||
| 501 | /* Global variables for DirectWrite. */ | ||
| 502 | static bool direct_write_available = false; | ||
| 503 | static IDWriteFactory *dwrite_factory = NULL; | ||
| 504 | static IDWriteFactory2 *dwrite_factory2 = NULL; | ||
| 505 | static IDWriteGdiInterop *gdi_interop = NULL; | ||
| 506 | static IDWriteRenderingParams *rendering_params = NULL; | ||
| 507 | |||
| 508 | static bool | ||
| 509 | verify_hr (HRESULT hr, const char *msg) | ||
| 510 | { | ||
| 511 | if (FAILED (hr)) | ||
| 512 | { | ||
| 513 | DebPrint (("DirectWrite HRESULT failed: (%d) %s\n", hr, msg)); | ||
| 514 | eassert (SUCCEEDED (hr)); | ||
| 515 | return false; | ||
| 516 | } | ||
| 517 | return true; | ||
| 518 | } | ||
| 519 | |||
| 520 | /* Gets a IDWriteFontFace from a struct font (its HFONT). Returns the | ||
| 521 | font size in points. It may fail to get a DirectWrite font, and face | ||
| 522 | will be NULL on return. This happens for some fonts like Courier. | ||
| 523 | |||
| 524 | Never call Release on the result, as it is cached for reuse on the | ||
| 525 | struct font. */ | ||
| 526 | static float | ||
| 527 | get_font_face (struct font *infont, IDWriteFontFace **face) | ||
| 528 | { | ||
| 529 | HRESULT hr; | ||
| 530 | LOGFONTW logfont; | ||
| 531 | IDWriteFont *font; | ||
| 532 | |||
| 533 | struct uniscribe_font_info *uniscribe_font | ||
| 534 | = (struct uniscribe_font_info *) infont; | ||
| 535 | |||
| 536 | /* Check the cache. */ | ||
| 537 | *face = uniscribe_font->dwrite_cache; | ||
| 538 | if (*face) | ||
| 539 | return uniscribe_font->dwrite_font_size; | ||
| 540 | |||
| 541 | GetObjectW (FONT_HANDLE (infont), sizeof (LOGFONTW), &logfont); | ||
| 542 | |||
| 543 | hr = gdi_interop->lpVtbl->CreateFontFromLOGFONT (gdi_interop, | ||
| 544 | (const LOGFONTW *) &logfont, | ||
| 545 | &font); | ||
| 546 | |||
| 547 | if (!verify_hr (hr, "Failed to CreateFontFromLOGFONT")) | ||
| 548 | { | ||
| 549 | uniscribe_font->dwrite_skip_font = true; | ||
| 550 | *face = NULL; | ||
| 551 | return 0.0; | ||
| 552 | } | ||
| 553 | |||
| 554 | hr = font->lpVtbl->CreateFontFace (font, face); | ||
| 555 | RELEASE_COM (font); | ||
| 556 | if (!verify_hr (hr, "Failed to create DWriteFontFace")) | ||
| 557 | { | ||
| 558 | uniscribe_font->dwrite_skip_font = true; | ||
| 559 | *face = NULL; | ||
| 560 | return 0.0; | ||
| 561 | } | ||
| 562 | |||
| 563 | /* Cache this FontFace. */ | ||
| 564 | uniscribe_font->dwrite_font_size = eabs (logfont.lfHeight); | ||
| 565 | uniscribe_font->dwrite_cache = *face; | ||
| 566 | |||
| 567 | return eabs (logfont.lfHeight); | ||
| 568 | } | ||
| 569 | |||
| 570 | void | ||
| 571 | w32_dwrite_free_cached_face (void *cache) | ||
| 572 | { | ||
| 573 | if (cache) | ||
| 574 | RELEASE_COM (cache); | ||
| 575 | } | ||
| 576 | |||
| 577 | static float | ||
| 578 | convert_metrics_sz (int sz, float font_size, int units_per_em) | ||
| 579 | { | ||
| 580 | return (float) sz * font_size / units_per_em; | ||
| 581 | } | ||
| 582 | |||
| 583 | /* Does not fill in the ascent and descent fields of metrics. */ | ||
| 584 | static bool | ||
| 585 | text_extents_internal (IDWriteFontFace *dwrite_font_face, | ||
| 586 | float font_size, const unsigned *code, | ||
| 587 | int nglyphs, struct font_metrics *metrics) | ||
| 588 | { | ||
| 589 | HRESULT hr; | ||
| 590 | |||
| 591 | USE_SAFE_ALLOCA; | ||
| 592 | |||
| 593 | DWRITE_FONT_METRICS dwrite_font_metrics; | ||
| 594 | dwrite_font_face->lpVtbl->GetMetrics (dwrite_font_face, | ||
| 595 | &dwrite_font_metrics); | ||
| 596 | |||
| 597 | UINT16 *indices = SAFE_ALLOCA (nglyphs * sizeof (UINT16)); | ||
| 598 | for (int i = 0; i < nglyphs; i++) | ||
| 599 | indices[i] = code[i]; | ||
| 600 | |||
| 601 | DWRITE_GLYPH_METRICS *gmetrics | ||
| 602 | = SAFE_ALLOCA (nglyphs * sizeof (DWRITE_GLYPH_METRICS)); | ||
| 603 | |||
| 604 | hr = dwrite_font_face->lpVtbl->GetGdiCompatibleGlyphMetrics (dwrite_font_face, | ||
| 605 | font_size, | ||
| 606 | 1.0, | ||
| 607 | NULL, | ||
| 608 | TRUE, | ||
| 609 | indices, | ||
| 610 | nglyphs, | ||
| 611 | gmetrics, | ||
| 612 | false); | ||
| 613 | if (!verify_hr (hr, "Failed to GetGdiCompatibleGlyphMetrics")) | ||
| 614 | { | ||
| 615 | SAFE_FREE (); | ||
| 616 | return false; | ||
| 617 | } | ||
| 618 | |||
| 619 | float width = 0; | ||
| 620 | int du_per_em = dwrite_font_metrics.designUnitsPerEm; | ||
| 621 | |||
| 622 | for (int i = 0; i < nglyphs; i++) | ||
| 623 | { | ||
| 624 | float advance | ||
| 625 | = convert_metrics_sz (gmetrics[i].advanceWidth, font_size, du_per_em); | ||
| 626 | |||
| 627 | width += advance; | ||
| 628 | |||
| 629 | float lbearing | ||
| 630 | = round (convert_metrics_sz (gmetrics[i].leftSideBearing, font_size, | ||
| 631 | du_per_em)); | ||
| 632 | float rbearing | ||
| 633 | = round (advance - | ||
| 634 | convert_metrics_sz (gmetrics[i].rightSideBearing, | ||
| 635 | font_size, du_per_em)); | ||
| 636 | if (i == 0) | ||
| 637 | { | ||
| 638 | metrics->lbearing = lbearing; | ||
| 639 | metrics->rbearing = rbearing; | ||
| 640 | } | ||
| 641 | if (metrics->lbearing > lbearing) | ||
| 642 | metrics->lbearing = lbearing; | ||
| 643 | if (metrics->rbearing < rbearing) | ||
| 644 | metrics->rbearing = rbearing; | ||
| 645 | } | ||
| 646 | metrics->width = round (width); | ||
| 647 | SAFE_FREE (); | ||
| 648 | return true; | ||
| 649 | } | ||
| 650 | |||
| 651 | unsigned | ||
| 652 | w32_dwrite_encode_char (struct font *font, int c) | ||
| 653 | { | ||
| 654 | HRESULT hr; | ||
| 655 | IDWriteFontFace *dwrite_font_face; | ||
| 656 | UINT16 index; | ||
| 657 | |||
| 658 | get_font_face (font, &dwrite_font_face); | ||
| 659 | if (dwrite_font_face == NULL) | ||
| 660 | return FONT_INVALID_CODE; | ||
| 661 | hr = dwrite_font_face->lpVtbl->GetGlyphIndices (dwrite_font_face, | ||
| 662 | (UINT32 *) &c, 1, &index); | ||
| 663 | if (verify_hr (hr, "Failed to GetGlyphIndices")) | ||
| 664 | { | ||
| 665 | if (index == 0) | ||
| 666 | return FONT_INVALID_CODE; | ||
| 667 | return index; | ||
| 668 | } | ||
| 669 | ((struct uniscribe_font_info *) font)->dwrite_skip_font = true; | ||
| 670 | return FONT_INVALID_CODE; | ||
| 671 | } | ||
| 672 | |||
| 673 | bool | ||
| 674 | w32_dwrite_text_extents (struct font *font, const unsigned *code, int nglyphs, | ||
| 675 | struct font_metrics *metrics) | ||
| 676 | { | ||
| 677 | IDWriteFontFace *dwrite_font_face; | ||
| 678 | |||
| 679 | float font_size = get_font_face (font, &dwrite_font_face); | ||
| 680 | |||
| 681 | if (dwrite_font_face == NULL) | ||
| 682 | return false; | ||
| 683 | |||
| 684 | /* We can get fonts with a size of 0. GDI handles this by using a default | ||
| 685 | size. We do the same. */ | ||
| 686 | if (font_size <= 0.0f) | ||
| 687 | font_size = FRAME_LINE_HEIGHT (SELECTED_FRAME ()); | ||
| 688 | |||
| 689 | metrics->ascent = font->ascent; | ||
| 690 | metrics->descent = font->descent; | ||
| 691 | |||
| 692 | return text_extents_internal (dwrite_font_face, font_size, code, nglyphs, | ||
| 693 | metrics); | ||
| 694 | } | ||
| 695 | |||
| 696 | /* Never call Release on the value returned by this function, as it is | ||
| 697 | reused. */ | ||
| 698 | static IDWriteBitmapRenderTarget * | ||
| 699 | get_bitmap_render_target (HDC hdc, int width, int height) | ||
| 700 | { | ||
| 701 | HRESULT hr; | ||
| 702 | static IDWriteBitmapRenderTarget *brt = NULL; | ||
| 703 | static SIZE size = {0, 0}; | ||
| 704 | |||
| 705 | if (brt) | ||
| 706 | { | ||
| 707 | /* Check if we need to make a bigger one. */ | ||
| 708 | if (width <= size.cx && height <= size.cy) | ||
| 709 | return brt; | ||
| 710 | RELEASE_COM (brt); | ||
| 711 | } | ||
| 712 | |||
| 713 | if (width > size.cx) | ||
| 714 | size.cx = width; | ||
| 715 | if (height > size.cy) | ||
| 716 | size.cy = height; | ||
| 717 | |||
| 718 | hr = gdi_interop->lpVtbl->CreateBitmapRenderTarget (gdi_interop, | ||
| 719 | hdc, | ||
| 720 | size.cx, size.cy, | ||
| 721 | &brt); | ||
| 722 | if (!verify_hr (hr, "Failed to CreateBitmapRenderTarget")) | ||
| 723 | return NULL; | ||
| 724 | |||
| 725 | /* We handle high dpi displays by incresing font size, so override | ||
| 726 | PixelsPerDip. */ | ||
| 727 | brt->lpVtbl->SetPixelsPerDip (brt, 1.0); | ||
| 728 | |||
| 729 | /* The SetTextAntialiasMode method is only available in | ||
| 730 | IDWriteBitmapRenderTarget1. */ | ||
| 731 | IDWriteBitmapRenderTarget1 *brt1; | ||
| 732 | hr = brt->lpVtbl->QueryInterface (brt, | ||
| 733 | &IID_IDWriteBitmapRenderTarget1, | ||
| 734 | (void **) &brt1); | ||
| 735 | /* This error should not happen, but is not catastrofic */ | ||
| 736 | if (verify_hr (hr, "Failed to QueryInterface for IDWriteBitmapRenderTarget1")) | ||
| 737 | { | ||
| 738 | brt1->lpVtbl->SetTextAntialiasMode (brt1, ANTIALIAS_MODE); | ||
| 739 | RELEASE_COM (brt1); | ||
| 740 | } | ||
| 741 | |||
| 742 | return brt; | ||
| 743 | } | ||
| 744 | |||
| 745 | void | ||
| 746 | w32_initialize_direct_write (void) | ||
| 747 | { | ||
| 748 | direct_write_available = false; | ||
| 749 | |||
| 750 | if (dwrite_factory) | ||
| 751 | { | ||
| 752 | RELEASE_COM (dwrite_factory); | ||
| 753 | RELEASE_COM (dwrite_factory2); | ||
| 754 | RELEASE_COM (gdi_interop); | ||
| 755 | RELEASE_COM (rendering_params); | ||
| 756 | } | ||
| 757 | |||
| 758 | HMODULE direct_write = LoadLibrary ("dwrite.dll"); | ||
| 759 | if (!direct_write) | ||
| 760 | return; | ||
| 761 | |||
| 762 | /* This is only used here, no need to define it globally. */ | ||
| 763 | typedef HRESULT (WINAPI *DWCreateFactory) (DWRITE_FACTORY_TYPE, | ||
| 764 | REFIID, IUnknown **); | ||
| 765 | |||
| 766 | DWCreateFactory dw_create_factory | ||
| 767 | = (DWCreateFactory) get_proc_addr (direct_write, | ||
| 768 | "DWriteCreateFactory"); | ||
| 769 | |||
| 770 | if (!dw_create_factory) | ||
| 771 | { | ||
| 772 | FreeLibrary (direct_write); | ||
| 773 | return; | ||
| 774 | } | ||
| 775 | |||
| 776 | HRESULT hr = dw_create_factory (DWRITE_FACTORY_TYPE_SHARED, | ||
| 777 | &IID_IDWriteFactory, | ||
| 778 | (IUnknown **) &dwrite_factory); | ||
| 779 | if (FAILED (hr)) | ||
| 780 | { | ||
| 781 | DebPrint (("DirectWrite HRESULT failed: (%d) CreateFactory\n", hr)); | ||
| 782 | FreeLibrary (direct_write); | ||
| 783 | eassert (SUCCEEDED (hr)); | ||
| 784 | return; | ||
| 785 | } | ||
| 786 | |||
| 787 | /* IDWriteFactory2 is only available on Windows 8.1 and later. | ||
| 788 | Without this, we can't use color fonts. So we disable DirectWrite | ||
| 789 | if it is not available. */ | ||
| 790 | hr = dwrite_factory->lpVtbl->QueryInterface (dwrite_factory, | ||
| 791 | &IID_IDWriteFactory2, | ||
| 792 | (void **) &dwrite_factory2); | ||
| 793 | |||
| 794 | if (FAILED (hr)) | ||
| 795 | { | ||
| 796 | DebPrint (("DirectWrite HRESULT failed: (%d) QueryInterface IDWriteFactory2\n", hr)); | ||
| 797 | RELEASE_COM (dwrite_factory); | ||
| 798 | FreeLibrary (direct_write); | ||
| 799 | return; | ||
| 800 | } | ||
| 801 | |||
| 802 | hr = dwrite_factory->lpVtbl->GetGdiInterop (dwrite_factory, | ||
| 803 | &gdi_interop); | ||
| 804 | if (FAILED (hr)) | ||
| 805 | { | ||
| 806 | DebPrint (("DirectWrite HRESULT failed: (%d) GetGdiInterop\n", hr)); | ||
| 807 | RELEASE_COM (dwrite_factory); | ||
| 808 | RELEASE_COM (dwrite_factory2); | ||
| 809 | FreeLibrary (direct_write); | ||
| 810 | eassert (SUCCEEDED (hr)); | ||
| 811 | return; | ||
| 812 | } | ||
| 813 | |||
| 814 | IDWriteRenderingParams *def; | ||
| 815 | |||
| 816 | hr = dwrite_factory->lpVtbl->CreateRenderingParams (dwrite_factory, | ||
| 817 | &def); | ||
| 818 | if (FAILED (hr)) | ||
| 819 | { | ||
| 820 | DebPrint (("DirectWrite HRESULT failed: (%d) CreateRenderingParams\n", hr)); | ||
| 821 | RELEASE_COM (dwrite_factory); | ||
| 822 | RELEASE_COM (dwrite_factory2); | ||
| 823 | RELEASE_COM (gdi_interop); | ||
| 824 | FreeLibrary (direct_write); | ||
| 825 | eassert (SUCCEEDED (hr)); | ||
| 826 | return; | ||
| 827 | } | ||
| 828 | |||
| 829 | /* range: [0.0, 1.0] */ | ||
| 830 | if (config_enhanced_contrast < 0.0f || config_enhanced_contrast > 1.0f) | ||
| 831 | config_enhanced_contrast = def->lpVtbl->GetEnhancedContrast (def); | ||
| 832 | |||
| 833 | /* range: [0.0, 1.0] */ | ||
| 834 | if (config_clear_type_level < 0.0f || config_clear_type_level > 1.0f) | ||
| 835 | config_clear_type_level = def->lpVtbl->GetClearTypeLevel (def); | ||
| 836 | |||
| 837 | /* range: (0.0, 256.0] */ | ||
| 838 | /* We change the default value of 2.2 for gamma to 1.4, that looks | ||
| 839 | very similar to GDI. The default looks too dim for emacs, | ||
| 840 | subjectively. */ | ||
| 841 | if (config_gamma <= 0.0f || config_gamma > 256.0f) | ||
| 842 | config_gamma = 1.4; /* def->lpVtbl->GetGamma (def); */ | ||
| 843 | |||
| 844 | hr = dwrite_factory->lpVtbl->CreateCustomRenderingParams (dwrite_factory, | ||
| 845 | config_gamma, | ||
| 846 | config_enhanced_contrast, | ||
| 847 | config_clear_type_level, | ||
| 848 | def->lpVtbl->GetPixelGeometry (def), | ||
| 849 | RENDERING_MODE, | ||
| 850 | &rendering_params); | ||
| 851 | |||
| 852 | RELEASE_COM (def); | ||
| 853 | |||
| 854 | if (FAILED (hr)) | ||
| 855 | { | ||
| 856 | DebPrint (("DirectWrite HRESULT failed: (%d)" | ||
| 857 | " CreateCustomRenderingParams\n", hr)); | ||
| 858 | RELEASE_COM (dwrite_factory); | ||
| 859 | RELEASE_COM (dwrite_factory2); | ||
| 860 | RELEASE_COM (gdi_interop); | ||
| 861 | FreeLibrary (direct_write); | ||
| 862 | eassert (SUCCEEDED (hr)); | ||
| 863 | return; | ||
| 864 | } | ||
| 865 | |||
| 866 | direct_write_available = true; | ||
| 867 | |||
| 868 | w32_inhibit_dwrite = false; | ||
| 869 | } | ||
| 870 | |||
| 871 | bool | ||
| 872 | w32_dwrite_draw (HDC hdc, int x, int y, unsigned *glyphs, int len, | ||
| 873 | COLORREF color, struct font *font) | ||
| 874 | { | ||
| 875 | HRESULT hr; | ||
| 876 | IDWriteFontFace *dwrite_font_face; | ||
| 877 | |||
| 878 | USE_SAFE_ALLOCA; | ||
| 879 | |||
| 880 | struct uniscribe_font_info *uniscribe_font | ||
| 881 | = (struct uniscribe_font_info *) font; | ||
| 882 | |||
| 883 | /* What we get as y is the baseline position. */ | ||
| 884 | y -= font->ascent; | ||
| 885 | |||
| 886 | float font_size = get_font_face (font, &dwrite_font_face); | ||
| 887 | if (dwrite_font_face == NULL) | ||
| 888 | return false; | ||
| 889 | |||
| 890 | struct font_metrics metrics; | ||
| 891 | if (!text_extents_internal (dwrite_font_face, font_size, glyphs, len, | ||
| 892 | &metrics)) | ||
| 893 | { | ||
| 894 | uniscribe_font->dwrite_skip_font = true; | ||
| 895 | return false; | ||
| 896 | } | ||
| 897 | |||
| 898 | int left_margin = metrics.lbearing < 0 ? -metrics.lbearing : 0; | ||
| 899 | |||
| 900 | int bitmap_width = left_margin + metrics.width + metrics.rbearing; | ||
| 901 | int bitmap_height = font->ascent + font->descent; | ||
| 902 | |||
| 903 | /* We never release this, get_bitmap_render_target reuses it. */ | ||
| 904 | IDWriteBitmapRenderTarget *bitmap_render_target = | ||
| 905 | get_bitmap_render_target (hdc, bitmap_width, bitmap_height); | ||
| 906 | |||
| 907 | /* If this fails, completely disable DirectWrite. */ | ||
| 908 | if (bitmap_render_target == NULL) | ||
| 909 | { | ||
| 910 | direct_write_available = false; | ||
| 911 | return false; | ||
| 912 | } | ||
| 913 | |||
| 914 | /* This DC can't be released. */ | ||
| 915 | HDC text_dc | ||
| 916 | = bitmap_render_target->lpVtbl->GetMemoryDC (bitmap_render_target); | ||
| 917 | |||
| 918 | /* Copy the background pixel to the render target bitmap. */ | ||
| 919 | BitBlt (text_dc, 0, 0, bitmap_width, bitmap_height, hdc, x - left_margin, y, SRCCOPY); | ||
| 920 | |||
| 921 | UINT16 *indices = SAFE_ALLOCA (len * sizeof (UINT16)); | ||
| 922 | |||
| 923 | for (int i = 0; i < len; i++) | ||
| 924 | indices[i] = glyphs[i]; | ||
| 925 | |||
| 926 | FLOAT *advances = SAFE_ALLOCA (len * sizeof (FLOAT)); | ||
| 927 | |||
| 928 | for (int i = 0; i < len; i++) | ||
| 929 | { | ||
| 930 | if (!text_extents_internal (dwrite_font_face, font_size, glyphs + i, 1, | ||
| 931 | &metrics)) | ||
| 932 | { | ||
| 933 | uniscribe_font->dwrite_skip_font = true; | ||
| 934 | SAFE_FREE (); | ||
| 935 | return false; | ||
| 936 | } | ||
| 937 | advances[i] = metrics.width; | ||
| 938 | } | ||
| 939 | |||
| 940 | DWRITE_GLYPH_RUN glyph_run; | ||
| 941 | glyph_run.fontFace = dwrite_font_face; | ||
| 942 | glyph_run.fontEmSize = font_size; | ||
| 943 | glyph_run.glyphIndices = indices; | ||
| 944 | glyph_run.glyphCount = len; | ||
| 945 | glyph_run.isSideways = false; | ||
| 946 | glyph_run.bidiLevel = 0; /* we reorder bidi text ourselves */ | ||
| 947 | glyph_run.glyphOffsets = NULL; | ||
| 948 | glyph_run.glyphAdvances = advances; | ||
| 949 | |||
| 950 | IDWriteColorGlyphRunEnumerator *layers; | ||
| 951 | /* This call will tell us if we have to handle any color glyphs. */ | ||
| 952 | hr = dwrite_factory2->lpVtbl->TranslateColorGlyphRun (dwrite_factory2, | ||
| 953 | left_margin, font->ascent, | ||
| 954 | &glyph_run, | ||
| 955 | NULL, | ||
| 956 | MEASURING_MODE, | ||
| 957 | NULL, | ||
| 958 | 0, | ||
| 959 | &layers); | ||
| 960 | |||
| 961 | /* No color. Just draw the GlyphRun. */ | ||
| 962 | if (hr == DWRITE_E_NOCOLOR) | ||
| 963 | bitmap_render_target->lpVtbl->DrawGlyphRun (bitmap_render_target, | ||
| 964 | left_margin, font->ascent, | ||
| 965 | MEASURING_MODE, | ||
| 966 | &glyph_run, | ||
| 967 | rendering_params, | ||
| 968 | color, | ||
| 969 | NULL); | ||
| 970 | else | ||
| 971 | { | ||
| 972 | /* If there were color glyphs, 'layers' contains a list of | ||
| 973 | GlyphRun with a color and a position for each. We draw them | ||
| 974 | individually. */ | ||
| 975 | if (!verify_hr (hr, "Failed at TranslateColorGlyphRun")) | ||
| 976 | { | ||
| 977 | uniscribe_font->dwrite_skip_font = true; | ||
| 978 | RELEASE_COM (layers); | ||
| 979 | SAFE_FREE (); | ||
| 980 | return false; | ||
| 981 | } | ||
| 982 | for (;;) | ||
| 983 | { | ||
| 984 | HRESULT hr; | ||
| 985 | BOOL more_layers; | ||
| 986 | const DWRITE_COLOR_GLYPH_RUN *layer; | ||
| 987 | |||
| 988 | hr = layers->lpVtbl->MoveNext (layers, &more_layers); | ||
| 989 | if (!verify_hr (hr, "Failed at MoveNext")) | ||
| 990 | { | ||
| 991 | uniscribe_font->dwrite_skip_font = true; | ||
| 992 | RELEASE_COM (layers); | ||
| 993 | SAFE_FREE (); | ||
| 994 | return false; | ||
| 995 | } | ||
| 996 | if (!more_layers) | ||
| 997 | break; | ||
| 998 | hr = layers->lpVtbl->GetCurrentRun (layers, &layer); | ||
| 999 | if (!verify_hr (hr, "Failed at GetCurrentRun")) | ||
| 1000 | { | ||
| 1001 | uniscribe_font->dwrite_skip_font = true; | ||
| 1002 | RELEASE_COM (layers); | ||
| 1003 | SAFE_FREE (); | ||
| 1004 | return false; | ||
| 1005 | } | ||
| 1006 | hr = bitmap_render_target->lpVtbl->DrawGlyphRun | ||
| 1007 | (bitmap_render_target, | ||
| 1008 | layer->baselineOriginX, | ||
| 1009 | layer->baselineOriginY, | ||
| 1010 | MEASURING_MODE, | ||
| 1011 | &layer->glyphRun, | ||
| 1012 | rendering_params, | ||
| 1013 | RGB (layer->runColor.r * 255, | ||
| 1014 | layer->runColor.g * 255, | ||
| 1015 | layer->runColor.b * 255), | ||
| 1016 | NULL); | ||
| 1017 | if (!verify_hr (hr, "Failed at GetCurrentRun")) | ||
| 1018 | { | ||
| 1019 | uniscribe_font->dwrite_skip_font = true; | ||
| 1020 | RELEASE_COM (layers); | ||
| 1021 | SAFE_FREE (); | ||
| 1022 | return false; | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | RELEASE_COM (layers); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | /* Finally, copy the rendered text back to the original DC. */ | ||
| 1029 | BitBlt (hdc, x - left_margin, y, bitmap_width, bitmap_height, text_dc, 0, 0, SRCCOPY); | ||
| 1030 | SAFE_FREE (); | ||
| 1031 | return true; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | /* Returns true if DirectWrite is to be used: | ||
| 1035 | - It is available. | ||
| 1036 | - The font is handled by HarfBuzz. | ||
| 1037 | - w32-inhibit-dwrite is false. | ||
| 1038 | - The font has not been marked after a failed DirectWrite operation. | ||
| 1039 | */ | ||
| 1040 | bool | ||
| 1041 | w32_use_direct_write (struct w32font_info *w32font) | ||
| 1042 | { | ||
| 1043 | #ifdef HAVE_HARFBUZZ | ||
| 1044 | return (direct_write_available | ||
| 1045 | && w32font->font.driver == &harfbuzz_font_driver | ||
| 1046 | && !w32_inhibit_dwrite | ||
| 1047 | && !((struct uniscribe_font_info *) w32font)->dwrite_skip_font); | ||
| 1048 | #else | ||
| 1049 | return false; | ||
| 1050 | #endif | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | DEFUN ("w32-dwrite-available", Fw32_dwrite_available, Sw32_dwrite_available, 0, 0, 0, | ||
| 1054 | doc: /* Returns t if DirectWrite is available. | ||
| 1055 | DirectWrite will be used if it is available and 'w32-inhibit-dwrite' is nil. */) | ||
| 1056 | (void) | ||
| 1057 | { | ||
| 1058 | return direct_write_available ? Qt : Qnil; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | DEFUN ("w32-dwrite-reinit", Fw32_dwrite_reinit, Sw32_dwrite_reinit, 0, 3, 0, | ||
| 1062 | doc: /* Reinitialize DirectWrite with the given parameters. | ||
| 1063 | If a parameter is not specified, or is out of range, it will take a default | ||
| 1064 | value. | ||
| 1065 | |||
| 1066 | Return value is nil. | ||
| 1067 | |||
| 1068 | ENHANCED_CONTRAST is in the range [0.0, 1.0], and defaults to 0.5. | ||
| 1069 | CLEAR_TYPE_LEVEL is in the range [0.0, 1.0], and defaults to 1.0. | ||
| 1070 | GAMMA is in the range (0.0, 256.0], and defaults to a system-dependent value | ||
| 1071 | around 2.0 (sometimes 1.8, sometimes 2.2). */) | ||
| 1072 | (Lisp_Object enhanced_contrast, Lisp_Object clear_type_level, | ||
| 1073 | Lisp_Object gamma) | ||
| 1074 | { | ||
| 1075 | config_enhanced_contrast = -1.0f; | ||
| 1076 | if (FLOATP (enhanced_contrast)) | ||
| 1077 | config_enhanced_contrast = XFLOAT_DATA (enhanced_contrast); | ||
| 1078 | if (FIXNUMP (enhanced_contrast)) | ||
| 1079 | config_enhanced_contrast = XFIXNUM (enhanced_contrast); | ||
| 1080 | |||
| 1081 | config_clear_type_level = -1.0f; | ||
| 1082 | if (FLOATP (clear_type_level)) | ||
| 1083 | config_clear_type_level = XFLOAT_DATA (clear_type_level); | ||
| 1084 | if (FIXNUMP (clear_type_level)) | ||
| 1085 | config_clear_type_level = XFIXNUM (clear_type_level); | ||
| 1086 | |||
| 1087 | config_gamma = -1.0f; | ||
| 1088 | if (FLOATP (gamma)) | ||
| 1089 | config_gamma = XFLOAT_DATA (gamma); | ||
| 1090 | if (FIXNUMP (gamma)) | ||
| 1091 | config_gamma = XFIXNUM (gamma); | ||
| 1092 | |||
| 1093 | w32_initialize_direct_write (); | ||
| 1094 | |||
| 1095 | return Qnil; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | void | ||
| 1099 | syms_of_w32dwrite (void) | ||
| 1100 | { | ||
| 1101 | DEFVAR_BOOL ("w32-inhibit-dwrite", w32_inhibit_dwrite, | ||
| 1102 | doc: /* If t, don't use DirectWrite. */); | ||
| 1103 | /* The actual value is determined at startup in | ||
| 1104 | w32_initialize_direct_write, which is called from | ||
| 1105 | syms_of_w32uniscribe_for_pdumper. */ | ||
| 1106 | w32_inhibit_dwrite = false; | ||
| 1107 | |||
| 1108 | defsubr (&Sw32_dwrite_reinit); | ||
| 1109 | defsubr (&Sw32_dwrite_available); | ||
| 1110 | } | ||
diff --git a/src/w32fns.c b/src/w32fns.c index 3ee13dcbbdd..e2455b9271e 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -2479,9 +2479,22 @@ static Lisp_Object | |||
| 2479 | process_dropfiles (DROPFILES *files) | 2479 | process_dropfiles (DROPFILES *files) |
| 2480 | { | 2480 | { |
| 2481 | char *start_of_files = (char *) files + files->pFiles; | 2481 | char *start_of_files = (char *) files + files->pFiles; |
| 2482 | #ifndef NTGUI_UNICODE | ||
| 2482 | char filename[MAX_UTF8_PATH]; | 2483 | char filename[MAX_UTF8_PATH]; |
| 2484 | #endif | ||
| 2483 | Lisp_Object lisp_files = Qnil; | 2485 | Lisp_Object lisp_files = Qnil; |
| 2484 | 2486 | ||
| 2487 | #ifdef NTGUI_UNICODE | ||
| 2488 | WCHAR *p = (WCHAR *) start_of_files; | ||
| 2489 | for (; *p; p += wcslen (p) + 1) | ||
| 2490 | { | ||
| 2491 | Lisp_Object fn = from_unicode_buffer (p); | ||
| 2492 | #ifdef CYGWIN | ||
| 2493 | fn = Fcygwin_convert_file_name_to_windows (fn, Qt); | ||
| 2494 | #endif | ||
| 2495 | lisp_files = Fcons (fn, lisp_files); | ||
| 2496 | } | ||
| 2497 | #else | ||
| 2485 | if (files->fWide) | 2498 | if (files->fWide) |
| 2486 | { | 2499 | { |
| 2487 | WCHAR *p = (WCHAR *) start_of_files; | 2500 | WCHAR *p = (WCHAR *) start_of_files; |
| @@ -2502,10 +2515,10 @@ process_dropfiles (DROPFILES *files) | |||
| 2502 | lisp_files); | 2515 | lisp_files); |
| 2503 | } | 2516 | } |
| 2504 | } | 2517 | } |
| 2518 | #endif | ||
| 2505 | return lisp_files; | 2519 | return lisp_files; |
| 2506 | } | 2520 | } |
| 2507 | 2521 | ||
| 2508 | |||
| 2509 | /* This function can be called ONLY between calls to | 2522 | /* This function can be called ONLY between calls to |
| 2510 | block_input/unblock_input. It is used in w32_read_socket. */ | 2523 | block_input/unblock_input. It is used in w32_read_socket. */ |
| 2511 | Lisp_Object | 2524 | Lisp_Object |
| @@ -2549,6 +2562,7 @@ struct w32_drop_target { | |||
| 2549 | /* i_drop_target must be the first member. */ | 2562 | /* i_drop_target must be the first member. */ |
| 2550 | IDropTarget i_drop_target; | 2563 | IDropTarget i_drop_target; |
| 2551 | HWND hwnd; | 2564 | HWND hwnd; |
| 2565 | int ref_count; | ||
| 2552 | }; | 2566 | }; |
| 2553 | 2567 | ||
| 2554 | static HRESULT STDMETHODCALLTYPE | 2568 | static HRESULT STDMETHODCALLTYPE |
| @@ -2560,18 +2574,34 @@ w32_drop_target_QueryInterface (IDropTarget *t, REFIID ri, void **r) | |||
| 2560 | static ULONG STDMETHODCALLTYPE | 2574 | static ULONG STDMETHODCALLTYPE |
| 2561 | w32_drop_target_AddRef (IDropTarget *This) | 2575 | w32_drop_target_AddRef (IDropTarget *This) |
| 2562 | { | 2576 | { |
| 2563 | return 1; | 2577 | struct w32_drop_target *target = (struct w32_drop_target *) This; |
| 2578 | return ++target->ref_count; | ||
| 2564 | } | 2579 | } |
| 2565 | 2580 | ||
| 2566 | static ULONG STDMETHODCALLTYPE | 2581 | static ULONG STDMETHODCALLTYPE |
| 2567 | w32_drop_target_Release (IDropTarget *This) | 2582 | w32_drop_target_Release (IDropTarget *This) |
| 2568 | { | 2583 | { |
| 2569 | struct w32_drop_target *target = (struct w32_drop_target *) This; | 2584 | struct w32_drop_target *target = (struct w32_drop_target *) This; |
| 2585 | if (--target->ref_count > 0) | ||
| 2586 | return target->ref_count; | ||
| 2570 | free (target->i_drop_target.lpVtbl); | 2587 | free (target->i_drop_target.lpVtbl); |
| 2571 | free (target); | 2588 | free (target); |
| 2572 | return 0; | 2589 | return 0; |
| 2573 | } | 2590 | } |
| 2574 | 2591 | ||
| 2592 | static void | ||
| 2593 | w32_handle_drag_movement (IDropTarget *This, POINTL pt) | ||
| 2594 | { | ||
| 2595 | struct w32_drop_target *target = (struct w32_drop_target *)This; | ||
| 2596 | |||
| 2597 | W32Msg msg = {0}; | ||
| 2598 | msg.dwModifiers = w32_get_modifiers (); | ||
| 2599 | msg.msg.time = GetMessageTime (); | ||
| 2600 | msg.msg.pt.x = pt.x; | ||
| 2601 | msg.msg.pt.y = pt.y; | ||
| 2602 | my_post_msg (&msg, target->hwnd, WM_EMACS_DRAGOVER, 0, 0 ); | ||
| 2603 | } | ||
| 2604 | |||
| 2575 | static HRESULT STDMETHODCALLTYPE | 2605 | static HRESULT STDMETHODCALLTYPE |
| 2576 | w32_drop_target_DragEnter (IDropTarget *This, IDataObject *pDataObj, | 2606 | w32_drop_target_DragEnter (IDropTarget *This, IDataObject *pDataObj, |
| 2577 | DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) | 2607 | DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) |
| @@ -2581,6 +2611,7 @@ w32_drop_target_DragEnter (IDropTarget *This, IDataObject *pDataObj, | |||
| 2581 | happen on drop. We send COPY because our use cases don't modify | 2611 | happen on drop. We send COPY because our use cases don't modify |
| 2582 | or link to the original data. */ | 2612 | or link to the original data. */ |
| 2583 | *pdwEffect = DROPEFFECT_COPY; | 2613 | *pdwEffect = DROPEFFECT_COPY; |
| 2614 | w32_handle_drag_movement (This, pt); | ||
| 2584 | return S_OK; | 2615 | return S_OK; |
| 2585 | } | 2616 | } |
| 2586 | 2617 | ||
| @@ -2590,6 +2621,7 @@ w32_drop_target_DragOver (IDropTarget *This, DWORD grfKeyState, POINTL pt, | |||
| 2590 | { | 2621 | { |
| 2591 | /* See comment in w32_drop_target_DragEnter. */ | 2622 | /* See comment in w32_drop_target_DragEnter. */ |
| 2592 | *pdwEffect = DROPEFFECT_COPY; | 2623 | *pdwEffect = DROPEFFECT_COPY; |
| 2624 | w32_handle_drag_movement (This, pt); | ||
| 2593 | return S_OK; | 2625 | return S_OK; |
| 2594 | } | 2626 | } |
| 2595 | 2627 | ||
| @@ -2742,6 +2774,7 @@ w32_createwindow (struct frame *f, int *coords) | |||
| 2742 | if (vtbl != NULL) | 2774 | if (vtbl != NULL) |
| 2743 | { | 2775 | { |
| 2744 | drop_target->hwnd = hwnd; | 2776 | drop_target->hwnd = hwnd; |
| 2777 | drop_target->ref_count = 0; | ||
| 2745 | drop_target->i_drop_target.lpVtbl = vtbl; | 2778 | drop_target->i_drop_target.lpVtbl = vtbl; |
| 2746 | vtbl->QueryInterface = w32_drop_target_QueryInterface; | 2779 | vtbl->QueryInterface = w32_drop_target_QueryInterface; |
| 2747 | vtbl->AddRef = w32_drop_target_AddRef; | 2780 | vtbl->AddRef = w32_drop_target_AddRef; |
| @@ -3607,6 +3640,7 @@ w32_name_of_message (UINT msg) | |||
| 3607 | M (WM_EMACS_PAINT), | 3640 | M (WM_EMACS_PAINT), |
| 3608 | M (WM_EMACS_IME_STATUS), | 3641 | M (WM_EMACS_IME_STATUS), |
| 3609 | M (WM_CHAR), | 3642 | M (WM_CHAR), |
| 3643 | M (WM_EMACS_DRAGOVER), | ||
| 3610 | M (WM_EMACS_DROP), | 3644 | M (WM_EMACS_DROP), |
| 3611 | #undef M | 3645 | #undef M |
| 3612 | { 0, 0 } | 3646 | { 0, 0 } |
diff --git a/src/w32font.c b/src/w32font.c index efb42d80336..48968a28fbd 100644 --- a/src/w32font.c +++ b/src/w32font.c | |||
| @@ -452,6 +452,10 @@ w32font_text_extents (struct font *font, const unsigned *code, | |||
| 452 | 452 | ||
| 453 | memset (metrics, 0, sizeof (struct font_metrics)); | 453 | memset (metrics, 0, sizeof (struct font_metrics)); |
| 454 | 454 | ||
| 455 | if (w32_use_direct_write (w32_font) | ||
| 456 | && w32_dwrite_text_extents (font, code, nglyphs, metrics)) | ||
| 457 | return; | ||
| 458 | |||
| 455 | for (i = 0, first = true; i < nglyphs; i++) | 459 | for (i = 0, first = true; i < nglyphs; i++) |
| 456 | { | 460 | { |
| 457 | struct w32_metric_cache *char_metric; | 461 | struct w32_metric_cache *char_metric; |
| @@ -706,22 +710,31 @@ w32font_draw (struct glyph_string *s, int from, int to, | |||
| 706 | int i; | 710 | int i; |
| 707 | 711 | ||
| 708 | for (i = 0; i < len; i++) | 712 | for (i = 0; i < len; i++) |
| 709 | { | 713 | if (!w32_use_direct_write (w32font) |
| 710 | WCHAR c = s->char2b[from + i] & 0xFFFF; | 714 | || !w32_dwrite_draw (s->hdc, x, y, s->char2b + from, 1, |
| 711 | ExtTextOutW (s->hdc, x + i, y, options, NULL, &c, 1, NULL); | 715 | GetTextColor (s->hdc), s->font)) |
| 712 | } | 716 | { |
| 717 | WCHAR c = s->char2b[from + i] & 0xFFFF; | ||
| 718 | ExtTextOutW (s->hdc, x + i, y, options, NULL, &c, 1, NULL); | ||
| 719 | } | ||
| 713 | } | 720 | } |
| 714 | else | 721 | else |
| 715 | { | 722 | { |
| 716 | /* The number of glyphs in a glyph_string cannot be larger than | 723 | if (!w32_use_direct_write (w32font) |
| 717 | the maximum value of the 'used' member of a glyph_row, so we | 724 | || !w32_dwrite_draw (s->hdc, x, y, |
| 718 | are OK using alloca here. */ | 725 | s->char2b + from, len, GetTextColor (s->hdc), |
| 719 | eassert (len <= SHRT_MAX); | 726 | s->font)) |
| 720 | WCHAR *chars = alloca (len * sizeof (WCHAR)); | 727 | { |
| 721 | int j; | 728 | /* The number of glyphs in a glyph_string cannot be larger than |
| 722 | for (j = 0; j < len; j++) | 729 | the maximum value of the 'used' member of a glyph_row, so we |
| 723 | chars[j] = s->char2b[from + j] & 0xFFFF; | 730 | are OK using alloca here. */ |
| 724 | ExtTextOutW (s->hdc, x, y, options, NULL, chars, len, NULL); | 731 | eassert (len <= SHRT_MAX); |
| 732 | WCHAR *chars = alloca (len * sizeof (WCHAR)); | ||
| 733 | int j; | ||
| 734 | for (j = 0; j < len; j++) | ||
| 735 | chars[j] = s->char2b[from + j] & 0xFFFF; | ||
| 736 | ExtTextOutW (s->hdc, x, y, options, NULL, chars, len, NULL); | ||
| 737 | } | ||
| 725 | } | 738 | } |
| 726 | 739 | ||
| 727 | /* Restore clip region. */ | 740 | /* Restore clip region. */ |
diff --git a/src/w32font.h b/src/w32font.h index 3f780c1d866..74552a5bee5 100644 --- a/src/w32font.h +++ b/src/w32font.h | |||
| @@ -57,6 +57,26 @@ struct w32font_info | |||
| 57 | HFONT hfont; | 57 | HFONT hfont; |
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | /* Extension of w32font_info used by Uniscribe and HarfBuzz backends. */ | ||
| 61 | struct uniscribe_font_info | ||
| 62 | { | ||
| 63 | struct w32font_info w32_font; | ||
| 64 | /* This is used by the Uniscribe backend as a pointer to the script | ||
| 65 | cache, and by the HarfBuzz backend as a pointer to a hb_font_t | ||
| 66 | object. */ | ||
| 67 | void *cache; | ||
| 68 | /* This is used by the HarfBuzz backend to store the font scale. */ | ||
| 69 | double scale; | ||
| 70 | /* This is used by DirectWrite to store the FontFace object. | ||
| 71 | DirectWrite works on top of the HarfBuzz backend, modifying some | ||
| 72 | calls. If there are problems manipulating this font, | ||
| 73 | dwrite_skip_font is set to true. Future operations will not use | ||
| 74 | DirectWrite and fall back to the HarfBuzz backend. */ | ||
| 75 | void *dwrite_cache; | ||
| 76 | float dwrite_font_size; | ||
| 77 | bool dwrite_skip_font; | ||
| 78 | }; | ||
| 79 | |||
| 60 | /* Macros for getting OS specific information from a font struct. */ | 80 | /* Macros for getting OS specific information from a font struct. */ |
| 61 | #define FONT_HANDLE(f) (((struct w32font_info *)(f))->hfont) | 81 | #define FONT_HANDLE(f) (((struct w32font_info *)(f))->hfont) |
| 62 | #define FONT_TEXTMETRIC(f) (((struct w32font_info *)(f))->metrics) | 82 | #define FONT_TEXTMETRIC(f) (((struct w32font_info *)(f))->metrics) |
| @@ -84,6 +104,17 @@ int uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec); | |||
| 84 | 104 | ||
| 85 | Lisp_Object intern_font_name (char *); | 105 | Lisp_Object intern_font_name (char *); |
| 86 | 106 | ||
| 107 | /* Function prototypes for DirectWrite. */ | ||
| 108 | void w32_initialize_direct_write (void); | ||
| 109 | bool w32_use_direct_write (struct w32font_info *w32font); | ||
| 110 | bool w32_dwrite_draw (HDC hdc, int x, int y, unsigned *glyphs, int len, | ||
| 111 | COLORREF color, struct font *font ); | ||
| 112 | bool w32_dwrite_text_extents (struct font *font, const unsigned *code, | ||
| 113 | int nglyphs, struct font_metrics *metrics); | ||
| 114 | unsigned w32_dwrite_encode_char (struct font *font, int c); | ||
| 115 | void w32_dwrite_free_cached_face (void *cache); | ||
| 116 | void syms_of_w32dwrite (void); | ||
| 117 | |||
| 87 | extern void globals_of_w32font (void); | 118 | extern void globals_of_w32font (void); |
| 88 | 119 | ||
| 89 | #endif | 120 | #endif |
diff --git a/src/w32gdiplus.h b/src/w32gdiplus.h new file mode 100644 index 00000000000..b438b1a64f8 --- /dev/null +++ b/src/w32gdiplus.h | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | #ifdef WINDOWSNT | ||
| 2 | typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc) | ||
| 3 | (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *); | ||
| 4 | typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR); | ||
| 5 | typedef GpStatus (WINGDIPAPI *GdipCreateFromHDC_Proc) | ||
| 6 | (HDC hdc, GpGraphics **graphics); | ||
| 7 | typedef GpStatus (WINGDIPAPI *GdipDeleteGraphics_Proc) (GpGraphics *graphics); | ||
| 8 | typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc) | ||
| 9 | (GpImage *, PROPID, UINT *); | ||
| 10 | typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc) | ||
| 11 | (GpImage *, PROPID, UINT, PropertyItem *); | ||
| 12 | typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc) | ||
| 13 | (GpImage *, UINT *); | ||
| 14 | typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc) | ||
| 15 | (GpImage *, GUID *, UINT); | ||
| 16 | typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc) | ||
| 17 | (GpImage *, GDIPCONST GUID *, UINT *); | ||
| 18 | typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc) | ||
| 19 | (GpImage*, GDIPCONST GUID *, UINT); | ||
| 20 | typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc) | ||
| 21 | (WCHAR *, GpBitmap **); | ||
| 22 | typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc) | ||
| 23 | (IStream *, GpBitmap **); | ||
| 24 | typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc) | ||
| 25 | (INT, INT, INT, PixelFormat, BYTE*, GpBitmap**); | ||
| 26 | typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromHBITMAP_Proc) | ||
| 27 | (HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap); | ||
| 28 | typedef GpStatus (WINGDIPAPI *GdipSetInterpolationMode_Proc) | ||
| 29 | (GpGraphics *graphics, InterpolationMode interpolationMode); | ||
| 30 | typedef GpStatus (WINGDIPAPI *GdipDrawImageRectRectI_Proc) | ||
| 31 | (GpGraphics *graphics, GpImage *image, INT dstx, INT dsty, INT dstwidth, | ||
| 32 | INT dstheight, INT srcx, INT srcy, INT srcwidth, INT srcheight, | ||
| 33 | GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, | ||
| 34 | DrawImageAbort callback, VOID * callbackData); | ||
| 35 | typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT); | ||
| 36 | typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc) | ||
| 37 | (GpBitmap *, HBITMAP *, ARGB); | ||
| 38 | typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *); | ||
| 39 | typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *); | ||
| 40 | typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *); | ||
| 41 | typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *); | ||
| 42 | typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc) | ||
| 43 | (UINT, UINT, ImageCodecInfo *); | ||
| 44 | typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc) | ||
| 45 | (GDIPCONST WCHAR *,GpImage **); | ||
| 46 | typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc) | ||
| 47 | (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *); | ||
| 48 | typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc) | ||
| 49 | (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *, | ||
| 50 | GDIPCONST EncoderParameters *); | ||
| 51 | typedef GpStatus (WINGDIPAPI *GdipImageRotateFlip_Proc) | ||
| 52 | (GpImage *image, RotateFlipType rfType); | ||
| 53 | |||
| 54 | extern GdiplusStartup_Proc fn_GdiplusStartup; | ||
| 55 | extern GdiplusShutdown_Proc fn_GdiplusShutdown; | ||
| 56 | extern GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; | ||
| 57 | extern GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; | ||
| 58 | extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; | ||
| 59 | extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; | ||
| 60 | extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; | ||
| 61 | extern GdipImageGetFrameDimensionsList_Proc fn_GdipImageGetFrameDimensionsList; | ||
| 62 | extern GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount; | ||
| 63 | extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; | ||
| 64 | extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; | ||
| 65 | extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; | ||
| 66 | extern GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; | ||
| 67 | extern GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; | ||
| 68 | extern GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; | ||
| 69 | extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; | ||
| 70 | extern SHCreateMemStream_Proc fn_SHCreateMemStream; | ||
| 71 | extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; | ||
| 72 | extern GdipDisposeImage_Proc fn_GdipDisposeImage; | ||
| 73 | extern GdipGetImageHeight_Proc fn_GdipGetImageHeight; | ||
| 74 | extern GdipGetImageWidth_Proc fn_GdipGetImageWidth; | ||
| 75 | extern GdipGetImageEncodersSize_Proc fn_GdipGetImageEncodersSize; | ||
| 76 | extern GdipGetImageEncoders_Proc fn_GdipGetImageEncoders; | ||
| 77 | extern GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile; | ||
| 78 | extern GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail; | ||
| 79 | extern GdipSaveImageToFile_Proc fn_GdipSaveImageToFile; | ||
| 80 | extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip; | ||
| 81 | |||
| 82 | # undef GdiplusStartup | ||
| 83 | # undef GdiplusShutdown | ||
| 84 | # undef GdipGetPropertyItemSize | ||
| 85 | # undef GdipGetPropertyItem | ||
| 86 | # undef GdipImageGetFrameDimensionsCount | ||
| 87 | # undef GdipImageGetFrameDimensionsList | ||
| 88 | # undef GdipImageGetFrameCount | ||
| 89 | # undef GdipImageSelectActiveFrame | ||
| 90 | # undef GdipCreateBitmapFromFile | ||
| 91 | # undef GdipCreateBitmapFromStream | ||
| 92 | # undef GdipCreateBitmapFromScan0 | ||
| 93 | # undef GdipCreateBitmapFromHBITMAP | ||
| 94 | # undef GdipCreateFromHDC | ||
| 95 | # undef GdipDrawImageRectRectI | ||
| 96 | # undef GdipSetInterpolationMode | ||
| 97 | # undef GdipDeleteGraphics | ||
| 98 | # undef SHCreateMemStream | ||
| 99 | # undef GdipCreateHBITMAPFromBitmap | ||
| 100 | # undef GdipDisposeImage | ||
| 101 | # undef GdipGetImageHeight | ||
| 102 | # undef GdipGetImageWidth | ||
| 103 | # undef GdipGetImageEncodersSize | ||
| 104 | # undef GdipGetImageEncoders | ||
| 105 | # undef GdipLoadImageFromFile | ||
| 106 | # undef GdipGetImageThumbnail | ||
| 107 | # undef GdipSaveImageToFile | ||
| 108 | # undef GdipSaveImageRotateFlip | ||
| 109 | |||
| 110 | # define GdiplusStartup fn_GdiplusStartup | ||
| 111 | # define GdiplusShutdown fn_GdiplusShutdown | ||
| 112 | # define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize | ||
| 113 | # define GdipGetPropertyItem fn_GdipGetPropertyItem | ||
| 114 | # define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount | ||
| 115 | # define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList | ||
| 116 | # define GdipImageGetFrameCount fn_GdipImageGetFrameCount | ||
| 117 | # define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame | ||
| 118 | # define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile | ||
| 119 | # define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream | ||
| 120 | # define GdipCreateBitmapFromScan0 fn_GdipCreateBitmapFromScan0 | ||
| 121 | # define GdipCreateBitmapFromHBITMAP fn_GdipCreateBitmapFromHBITMAP | ||
| 122 | # define GdipCreateFromHDC fn_GdipCreateFromHDC | ||
| 123 | # define GdipDrawImageRectRectI fn_GdipDrawImageRectRectI | ||
| 124 | # define GdipSetInterpolationMode fn_GdipSetInterpolationMode | ||
| 125 | # define GdipDeleteGraphics fn_GdipDeleteGraphics | ||
| 126 | # define SHCreateMemStream fn_SHCreateMemStream | ||
| 127 | # define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap | ||
| 128 | # define GdipDisposeImage fn_GdipDisposeImage | ||
| 129 | # define GdipGetImageHeight fn_GdipGetImageHeight | ||
| 130 | # define GdipGetImageWidth fn_GdipGetImageWidth | ||
| 131 | # define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize | ||
| 132 | # define GdipGetImageEncoders fn_GdipGetImageEncoders | ||
| 133 | # define GdipLoadImageFromFile fn_GdipLoadImageFromFile | ||
| 134 | # define GdipGetImageThumbnail fn_GdipGetImageThumbnail | ||
| 135 | # define GdipSaveImageToFile fn_GdipSaveImageToFile | ||
| 136 | # define GdipImageRotateFlip fn_GdipImageRotateFlip | ||
| 137 | #endif | ||
| 138 | |||
| 139 | int w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid); | ||
diff --git a/src/w32gui.h b/src/w32gui.h index 739a790911e..26565dcae6b 100644 --- a/src/w32gui.h +++ b/src/w32gui.h | |||
| @@ -45,7 +45,9 @@ struct image; | |||
| 45 | extern int w32_load_image (struct frame *f, struct image *img, | 45 | extern int w32_load_image (struct frame *f, struct image *img, |
| 46 | Lisp_Object spec_file, Lisp_Object spec_data); | 46 | Lisp_Object spec_file, Lisp_Object spec_data); |
| 47 | extern bool w32_can_use_native_image_api (Lisp_Object); | 47 | extern bool w32_can_use_native_image_api (Lisp_Object); |
| 48 | extern bool w32_gdiplus_startup (void); | ||
| 48 | extern void w32_gdiplus_shutdown (void); | 49 | extern void w32_gdiplus_shutdown (void); |
| 50 | |||
| 49 | extern size_t w32_image_size (Emacs_Pixmap); | 51 | extern size_t w32_image_size (Emacs_Pixmap); |
| 50 | 52 | ||
| 51 | #define FACE_DEFAULT (~0) | 53 | #define FACE_DEFAULT (~0) |
diff --git a/src/w32image.c b/src/w32image.c index 359a4fa3a72..da4d6843ba9 100644 --- a/src/w32image.c +++ b/src/w32image.c | |||
| @@ -38,46 +38,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 38 | #include "frame.h" | 38 | #include "frame.h" |
| 39 | #include "coding.h" | 39 | #include "coding.h" |
| 40 | 40 | ||
| 41 | #include "w32gdiplus.h" | ||
| 41 | #ifdef WINDOWSNT | 42 | #ifdef WINDOWSNT |
| 42 | |||
| 43 | typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc) | ||
| 44 | (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *); | ||
| 45 | typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR); | ||
| 46 | typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc) | ||
| 47 | (GpImage *, PROPID, UINT *); | ||
| 48 | typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc) | ||
| 49 | (GpImage *, PROPID, UINT, PropertyItem *); | ||
| 50 | typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc) | ||
| 51 | (GpImage *, UINT *); | ||
| 52 | typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc) | ||
| 53 | (GpImage *, GUID *, UINT); | ||
| 54 | typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc) | ||
| 55 | (GpImage *, GDIPCONST GUID *, UINT *); | ||
| 56 | typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc) | ||
| 57 | (GpImage*, GDIPCONST GUID *, UINT); | ||
| 58 | typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc) | ||
| 59 | (WCHAR *, GpBitmap **); | ||
| 60 | typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc) | ||
| 61 | (IStream *, GpBitmap **); | ||
| 62 | typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT); | ||
| 63 | typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc) | ||
| 64 | (GpBitmap *, HBITMAP *, ARGB); | ||
| 65 | typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *); | ||
| 66 | typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *); | ||
| 67 | typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *); | ||
| 68 | typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *); | ||
| 69 | typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc) | ||
| 70 | (UINT, UINT, ImageCodecInfo *); | ||
| 71 | typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc) | ||
| 72 | (GDIPCONST WCHAR *,GpImage **); | ||
| 73 | typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc) | ||
| 74 | (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *); | ||
| 75 | typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc) | ||
| 76 | (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *, | ||
| 77 | GDIPCONST EncoderParameters *); | ||
| 78 | |||
| 79 | GdiplusStartup_Proc fn_GdiplusStartup; | 43 | GdiplusStartup_Proc fn_GdiplusStartup; |
| 80 | GdiplusShutdown_Proc fn_GdiplusShutdown; | 44 | GdiplusShutdown_Proc fn_GdiplusShutdown; |
| 45 | GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; | ||
| 46 | GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; | ||
| 81 | GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; | 47 | GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; |
| 82 | GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; | 48 | GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; |
| 83 | GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; | 49 | GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; |
| @@ -86,8 +52,12 @@ GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount; | |||
| 86 | GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; | 52 | GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; |
| 87 | GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; | 53 | GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; |
| 88 | GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; | 54 | GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; |
| 55 | GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; | ||
| 89 | SHCreateMemStream_Proc fn_SHCreateMemStream; | 56 | SHCreateMemStream_Proc fn_SHCreateMemStream; |
| 90 | GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; | 57 | GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; |
| 58 | GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; | ||
| 59 | GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; | ||
| 60 | GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; | ||
| 91 | GdipDisposeImage_Proc fn_GdipDisposeImage; | 61 | GdipDisposeImage_Proc fn_GdipDisposeImage; |
| 92 | GdipGetImageHeight_Proc fn_GdipGetImageHeight; | 62 | GdipGetImageHeight_Proc fn_GdipGetImageHeight; |
| 93 | GdipGetImageWidth_Proc fn_GdipGetImageWidth; | 63 | GdipGetImageWidth_Proc fn_GdipGetImageWidth; |
| @@ -96,6 +66,7 @@ GdipGetImageEncoders_Proc fn_GdipGetImageEncoders; | |||
| 96 | GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile; | 66 | GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile; |
| 97 | GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail; | 67 | GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail; |
| 98 | GdipSaveImageToFile_Proc fn_GdipSaveImageToFile; | 68 | GdipSaveImageToFile_Proc fn_GdipSaveImageToFile; |
| 69 | GdipImageRotateFlip_Proc fn_GdipImageRotateFlip; | ||
| 99 | 70 | ||
| 100 | static bool | 71 | static bool |
| 101 | gdiplus_init (void) | 72 | gdiplus_init (void) |
| @@ -114,6 +85,14 @@ gdiplus_init (void) | |||
| 114 | get_proc_addr (gdiplus_lib, "GdiplusShutdown"); | 85 | get_proc_addr (gdiplus_lib, "GdiplusShutdown"); |
| 115 | if (!fn_GdiplusShutdown) | 86 | if (!fn_GdiplusShutdown) |
| 116 | return false; | 87 | return false; |
| 88 | fn_GdipCreateFromHDC = (GdipCreateFromHDC_Proc) | ||
| 89 | get_proc_addr (gdiplus_lib, "GdipCreateFromHDC"); | ||
| 90 | if (!fn_GdipCreateFromHDC) | ||
| 91 | return false; | ||
| 92 | fn_GdipDeleteGraphics = (GdipDeleteGraphics_Proc) | ||
| 93 | get_proc_addr (gdiplus_lib, "GdipDeleteGraphics"); | ||
| 94 | if (!fn_GdipDeleteGraphics) | ||
| 95 | return false; | ||
| 117 | fn_GdipGetPropertyItemSize = (GdipGetPropertyItemSize_Proc) | 96 | fn_GdipGetPropertyItemSize = (GdipGetPropertyItemSize_Proc) |
| 118 | get_proc_addr (gdiplus_lib, "GdipGetPropertyItemSize"); | 97 | get_proc_addr (gdiplus_lib, "GdipGetPropertyItemSize"); |
| 119 | if (!fn_GdipGetPropertyItemSize) | 98 | if (!fn_GdipGetPropertyItemSize) |
| @@ -146,10 +125,26 @@ gdiplus_init (void) | |||
| 146 | get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream"); | 125 | get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream"); |
| 147 | if (!fn_GdipCreateBitmapFromStream) | 126 | if (!fn_GdipCreateBitmapFromStream) |
| 148 | return false; | 127 | return false; |
| 128 | fn_GdipCreateBitmapFromScan0 = (GdipCreateBitmapFromScan0_Proc) | ||
| 129 | get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromScan0"); | ||
| 130 | if (!fn_GdipCreateBitmapFromScan0) | ||
| 131 | return false; | ||
| 149 | fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc) | 132 | fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc) |
| 150 | get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap"); | 133 | get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap"); |
| 151 | if (!fn_GdipCreateHBITMAPFromBitmap) | 134 | if (!fn_GdipCreateHBITMAPFromBitmap) |
| 152 | return false; | 135 | return false; |
| 136 | fn_GdipCreateBitmapFromHBITMAP = (GdipCreateBitmapFromHBITMAP_Proc) | ||
| 137 | get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromHBITMAP"); | ||
| 138 | if (!fn_GdipCreateBitmapFromHBITMAP) | ||
| 139 | return false; | ||
| 140 | fn_GdipDrawImageRectRectI = (GdipDrawImageRectRectI_Proc) | ||
| 141 | get_proc_addr (gdiplus_lib, "GdipDrawImageRectRectI"); | ||
| 142 | if (!fn_GdipDrawImageRectRectI) | ||
| 143 | return false; | ||
| 144 | fn_GdipSetInterpolationMode = (GdipSetInterpolationMode_Proc) | ||
| 145 | get_proc_addr (gdiplus_lib, "GdipSetInterpolationMode"); | ||
| 146 | if (!fn_GdipSetInterpolationMode) | ||
| 147 | return false; | ||
| 153 | fn_GdipDisposeImage = (GdipDisposeImage_Proc) | 148 | fn_GdipDisposeImage = (GdipDisposeImage_Proc) |
| 154 | get_proc_addr (gdiplus_lib, "GdipDisposeImage"); | 149 | get_proc_addr (gdiplus_lib, "GdipDisposeImage"); |
| 155 | if (!fn_GdipDisposeImage) | 150 | if (!fn_GdipDisposeImage) |
| @@ -196,52 +191,14 @@ gdiplus_init (void) | |||
| 196 | get_proc_addr (gdiplus_lib, "GdipSaveImageToFile"); | 191 | get_proc_addr (gdiplus_lib, "GdipSaveImageToFile"); |
| 197 | if (!fn_GdipSaveImageToFile) | 192 | if (!fn_GdipSaveImageToFile) |
| 198 | return false; | 193 | return false; |
| 194 | fn_GdipImageRotateFlip = (GdipImageRotateFlip_Proc) | ||
| 195 | get_proc_addr (gdiplus_lib, "GdipImageRotateFlip"); | ||
| 196 | if (!fn_GdipImageRotateFlip) | ||
| 197 | return false; | ||
| 199 | 198 | ||
| 200 | return true; | 199 | return true; |
| 201 | } | 200 | } |
| 202 | 201 | ||
| 203 | # undef GdiplusStartup | ||
| 204 | # undef GdiplusShutdown | ||
| 205 | # undef GdipGetPropertyItemSize | ||
| 206 | # undef GdipGetPropertyItem | ||
| 207 | # undef GdipImageGetFrameDimensionsCount | ||
| 208 | # undef GdipImageGetFrameDimensionsList | ||
| 209 | # undef GdipImageGetFrameCount | ||
| 210 | # undef GdipImageSelectActiveFrame | ||
| 211 | # undef GdipCreateBitmapFromFile | ||
| 212 | # undef GdipCreateBitmapFromStream | ||
| 213 | # undef SHCreateMemStream | ||
| 214 | # undef GdipCreateHBITMAPFromBitmap | ||
| 215 | # undef GdipDisposeImage | ||
| 216 | # undef GdipGetImageHeight | ||
| 217 | # undef GdipGetImageWidth | ||
| 218 | # undef GdipGetImageEncodersSize | ||
| 219 | # undef GdipGetImageEncoders | ||
| 220 | # undef GdipLoadImageFromFile | ||
| 221 | # undef GdipGetImageThumbnail | ||
| 222 | # undef GdipSaveImageToFile | ||
| 223 | |||
| 224 | # define GdiplusStartup fn_GdiplusStartup | ||
| 225 | # define GdiplusShutdown fn_GdiplusShutdown | ||
| 226 | # define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize | ||
| 227 | # define GdipGetPropertyItem fn_GdipGetPropertyItem | ||
| 228 | # define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount | ||
| 229 | # define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList | ||
| 230 | # define GdipImageGetFrameCount fn_GdipImageGetFrameCount | ||
| 231 | # define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame | ||
| 232 | # define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile | ||
| 233 | # define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream | ||
| 234 | # define SHCreateMemStream fn_SHCreateMemStream | ||
| 235 | # define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap | ||
| 236 | # define GdipDisposeImage fn_GdipDisposeImage | ||
| 237 | # define GdipGetImageHeight fn_GdipGetImageHeight | ||
| 238 | # define GdipGetImageWidth fn_GdipGetImageWidth | ||
| 239 | # define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize | ||
| 240 | # define GdipGetImageEncoders fn_GdipGetImageEncoders | ||
| 241 | # define GdipLoadImageFromFile fn_GdipLoadImageFromFile | ||
| 242 | # define GdipGetImageThumbnail fn_GdipGetImageThumbnail | ||
| 243 | # define GdipSaveImageToFile fn_GdipSaveImageToFile | ||
| 244 | |||
| 245 | #endif /* WINDOWSNT */ | 202 | #endif /* WINDOWSNT */ |
| 246 | 203 | ||
| 247 | static int gdip_initialized; | 204 | static int gdip_initialized; |
| @@ -252,8 +209,8 @@ static GdiplusStartupOutput output; | |||
| 252 | 209 | ||
| 253 | 210 | ||
| 254 | /* Initialize GDI+, return true if successful. */ | 211 | /* Initialize GDI+, return true if successful. */ |
| 255 | static bool | 212 | bool |
| 256 | gdiplus_startup (void) | 213 | w32_gdiplus_startup (void) |
| 257 | { | 214 | { |
| 258 | GpStatus status; | 215 | GpStatus status; |
| 259 | 216 | ||
| @@ -305,7 +262,7 @@ w32_can_use_native_image_api (Lisp_Object type) | |||
| 305 | But we don't yet support these in image.c. */ | 262 | But we don't yet support these in image.c. */ |
| 306 | return false; | 263 | return false; |
| 307 | } | 264 | } |
| 308 | return gdiplus_startup (); | 265 | return w32_gdiplus_startup (); |
| 309 | } | 266 | } |
| 310 | 267 | ||
| 311 | enum PropertyItem_type { | 268 | enum PropertyItem_type { |
| @@ -549,8 +506,8 @@ static struct thumb_type_data thumb_types [] = | |||
| 549 | }; | 506 | }; |
| 550 | 507 | ||
| 551 | 508 | ||
| 552 | static int | 509 | int |
| 553 | get_encoder_clsid (const char *type, CLSID *clsid) | 510 | w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid) |
| 554 | { | 511 | { |
| 555 | /* A simple cache based on the assumptions that many thumbnails will | 512 | /* A simple cache based on the assumptions that many thumbnails will |
| 556 | be generated using the same TYPE. */ | 513 | be generated using the same TYPE. */ |
| @@ -625,7 +582,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) | |||
| 625 | 582 | ||
| 626 | if (!gdiplus_started) | 583 | if (!gdiplus_started) |
| 627 | { | 584 | { |
| 628 | if (!gdiplus_startup ()) | 585 | if (!w32_gdiplus_startup ()) |
| 629 | return Qnil; | 586 | return Qnil; |
| 630 | } | 587 | } |
| 631 | 588 | ||
| @@ -649,7 +606,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) | |||
| 649 | CLSID thumb_clsid; | 606 | CLSID thumb_clsid; |
| 650 | if (status == Ok | 607 | if (status == Ok |
| 651 | /* Get the GUID of the TYPE's encoder. */ | 608 | /* Get the GUID of the TYPE's encoder. */ |
| 652 | && get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0) | 609 | && w32_gdip_get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0) |
| 653 | { | 610 | { |
| 654 | /* Save the thumbnail image to a file of specified TYPE. */ | 611 | /* Save the thumbnail image to a file of specified TYPE. */ |
| 655 | wchar_t thumb_file_w[MAX_PATH]; | 612 | wchar_t thumb_file_w[MAX_PATH]; |
diff --git a/src/w32menu.c b/src/w32menu.c index c3d147841b6..92b4b9c6d3c 100644 --- a/src/w32menu.c +++ b/src/w32menu.c | |||
| @@ -186,6 +186,11 @@ task_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, | |||
| 186 | Lisp_Object | 186 | Lisp_Object |
| 187 | w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) | 187 | w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) |
| 188 | { | 188 | { |
| 189 | #ifdef NTGUI_UNICODE | ||
| 190 | typedef int (WINAPI *MultiByteToWideChar_Proc)(UINT,DWORD,LPCSTR,int, | ||
| 191 | LPWSTR, int); | ||
| 192 | static MultiByteToWideChar_Proc pMultiByteToWideChar = MultiByteToWideChar; | ||
| 193 | #endif /* NTGUI_UNICODE */ | ||
| 189 | check_window_system (f); | 194 | check_window_system (f); |
| 190 | 195 | ||
| 191 | if (task_dialog_indirect) | 196 | if (task_dialog_indirect) |
diff --git a/src/w32select.c b/src/w32select.c index 006bf408b47..646c8faf634 100644 --- a/src/w32select.c +++ b/src/w32select.c | |||
| @@ -73,12 +73,22 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 73 | */ | 73 | */ |
| 74 | 74 | ||
| 75 | #include <config.h> | 75 | #include <config.h> |
| 76 | #include <windows.h> | ||
| 77 | #include <wingdi.h> | ||
| 78 | #include <wtypes.h> | ||
| 79 | #include <gdiplus.h> | ||
| 80 | #ifndef CF_DIBV5 | ||
| 81 | # define CF_DIBV5 17 | ||
| 82 | # undef CF_MAX | ||
| 83 | # define CF_MAX 18 | ||
| 84 | #endif | ||
| 76 | #include "lisp.h" | 85 | #include "lisp.h" |
| 77 | #include "w32common.h" /* os_subtype */ | 86 | #include "w32common.h" /* os_subtype */ |
| 78 | #include "w32term.h" /* for all of the w32 includes */ | 87 | #include "w32term.h" /* for all of the w32 includes */ |
| 79 | #include "w32select.h" | 88 | #include "w32select.h" |
| 80 | #include "blockinput.h" | 89 | #include "blockinput.h" |
| 81 | #include "coding.h" | 90 | #include "coding.h" |
| 91 | #include "w32gdiplus.h" | ||
| 82 | 92 | ||
| 83 | #ifdef CYGWIN | 93 | #ifdef CYGWIN |
| 84 | #include <string.h> | 94 | #include <string.h> |
| @@ -787,6 +797,170 @@ DEFUN ("w32-set-clipboard-data", Fw32_set_clipboard_data, | |||
| 787 | return (ok ? string : Qnil); | 797 | return (ok ? string : Qnil); |
| 788 | } | 798 | } |
| 789 | 799 | ||
| 800 | /* Xlib-like names for standard Windows clipboard data formats. | ||
| 801 | They are in upper-case to mimic xselect.c. A couple of the names | ||
| 802 | were changed to be more like their X counterparts. */ | ||
| 803 | static const char *stdfmt_name[] = { | ||
| 804 | "UNDEFINED", | ||
| 805 | "STRING", | ||
| 806 | "BITMAP", | ||
| 807 | "METAFILE", | ||
| 808 | "SYMLINK", | ||
| 809 | "DIF", | ||
| 810 | "TIFF", | ||
| 811 | "OEM_STRING", | ||
| 812 | "DIB", | ||
| 813 | "PALETTE", | ||
| 814 | "PENDATA", | ||
| 815 | "RIFF", | ||
| 816 | "WAVE", | ||
| 817 | "UTF8_STRING", | ||
| 818 | "ENHMETAFILE", | ||
| 819 | "FILE_NAMES", /* DND */ | ||
| 820 | "LOCALE", /* not used */ | ||
| 821 | "DIBV5" | ||
| 822 | }; | ||
| 823 | |||
| 824 | /* Must be called with block_input() active. */ | ||
| 825 | static bool | ||
| 826 | convert_dibv5_to_png (char *data, int size, char *temp_file) | ||
| 827 | { | ||
| 828 | #ifdef HAVE_NATIVE_IMAGE_API | ||
| 829 | CLSID clsid_png; | ||
| 830 | |||
| 831 | if (!w32_gdiplus_startup () | ||
| 832 | || !w32_gdip_get_encoder_clsid ("png", &clsid_png)) | ||
| 833 | return false; | ||
| 834 | |||
| 835 | BITMAPV5HEADER *bmi = (void *) data; | ||
| 836 | int stride = bmi->bV5SizeImage / bmi->bV5Height; | ||
| 837 | long offset = bmi->bV5Size + bmi->bV5ClrUsed * sizeof (RGBQUAD); | ||
| 838 | if (bmi->bV5Compression == BI_BITFIELDS) | ||
| 839 | offset += 12; | ||
| 840 | BYTE *scan0 = data + offset; | ||
| 841 | |||
| 842 | GpBitmap *bitmap = NULL; | ||
| 843 | |||
| 844 | GpStatus status | ||
| 845 | = GdipCreateBitmapFromScan0 (bmi->bV5Width, bmi->bV5Height, stride, | ||
| 846 | PixelFormat32bppARGB, scan0, &bitmap); | ||
| 847 | |||
| 848 | if (status != Ok) | ||
| 849 | return false; | ||
| 850 | |||
| 851 | /* The bitmap comes upside down. */ | ||
| 852 | GdipImageRotateFlip (bitmap, RotateNoneFlipY); | ||
| 853 | |||
| 854 | WCHAR wide_filename[MAX_PATH]; | ||
| 855 | filename_to_utf16 (temp_file, wide_filename); | ||
| 856 | |||
| 857 | status = GdipSaveImageToFile (bitmap, wide_filename, &clsid_png, NULL); | ||
| 858 | GdipDisposeImage (bitmap); | ||
| 859 | if (status != Ok) | ||
| 860 | return false; | ||
| 861 | return true; | ||
| 862 | #else /* !HAVE_NATIVE_IMAGE_API */ | ||
| 863 | return false; | ||
| 864 | #endif | ||
| 865 | } | ||
| 866 | |||
| 867 | static int | ||
| 868 | get_clipboard_format_name (int format_index, char *name) | ||
| 869 | { | ||
| 870 | *name = 0; | ||
| 871 | format_index = EnumClipboardFormats (format_index); | ||
| 872 | if (format_index == 0) | ||
| 873 | return 0; | ||
| 874 | if (format_index < CF_MAX) | ||
| 875 | strcpy (name, stdfmt_name[format_index]); | ||
| 876 | GetClipboardFormatName (format_index, name, 256); | ||
| 877 | return format_index; | ||
| 878 | } | ||
| 879 | |||
| 880 | DEFUN ("w32--get-clipboard-data-media", Fw32__get_clipboard_data_media, | ||
| 881 | Sw32__get_clipboard_data_media, 3, 3, 0, | ||
| 882 | doc: /* Gets media (not plain text) clipboard data in one of the given formats. | ||
| 883 | |||
| 884 | FORMATS is a list of formats. | ||
| 885 | TEMP-FILE-IN is the name of the file to store the data. | ||
| 886 | |||
| 887 | Elements in FORMATS are symbols naming a format, such a image/png, or | ||
| 888 | image/jpeg. For compatibility with X systems, some conventional | ||
| 889 | format names are translated to equivalent MIME types, as configured with | ||
| 890 | the variable 'w32--selection-target-translations'. | ||
| 891 | |||
| 892 | The file named in TEMP-FILE-IN must be created by the caller, and also | ||
| 893 | deleted if required. | ||
| 894 | |||
| 895 | Returns nil it there is no such format, or something failed. | ||
| 896 | If it returns t, then the caller should read the file to get the data. | ||
| 897 | If it returns a string, then that is the data and the file is not used. | ||
| 898 | |||
| 899 | When returning a string, it will be unibyte if IS-TEXTUAL is nil (the | ||
| 900 | content is binary data). */) | ||
| 901 | (Lisp_Object formats, Lisp_Object temp_file_in, Lisp_Object is_textual) | ||
| 902 | { | ||
| 903 | CHECK_LIST (formats); | ||
| 904 | CHECK_STRING (temp_file_in); | ||
| 905 | |||
| 906 | temp_file_in = Fexpand_file_name (temp_file_in, Qnil); | ||
| 907 | char *temp_file = SSDATA (ENCODE_FILE (temp_file_in)); | ||
| 908 | |||
| 909 | Lisp_Object result = Qnil; | ||
| 910 | |||
| 911 | block_input(); | ||
| 912 | if (!OpenClipboard (NULL)) | ||
| 913 | { | ||
| 914 | unblock_input(); | ||
| 915 | return Qnil; | ||
| 916 | } | ||
| 917 | |||
| 918 | for (int format_index = 0;;) | ||
| 919 | { | ||
| 920 | static char name[256]; | ||
| 921 | format_index = get_clipboard_format_name (format_index, name); | ||
| 922 | if (format_index == 0) | ||
| 923 | break; | ||
| 924 | |||
| 925 | /* If name doesn't match any of the formats, try the next format. */ | ||
| 926 | bool match = false; | ||
| 927 | for (Lisp_Object tail = formats; CONSP (tail); tail = XCDR (tail)) | ||
| 928 | if (strcmp (name, SSDATA (SYMBOL_NAME (XCAR (tail)))) == 0) | ||
| 929 | match = true; | ||
| 930 | if (!match) | ||
| 931 | continue; | ||
| 932 | |||
| 933 | /* Of the standard formats, only DIBV5 is supported. */ | ||
| 934 | if (format_index < CF_MAX && format_index != CF_DIBV5) | ||
| 935 | continue; | ||
| 936 | |||
| 937 | /* Found the format. */ | ||
| 938 | HANDLE d = GetClipboardData (format_index); | ||
| 939 | if (!d) | ||
| 940 | break; | ||
| 941 | int size = GlobalSize (d); | ||
| 942 | char *data = GlobalLock (d); | ||
| 943 | if (!data) | ||
| 944 | break; | ||
| 945 | if (strcmp (name, "DIBV5") == 0) | ||
| 946 | { | ||
| 947 | if (convert_dibv5_to_png (data, size, temp_file)) | ||
| 948 | result = Qt; | ||
| 949 | } | ||
| 950 | else | ||
| 951 | { | ||
| 952 | if (NILP (is_textual)) | ||
| 953 | result = make_unibyte_string (data, size); | ||
| 954 | else | ||
| 955 | result = make_string (data, size); | ||
| 956 | } | ||
| 957 | GlobalUnlock (d); | ||
| 958 | break; | ||
| 959 | } | ||
| 960 | CloseClipboard (); | ||
| 961 | unblock_input (); | ||
| 962 | return result; | ||
| 963 | } | ||
| 790 | 964 | ||
| 791 | DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data, | 965 | DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data, |
| 792 | Sw32_get_clipboard_data, 0, 1, 0, | 966 | Sw32_get_clipboard_data, 0, 1, 0, |
| @@ -1069,29 +1243,6 @@ for `CLIPBOARD'. The return value is a vector of symbols, each symbol | |||
| 1069 | representing a data format that is currently available in the clipboard. */) | 1243 | representing a data format that is currently available in the clipboard. */) |
| 1070 | (Lisp_Object selection, Lisp_Object terminal) | 1244 | (Lisp_Object selection, Lisp_Object terminal) |
| 1071 | { | 1245 | { |
| 1072 | /* Xlib-like names for standard Windows clipboard data formats. | ||
| 1073 | They are in upper-case to mimic xselect.c. A couple of the names | ||
| 1074 | were changed to be more like their X counterparts. */ | ||
| 1075 | static const char *stdfmt_name[] = { | ||
| 1076 | "UNDEFINED", | ||
| 1077 | "STRING", | ||
| 1078 | "BITMAP", | ||
| 1079 | "METAFILE", | ||
| 1080 | "SYMLINK", | ||
| 1081 | "DIF", | ||
| 1082 | "TIFF", | ||
| 1083 | "OEM_STRING", | ||
| 1084 | "DIB", | ||
| 1085 | "PALETTE", | ||
| 1086 | "PENDATA", | ||
| 1087 | "RIFF", | ||
| 1088 | "WAVE", | ||
| 1089 | "UTF8_STRING", | ||
| 1090 | "ENHMETAFILE", | ||
| 1091 | "FILE_NAMES", /* DND */ | ||
| 1092 | "LOCALE", /* not used */ | ||
| 1093 | "DIBV5" | ||
| 1094 | }; | ||
| 1095 | CHECK_SYMBOL (selection); | 1246 | CHECK_SYMBOL (selection); |
| 1096 | 1247 | ||
| 1097 | /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check | 1248 | /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check |
| @@ -1166,6 +1317,7 @@ syms_of_w32select (void) | |||
| 1166 | { | 1317 | { |
| 1167 | defsubr (&Sw32_set_clipboard_data); | 1318 | defsubr (&Sw32_set_clipboard_data); |
| 1168 | defsubr (&Sw32_get_clipboard_data); | 1319 | defsubr (&Sw32_get_clipboard_data); |
| 1320 | defsubr (&Sw32__get_clipboard_data_media); | ||
| 1169 | defsubr (&Sw32_selection_exists_p); | 1321 | defsubr (&Sw32_selection_exists_p); |
| 1170 | defsubr (&Sw32_selection_targets); | 1322 | defsubr (&Sw32_selection_targets); |
| 1171 | 1323 | ||
diff --git a/src/w32term.c b/src/w32term.c index e41d2fa3c34..aceb721f92b 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -24,6 +24,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 24 | #include "blockinput.h" | 24 | #include "blockinput.h" |
| 25 | #include "w32term.h" | 25 | #include "w32term.h" |
| 26 | #include "w32common.h" /* for OS version info */ | 26 | #include "w32common.h" /* for OS version info */ |
| 27 | #include <wtypes.h> | ||
| 28 | #include <gdiplus.h> | ||
| 29 | #include "w32gdiplus.h" | ||
| 27 | 30 | ||
| 28 | #include <ctype.h> | 31 | #include <ctype.h> |
| 29 | #include <errno.h> | 32 | #include <errno.h> |
| @@ -2106,16 +2109,53 @@ w32_draw_image_foreground (struct glyph_string *s) | |||
| 2106 | compat_hdc, s->slice.x, s->slice.y, SRCCOPY); | 2109 | compat_hdc, s->slice.x, s->slice.y, SRCCOPY); |
| 2107 | else | 2110 | else |
| 2108 | { | 2111 | { |
| 2109 | int pmode = 0; | 2112 | #ifdef HAVE_NATIVE_IMAGE_API |
| 2110 | /* Windows 9X doesn't support HALFTONE. */ | 2113 | if (s->img->smoothing && w32_gdiplus_startup ()) |
| 2111 | if (os_subtype == OS_SUBTYPE_NT | 2114 | { |
| 2112 | && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) | 2115 | GpGraphics *graphics; |
| 2113 | SetBrushOrgEx (s->hdc, 0, 0, NULL); | 2116 | if (GdipCreateFromHDC (s->hdc, &graphics) == Ok) |
| 2114 | StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, | 2117 | { |
| 2115 | compat_hdc, orig_slice_x, orig_slice_y, | 2118 | GpBitmap *gp_bitmap; |
| 2116 | orig_slice_width, orig_slice_height, SRCCOPY); | 2119 | /* Can't create a GpBitmap from a HBITMAP that was |
| 2117 | if (pmode) | 2120 | ever selected into a DC, so we need to copy. */ |
| 2118 | SetStretchBltMode (s->hdc, pmode); | 2121 | HBITMAP copy |
| 2122 | = CopyImage (GetCurrentObject (compat_hdc, OBJ_BITMAP), | ||
| 2123 | IMAGE_BITMAP, 0, 0, 0); | ||
| 2124 | if (GdipCreateBitmapFromHBITMAP (copy, NULL, | ||
| 2125 | &gp_bitmap) == Ok) | ||
| 2126 | { | ||
| 2127 | GdipSetInterpolationMode (graphics, | ||
| 2128 | InterpolationModeHighQualityBilinear); | ||
| 2129 | GdipDrawImageRectRectI (graphics, | ||
| 2130 | gp_bitmap, x, y, | ||
| 2131 | s->slice.width, | ||
| 2132 | s->slice.height, | ||
| 2133 | orig_slice_x, | ||
| 2134 | orig_slice_y, | ||
| 2135 | orig_slice_width, | ||
| 2136 | orig_slice_height, | ||
| 2137 | UnitPixel, | ||
| 2138 | NULL, NULL, NULL); | ||
| 2139 | GdipDisposeImage (gp_bitmap); | ||
| 2140 | } | ||
| 2141 | DeleteObject (copy); | ||
| 2142 | GdipDeleteGraphics (graphics); | ||
| 2143 | } | ||
| 2144 | } | ||
| 2145 | else | ||
| 2146 | #endif | ||
| 2147 | { | ||
| 2148 | int pmode = 0; | ||
| 2149 | /* Windows 9X doesn't support HALFTONE. */ | ||
| 2150 | if (os_subtype == OS_SUBTYPE_NT | ||
| 2151 | && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) | ||
| 2152 | SetBrushOrgEx (s->hdc, 0, 0, NULL); | ||
| 2153 | StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, | ||
| 2154 | compat_hdc, orig_slice_x, orig_slice_y, | ||
| 2155 | orig_slice_width, orig_slice_height, SRCCOPY); | ||
| 2156 | if (pmode) | ||
| 2157 | SetStretchBltMode (s->hdc, pmode); | ||
| 2158 | } | ||
| 2119 | } | 2159 | } |
| 2120 | 2160 | ||
| 2121 | /* When the image has a mask, we can expect that at | 2161 | /* When the image has a mask, we can expect that at |
| @@ -5629,6 +5669,24 @@ w32_read_socket (struct terminal *terminal, | |||
| 5629 | } | 5669 | } |
| 5630 | break; | 5670 | break; |
| 5631 | 5671 | ||
| 5672 | case WM_EMACS_DRAGOVER: | ||
| 5673 | { | ||
| 5674 | f = w32_window_to_frame (dpyinfo, msg.msg.hwnd); | ||
| 5675 | if (!f) | ||
| 5676 | break; | ||
| 5677 | XSETFRAME (inev.frame_or_window, f); | ||
| 5678 | inev.kind = DRAG_N_DROP_EVENT; | ||
| 5679 | inev.code = 0; | ||
| 5680 | inev.timestamp = msg.msg.time; | ||
| 5681 | inev.modifiers = msg.dwModifiers; | ||
| 5682 | ScreenToClient (msg.msg.hwnd, &msg.msg.pt); | ||
| 5683 | XSETINT (inev.x, msg.msg.pt.x); | ||
| 5684 | XSETINT (inev.y, msg.msg.pt.y); | ||
| 5685 | /* This is a drag movement. */ | ||
| 5686 | inev.arg = Qnil; | ||
| 5687 | break; | ||
| 5688 | } | ||
| 5689 | |||
| 5632 | case WM_HSCROLL: | 5690 | case WM_HSCROLL: |
| 5633 | { | 5691 | { |
| 5634 | struct scroll_bar *bar = | 5692 | struct scroll_bar *bar = |
diff --git a/src/w32term.h b/src/w32term.h index 39e2262e2a8..cad9fcf8cb1 100644 --- a/src/w32term.h +++ b/src/w32term.h | |||
| @@ -711,8 +711,9 @@ do { \ | |||
| 711 | #define WM_EMACS_INPUT_READY (WM_EMACS_START + 24) | 711 | #define WM_EMACS_INPUT_READY (WM_EMACS_START + 24) |
| 712 | #define WM_EMACS_FILENOTIFY (WM_EMACS_START + 25) | 712 | #define WM_EMACS_FILENOTIFY (WM_EMACS_START + 25) |
| 713 | #define WM_EMACS_IME_STATUS (WM_EMACS_START + 26) | 713 | #define WM_EMACS_IME_STATUS (WM_EMACS_START + 26) |
| 714 | #define WM_EMACS_DROP (WM_EMACS_START + 27) | 714 | #define WM_EMACS_DRAGOVER (WM_EMACS_START + 27) |
| 715 | #define WM_EMACS_END (WM_EMACS_START + 28) | 715 | #define WM_EMACS_DROP (WM_EMACS_START + 28) |
| 716 | #define WM_EMACS_END (WM_EMACS_START + 29) | ||
| 716 | 717 | ||
| 717 | #define WND_FONTWIDTH_INDEX (0) | 718 | #define WND_FONTWIDTH_INDEX (0) |
| 718 | #define WND_LINEHEIGHT_INDEX (4) | 719 | #define WND_LINEHEIGHT_INDEX (4) |
diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index b77bf56b8cf..66d27b81b9e 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c | |||
| @@ -44,18 +44,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 44 | #include "pdumper.h" | 44 | #include "pdumper.h" |
| 45 | #include "w32common.h" | 45 | #include "w32common.h" |
| 46 | 46 | ||
| 47 | /* Extension of w32font_info used by Uniscribe and HarfBuzz backends. */ | ||
| 48 | struct uniscribe_font_info | ||
| 49 | { | ||
| 50 | struct w32font_info w32_font; | ||
| 51 | /* This is used by the Uniscribe backend as a pointer to the script | ||
| 52 | cache, and by the HarfBuzz backend as a pointer to a hb_font_t | ||
| 53 | object. */ | ||
| 54 | void *cache; | ||
| 55 | /* This is used by the HarfBuzz backend to store the font scale. */ | ||
| 56 | double scale; | ||
| 57 | }; | ||
| 58 | |||
| 59 | int uniscribe_available = 0; | 47 | int uniscribe_available = 0; |
| 60 | 48 | ||
| 61 | /* EnumFontFamiliesEx callback. */ | 49 | /* EnumFontFamiliesEx callback. */ |
| @@ -200,6 +188,8 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size) | |||
| 200 | 188 | ||
| 201 | /* Initialize the cache for this font. */ | 189 | /* Initialize the cache for this font. */ |
| 202 | uniscribe_font->cache = NULL; | 190 | uniscribe_font->cache = NULL; |
| 191 | uniscribe_font->dwrite_cache = NULL; | ||
| 192 | uniscribe_font->dwrite_skip_font = false; | ||
| 203 | 193 | ||
| 204 | /* Uniscribe and HarfBuzz backends use glyph indices. */ | 194 | /* Uniscribe and HarfBuzz backends use glyph indices. */ |
| 205 | uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX; | 195 | uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX; |
| @@ -221,6 +211,7 @@ uniscribe_close (struct font *font) | |||
| 221 | = (struct uniscribe_font_info *) font; | 211 | = (struct uniscribe_font_info *) font; |
| 222 | 212 | ||
| 223 | #ifdef HAVE_HARFBUZZ | 213 | #ifdef HAVE_HARFBUZZ |
| 214 | w32_dwrite_free_cached_face (uniscribe_font->dwrite_cache); | ||
| 224 | if (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver | 215 | if (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver |
| 225 | && uniscribe_font->cache) | 216 | && uniscribe_font->cache) |
| 226 | hb_font_destroy ((hb_font_t *) uniscribe_font->cache); | 217 | hb_font_destroy ((hb_font_t *) uniscribe_font->cache); |
| @@ -1372,6 +1363,17 @@ w32hb_encode_char (struct font *font, int c) | |||
| 1372 | struct uniscribe_font_info *uniscribe_font | 1363 | struct uniscribe_font_info *uniscribe_font |
| 1373 | = (struct uniscribe_font_info *) font; | 1364 | = (struct uniscribe_font_info *) font; |
| 1374 | eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver); | 1365 | eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver); |
| 1366 | |||
| 1367 | if (w32_use_direct_write (&uniscribe_font->w32_font)) | ||
| 1368 | { | ||
| 1369 | unsigned encoded = w32_dwrite_encode_char (font, c); | ||
| 1370 | |||
| 1371 | /* The call to w32_dwrite_encode_char may fail, disabling | ||
| 1372 | DirectWrite for this font. So check again. */ | ||
| 1373 | if (w32_use_direct_write (&uniscribe_font->w32_font)) | ||
| 1374 | return encoded; | ||
| 1375 | } | ||
| 1376 | |||
| 1375 | hb_font_t *hb_font = uniscribe_font->cache; | 1377 | hb_font_t *hb_font = uniscribe_font->cache; |
| 1376 | 1378 | ||
| 1377 | /* First time we use this font with HarfBuzz, create the hb_font_t | 1379 | /* First time we use this font with HarfBuzz, create the hb_font_t |
| @@ -1624,5 +1626,8 @@ syms_of_w32uniscribe_for_pdumper (void) | |||
| 1624 | harfbuzz_font_driver.combining_capability = hbfont_combining_capability; | 1626 | harfbuzz_font_driver.combining_capability = hbfont_combining_capability; |
| 1625 | harfbuzz_font_driver.begin_hb_font = w32hb_begin_font; | 1627 | harfbuzz_font_driver.begin_hb_font = w32hb_begin_font; |
| 1626 | register_font_driver (&harfbuzz_font_driver, NULL); | 1628 | register_font_driver (&harfbuzz_font_driver, NULL); |
| 1629 | |||
| 1630 | w32_initialize_direct_write (); | ||
| 1631 | |||
| 1627 | #endif /* HAVE_HARFBUZZ */ | 1632 | #endif /* HAVE_HARFBUZZ */ |
| 1628 | } | 1633 | } |
diff --git a/src/window.c b/src/window.c index 34968ac824f..7f157911685 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -6140,7 +6140,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 6140 | /* The last line was only partially visible, make it fully | 6140 | /* The last line was only partially visible, make it fully |
| 6141 | visible. */ | 6141 | visible. */ |
| 6142 | w->vscroll = (it.last_visible_y | 6142 | w->vscroll = (it.last_visible_y |
| 6143 | - it.current_y + it.max_ascent + it.max_descent); | 6143 | - (it.current_y + it.max_ascent + it.max_descent)); |
| 6144 | adjust_frame_glyphs (it.f); | 6144 | adjust_frame_glyphs (it.f); |
| 6145 | } | 6145 | } |
| 6146 | else | 6146 | else |
diff --git a/src/xdisp.c b/src/xdisp.c index 7d9dd6e8e85..3364c6870cf 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -4993,7 +4993,7 @@ face_before_or_after_it_pos (struct it *it, bool before_p) | |||
| 4993 | /* For composition, we must check the position after | 4993 | /* For composition, we must check the position after |
| 4994 | the composition. */ | 4994 | the composition. */ |
| 4995 | pos.charpos += it->cmp_it.nchars; | 4995 | pos.charpos += it->cmp_it.nchars; |
| 4996 | pos.bytepos += it->len; | 4996 | pos.bytepos += it->cmp_it.nbytes; |
| 4997 | } | 4997 | } |
| 4998 | else | 4998 | else |
| 4999 | INC_TEXT_POS (pos, it->multibyte_p); | 4999 | INC_TEXT_POS (pos, it->multibyte_p); |