aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGerd Möllmann2024-11-16 04:31:46 +0100
committerGerd Möllmann2024-11-16 04:31:46 +0100
commit36c81859f6c3d798fa1c1d9eb45cf730e0237e04 (patch)
tree3710ea1733b746f420836fc892b7a1e52b28cb66 /src
parentf62d70f52f4f6b7ed158d618bf790df21f171172 (diff)
parent29098a291f535c8e2be114171308169f025de43f (diff)
downloademacs-36c81859f6c3d798fa1c1d9eb45cf730e0237e04.tar.gz
emacs-36c81859f6c3d798fa1c1d9eb45cf730e0237e04.zip
Merge branch 'master' into scratch/tty-child-frames
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c13
-rw-r--r--src/charset.c3
-rw-r--r--src/data.c12
-rw-r--r--src/dispextern.h1
-rw-r--r--src/emacs.c1
-rw-r--r--src/fns.c23
-rw-r--r--src/ftcrfont.c11
-rw-r--r--src/image.c10
-rw-r--r--src/itree.c52
-rw-r--r--src/itree.h18
-rw-r--r--src/lread.c2
-rw-r--r--src/nsterm.m35
-rw-r--r--src/pdumper.c11
-rw-r--r--src/w32dwrite.c1110
-rw-r--r--src/w32fns.c38
-rw-r--r--src/w32font.c39
-rw-r--r--src/w32font.h31
-rw-r--r--src/w32gdiplus.h139
-rw-r--r--src/w32gui.h2
-rw-r--r--src/w32image.c129
-rw-r--r--src/w32menu.c5
-rw-r--r--src/w32select.c198
-rw-r--r--src/w32term.c78
-rw-r--r--src/w32term.h5
-rw-r--r--src/w32uniscribe.c29
-rw-r--r--src/window.c2
-rw-r--r--src/xdisp.c2
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;
111static void call_overlay_mod_hooks (Lisp_Object list, Lisp_Object overlay, 111static 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);
114static void reset_buffer_local_variables (struct buffer *, bool); 114static 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
1115static void 1116static void
1116reset_buffer_local_variables (struct buffer *b, bool permanent_too) 1117reset_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. */
758DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, 758DEFUN ("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
784DEFUN ("fmakunbound", Ffmakunbound, Sfmakunbound, 1, 1, 0, 784DEFUN ("fmakunbound", Ffmakunbound, Sfmakunbound, 1, 1, 0,
785 doc: /* Make SYMBOL's function definition be void. 785 doc: /* Make SYMBOL's function definition be nil.
786Return SYMBOL. 786Return SYMBOL.
787 787
788If a function definition is void, trying to call a function by that 788If a function definition is nil, trying to call a function by
789name will cause a `void-function' error. For more details, see Info 789that name will cause a `void-function' error. For more details, see
790node `(elisp) Function Cells'. 790Info node `(elisp) Function Cells'.
791 791
792See also `makunbound'. */) 792See also `makunbound'. */)
793 (register Lisp_Object symbol) 793 (register Lisp_Object symbol)
@@ -800,7 +800,7 @@ See also `makunbound'. */)
800} 800}
801 801
802DEFUN ("symbol-function", Fsymbol_function, Ssymbol_function, 1, 1, 0, 802DEFUN ("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 ();
diff --git a/src/fns.c b/src/fns.c
index 2de04d06519..ef6922c137b 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -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
2825static bool 2825static bool
2826internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, 2826internal_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
2988static bool
2989internal_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. */
2989static int 2996static int
2990bool_vector_cmp (Lisp_Object a, Lisp_Object b) 2997bool_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'. */
918static void 918static void
919itree_replace_child (struct itree_tree *tree, 919itree_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'. */
944static void 944static void
945itree_transplant (struct itree_tree *tree, 945itree_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
41struct itree_node 41struct 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
4853static void 4853static void
4854dump_mm_heap_cb_release (struct dump_memory_map_heap_control_block *cb) 4854dump_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
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
63typedef 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
69typedef 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
79typedef 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
85typedef 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
90typedef enum DWRITE_FACTORY_TYPE {
91 DWRITE_FACTORY_TYPE_SHARED = 0,
92 DWRITE_FACTORY_TYPE_ISOLATED = 1
93} DWRITE_FACTORY_TYPE;
94
95typedef 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
108typedef 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
118typedef interface IDWriteRenderingParams IDWriteRenderingParams;
119typedef interface IDWriteFont IDWriteFont;
120typedef interface IDWriteGdiInterop IDWriteGdiInterop;
121typedef interface IDWriteFactory IDWriteFactory;
122typedef interface IDWriteFactory2 IDWriteFactory2;
123typedef interface IDWriteFontFace IDWriteFontFace;
124typedef interface IDWriteBitmapRenderTarget IDWriteBitmapRenderTarget;
125typedef interface IDWriteBitmapRenderTarget1 IDWriteBitmapRenderTarget1;
126typedef interface IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator;
127
128DEFINE_GUID (IID_IDWriteBitmapRenderTarget1, 0x791e8298, 0x3ef3, 0x4230, 0x98,
129 0x80, 0xc9, 0xbd, 0xec, 0xc4, 0x20, 0x64);
130DEFINE_GUID (IID_IDWriteFactory2, 0x0439fc60, 0xca44, 0x4994, 0x8d, 0xee,
131 0x3a, 0x9a, 0xf7, 0xb7, 0x32, 0xec);
132DEFINE_GUID (IID_IDWriteFactory, 0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a,
133 0xdc, 0x7d, 0x93, 0xdb, 0x48);
134
135typedef struct DWRITE_GLYPH_OFFSET {
136 FLOAT advanceOffset;
137 FLOAT ascenderOffset;
138} DWRITE_GLYPH_OFFSET;
139
140typedef 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
151typedef struct _D3DCOLORVALUE {
152 float r;
153 float g;
154 float b;
155 float a;
156} D3DCOLORVALUE;
157
158typedef D3DCOLORVALUE DWRITE_COLOR_F;
159
160typedef 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
169typedef 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
212interface IDWriteFontFace {
213 CONST_VTBL IDWriteFontFaceVtbl *lpVtbl;
214};
215
216typedef 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
235interface IDWriteRenderingParams {
236 CONST_VTBL IDWriteRenderingParamsVtbl *lpVtbl;
237};
238
239typedef 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
267interface IDWriteFont {
268 CONST_VTBL IDWriteFontVtbl *lpVtbl;
269};
270
271typedef 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
303interface IDWriteBitmapRenderTarget {
304 CONST_VTBL IDWriteBitmapRenderTargetVtbl *lpVtbl;
305};
306
307typedef 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
331interface IDWriteBitmapRenderTarget1 {
332 CONST_VTBL IDWriteBitmapRenderTarget1Vtbl *lpVtbl;
333};
334
335typedef 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
357interface IDWriteGdiInterop {
358 CONST_VTBL IDWriteGdiInteropVtbl *lpVtbl;
359};
360
361typedef 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
398interface IDWriteFactory { CONST_VTBL IDWriteFactoryVtbl *lpVtbl; };
399
400typedef 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
417interface IDWriteColorGlyphRunEnumerator {
418 CONST_VTBL IDWriteColorGlyphRunEnumeratorVtbl *lpVtbl;
419};
420
421typedef 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
470interface 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' */
480static float config_enhanced_contrast = -1.0f;
481static float config_clear_type_level = -1.0f;
482static 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
489static void
490release_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. */
502static bool direct_write_available = false;
503static IDWriteFactory *dwrite_factory = NULL;
504static IDWriteFactory2 *dwrite_factory2 = NULL;
505static IDWriteGdiInterop *gdi_interop = NULL;
506static IDWriteRenderingParams *rendering_params = NULL;
507
508static bool
509verify_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. */
526static float
527get_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
570void
571w32_dwrite_free_cached_face (void *cache)
572{
573 if (cache)
574 RELEASE_COM (cache);
575}
576
577static float
578convert_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. */
584static bool
585text_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
651unsigned
652w32_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
673bool
674w32_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. */
698static IDWriteBitmapRenderTarget *
699get_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
745void
746w32_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
871bool
872w32_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*/
1040bool
1041w32_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
1053DEFUN ("w32-dwrite-available", Fw32_dwrite_available, Sw32_dwrite_available, 0, 0, 0,
1054 doc: /* Returns t if DirectWrite is available.
1055DirectWrite 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
1061DEFUN ("w32-dwrite-reinit", Fw32_dwrite_reinit, Sw32_dwrite_reinit, 0, 3, 0,
1062 doc: /* Reinitialize DirectWrite with the given parameters.
1063If a parameter is not specified, or is out of range, it will take a default
1064value.
1065
1066Return value is nil.
1067
1068ENHANCED_CONTRAST is in the range [0.0, 1.0], and defaults to 0.5.
1069CLEAR_TYPE_LEVEL is in the range [0.0, 1.0], and defaults to 1.0.
1070GAMMA 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
1098void
1099syms_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
2479process_dropfiles (DROPFILES *files) 2479process_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. */
2511Lisp_Object 2524Lisp_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
2554static HRESULT STDMETHODCALLTYPE 2568static HRESULT STDMETHODCALLTYPE
@@ -2560,18 +2574,34 @@ w32_drop_target_QueryInterface (IDropTarget *t, REFIID ri, void **r)
2560static ULONG STDMETHODCALLTYPE 2574static ULONG STDMETHODCALLTYPE
2561w32_drop_target_AddRef (IDropTarget *This) 2575w32_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
2566static ULONG STDMETHODCALLTYPE 2581static ULONG STDMETHODCALLTYPE
2567w32_drop_target_Release (IDropTarget *This) 2582w32_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
2592static void
2593w32_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
2575static HRESULT STDMETHODCALLTYPE 2605static HRESULT STDMETHODCALLTYPE
2576w32_drop_target_DragEnter (IDropTarget *This, IDataObject *pDataObj, 2606w32_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. */
61struct 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
85Lisp_Object intern_font_name (char *); 105Lisp_Object intern_font_name (char *);
86 106
107/* Function prototypes for DirectWrite. */
108void w32_initialize_direct_write (void);
109bool w32_use_direct_write (struct w32font_info *w32font);
110bool w32_dwrite_draw (HDC hdc, int x, int y, unsigned *glyphs, int len,
111 COLORREF color, struct font *font );
112bool w32_dwrite_text_extents (struct font *font, const unsigned *code,
113 int nglyphs, struct font_metrics *metrics);
114unsigned w32_dwrite_encode_char (struct font *font, int c);
115void w32_dwrite_free_cached_face (void *cache);
116void syms_of_w32dwrite (void);
117
87extern void globals_of_w32font (void); 118extern 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
2typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc)
3 (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *);
4typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR);
5typedef GpStatus (WINGDIPAPI *GdipCreateFromHDC_Proc)
6 (HDC hdc, GpGraphics **graphics);
7typedef GpStatus (WINGDIPAPI *GdipDeleteGraphics_Proc) (GpGraphics *graphics);
8typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc)
9 (GpImage *, PROPID, UINT *);
10typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc)
11 (GpImage *, PROPID, UINT, PropertyItem *);
12typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc)
13 (GpImage *, UINT *);
14typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc)
15 (GpImage *, GUID *, UINT);
16typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc)
17 (GpImage *, GDIPCONST GUID *, UINT *);
18typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc)
19 (GpImage*, GDIPCONST GUID *, UINT);
20typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc)
21 (WCHAR *, GpBitmap **);
22typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
23 (IStream *, GpBitmap **);
24typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc)
25 (INT, INT, INT, PixelFormat, BYTE*, GpBitmap**);
26typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromHBITMAP_Proc)
27 (HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap);
28typedef GpStatus (WINGDIPAPI *GdipSetInterpolationMode_Proc)
29 (GpGraphics *graphics, InterpolationMode interpolationMode);
30typedef 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);
35typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT);
36typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc)
37 (GpBitmap *, HBITMAP *, ARGB);
38typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *);
39typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *);
40typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *);
41typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *);
42typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc)
43 (UINT, UINT, ImageCodecInfo *);
44typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc)
45 (GDIPCONST WCHAR *,GpImage **);
46typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc)
47 (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *);
48typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc)
49 (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *,
50 GDIPCONST EncoderParameters *);
51typedef GpStatus (WINGDIPAPI *GdipImageRotateFlip_Proc)
52 (GpImage *image, RotateFlipType rfType);
53
54extern GdiplusStartup_Proc fn_GdiplusStartup;
55extern GdiplusShutdown_Proc fn_GdiplusShutdown;
56extern GdipCreateFromHDC_Proc fn_GdipCreateFromHDC;
57extern GdipDeleteGraphics_Proc fn_GdipDeleteGraphics;
58extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
59extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem;
60extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount;
61extern GdipImageGetFrameDimensionsList_Proc fn_GdipImageGetFrameDimensionsList;
62extern GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
63extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
64extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
65extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
66extern GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP;
67extern GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI;
68extern GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode;
69extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0;
70extern SHCreateMemStream_Proc fn_SHCreateMemStream;
71extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
72extern GdipDisposeImage_Proc fn_GdipDisposeImage;
73extern GdipGetImageHeight_Proc fn_GdipGetImageHeight;
74extern GdipGetImageWidth_Proc fn_GdipGetImageWidth;
75extern GdipGetImageEncodersSize_Proc fn_GdipGetImageEncodersSize;
76extern GdipGetImageEncoders_Proc fn_GdipGetImageEncoders;
77extern GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
78extern GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
79extern GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
80extern 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
139int 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;
45extern int w32_load_image (struct frame *f, struct image *img, 45extern 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);
47extern bool w32_can_use_native_image_api (Lisp_Object); 47extern bool w32_can_use_native_image_api (Lisp_Object);
48extern bool w32_gdiplus_startup (void);
48extern void w32_gdiplus_shutdown (void); 49extern void w32_gdiplus_shutdown (void);
50
49extern size_t w32_image_size (Emacs_Pixmap); 51extern 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
43typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc)
44 (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *);
45typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR);
46typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc)
47 (GpImage *, PROPID, UINT *);
48typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc)
49 (GpImage *, PROPID, UINT, PropertyItem *);
50typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc)
51 (GpImage *, UINT *);
52typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc)
53 (GpImage *, GUID *, UINT);
54typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc)
55 (GpImage *, GDIPCONST GUID *, UINT *);
56typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc)
57 (GpImage*, GDIPCONST GUID *, UINT);
58typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc)
59 (WCHAR *, GpBitmap **);
60typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
61 (IStream *, GpBitmap **);
62typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT);
63typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc)
64 (GpBitmap *, HBITMAP *, ARGB);
65typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *);
66typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *);
67typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *);
68typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *);
69typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc)
70 (UINT, UINT, ImageCodecInfo *);
71typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc)
72 (GDIPCONST WCHAR *,GpImage **);
73typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc)
74 (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *);
75typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc)
76 (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *,
77 GDIPCONST EncoderParameters *);
78
79GdiplusStartup_Proc fn_GdiplusStartup; 43GdiplusStartup_Proc fn_GdiplusStartup;
80GdiplusShutdown_Proc fn_GdiplusShutdown; 44GdiplusShutdown_Proc fn_GdiplusShutdown;
45GdipCreateFromHDC_Proc fn_GdipCreateFromHDC;
46GdipDeleteGraphics_Proc fn_GdipDeleteGraphics;
81GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; 47GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
82GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; 48GdipGetPropertyItem_Proc fn_GdipGetPropertyItem;
83GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; 49GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount;
@@ -86,8 +52,12 @@ GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
86GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; 52GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
87GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; 53GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
88GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; 54GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
55GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0;
89SHCreateMemStream_Proc fn_SHCreateMemStream; 56SHCreateMemStream_Proc fn_SHCreateMemStream;
90GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; 57GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
58GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP;
59GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI;
60GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode;
91GdipDisposeImage_Proc fn_GdipDisposeImage; 61GdipDisposeImage_Proc fn_GdipDisposeImage;
92GdipGetImageHeight_Proc fn_GdipGetImageHeight; 62GdipGetImageHeight_Proc fn_GdipGetImageHeight;
93GdipGetImageWidth_Proc fn_GdipGetImageWidth; 63GdipGetImageWidth_Proc fn_GdipGetImageWidth;
@@ -96,6 +66,7 @@ GdipGetImageEncoders_Proc fn_GdipGetImageEncoders;
96GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile; 66GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
97GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail; 67GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
98GdipSaveImageToFile_Proc fn_GdipSaveImageToFile; 68GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
69GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
99 70
100static bool 71static bool
101gdiplus_init (void) 72gdiplus_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
247static int gdip_initialized; 204static 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. */
255static bool 212bool
256gdiplus_startup (void) 213w32_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
311enum PropertyItem_type { 268enum PropertyItem_type {
@@ -549,8 +506,8 @@ static struct thumb_type_data thumb_types [] =
549 }; 506 };
550 507
551 508
552static int 509int
553get_encoder_clsid (const char *type, CLSID *clsid) 510w32_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,
186Lisp_Object 186Lisp_Object
187w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) 187w32_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. */
803static 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. */
825static bool
826convert_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
867static int
868get_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
880DEFUN ("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
884FORMATS is a list of formats.
885TEMP-FILE-IN is the name of the file to store the data.
886
887Elements in FORMATS are symbols naming a format, such a image/png, or
888image/jpeg. For compatibility with X systems, some conventional
889format names are translated to equivalent MIME types, as configured with
890the variable 'w32--selection-target-translations'.
891
892The file named in TEMP-FILE-IN must be created by the caller, and also
893deleted if required.
894
895Returns nil it there is no such format, or something failed.
896If it returns t, then the caller should read the file to get the data.
897If it returns a string, then that is the data and the file is not used.
898
899When returning a string, it will be unibyte if IS-TEXTUAL is nil (the
900content 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
791DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data, 965DEFUN ("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
1069representing a data format that is currently available in the clipboard. */) 1243representing 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. */
48struct 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
59int uniscribe_available = 0; 47int 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);