aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrea Corallo2020-08-13 12:22:07 +0200
committerAndrea Corallo2020-08-13 12:22:07 +0200
commit46e7613ad3b88807d25cfab3d78bf46c9e2fe13e (patch)
treea7b560c36e097660536697c9d0057c9273d779b2 /src
parentf6502f959253b8f705e324e137c2933c5a668f62 (diff)
parente9eafd22681b8e95d8d642def0512d9290564206 (diff)
downloademacs-46e7613ad3b88807d25cfab3d78bf46c9e2fe13e.tar.gz
emacs-46e7613ad3b88807d25cfab3d78bf46c9e2fe13e.zip
Merge remote-tracking branch 'savannah/master' into HEAD
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in1
-rw-r--r--src/bytecode.c1
-rw-r--r--src/composite.c1
-rw-r--r--src/emacs.c3
-rw-r--r--src/fns.c67
-rw-r--r--src/json.c4
-rw-r--r--src/lisp.h24
-rw-r--r--src/macfont.m88
-rw-r--r--src/minibuf.c3
-rw-r--r--src/nsterm.m21
-rw-r--r--src/nsxwidget.h80
-rw-r--r--src/nsxwidget.m601
-rw-r--r--src/pdumper.c320
-rw-r--r--src/pdumper.h1
-rw-r--r--src/timefns.c2
-rw-r--r--src/xfaces.c20
-rw-r--r--src/xwidget.c253
-rw-r--r--src/xwidget.h48
18 files changed, 1242 insertions, 296 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 3cc9d594144..63a4aa80e93 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -438,6 +438,7 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \
438 xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ 438 xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \
439 fontset.o dbusbind.o cygw32.o \ 439 fontset.o dbusbind.o cygw32.o \
440 nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o macfont.o \ 440 nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o macfont.o \
441 nsxwidget.o \
441 w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \ 442 w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \
442 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ 443 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
443 w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ 444 w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \
diff --git a/src/bytecode.c b/src/bytecode.c
index 1913a4812a0..1c3b6eac0d1 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -1401,7 +1401,6 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
1401 Lisp_Object v1 = POP; 1401 Lisp_Object v1 = POP;
1402 ptrdiff_t i; 1402 ptrdiff_t i;
1403 struct Lisp_Hash_Table *h = XHASH_TABLE (jmp_table); 1403 struct Lisp_Hash_Table *h = XHASH_TABLE (jmp_table);
1404 hash_rehash_if_needed (h);
1405 1404
1406 /* h->count is a faster approximation for HASH_TABLE_SIZE (h) 1405 /* h->count is a faster approximation for HASH_TABLE_SIZE (h)
1407 here. */ 1406 here. */
diff --git a/src/composite.c b/src/composite.c
index f96f0b77726..ec2b8328f78 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -652,7 +652,6 @@ Lisp_Object
652composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len) 652composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len)
653{ 653{
654 struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table); 654 struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
655 hash_rehash_if_needed (h);
656 Lisp_Object header = LGSTRING_HEADER (gstring); 655 Lisp_Object header = LGSTRING_HEADER (gstring);
657 Lisp_Object hash = h->test.hashfn (header, h); 656 Lisp_Object hash = h->test.hashfn (header, h);
658 if (len < 0) 657 if (len < 0)
diff --git a/src/emacs.c b/src/emacs.c
index 8c252276352..288ddb47bd7 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1551,6 +1551,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1551 if (!initialized) 1551 if (!initialized)
1552 { 1552 {
1553 init_alloc_once (); 1553 init_alloc_once ();
1554 init_pdumper_once ();
1554 init_obarray_once (); 1555 init_obarray_once ();
1555 init_eval_once (); 1556 init_eval_once ();
1556 init_charset_once (); 1557 init_charset_once ();
@@ -1877,7 +1878,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1877 syms_of_xfns (); 1878 syms_of_xfns ();
1878 syms_of_xmenu (); 1879 syms_of_xmenu ();
1879 syms_of_fontset (); 1880 syms_of_fontset ();
1880 syms_of_xwidget ();
1881 syms_of_xsettings (); 1881 syms_of_xsettings ();
1882#ifdef HAVE_X_SM 1882#ifdef HAVE_X_SM
1883 syms_of_xsmfns (); 1883 syms_of_xsmfns ();
@@ -1954,6 +1954,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1954#endif /* HAVE_W32NOTIFY */ 1954#endif /* HAVE_W32NOTIFY */
1955#endif /* WINDOWSNT */ 1955#endif /* WINDOWSNT */
1956 1956
1957 syms_of_xwidget ();
1957 syms_of_threads (); 1958 syms_of_threads ();
1958 syms_of_profiler (); 1959 syms_of_profiler ();
1959 syms_of_pdumper (); 1960 syms_of_pdumper ();
diff --git a/src/fns.c b/src/fns.c
index 811d6e82001..91991782124 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -4248,50 +4248,31 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
4248 4248
4249/* Recompute the hashes (and hence also the "next" pointers). 4249/* Recompute the hashes (and hence also the "next" pointers).
4250 Normally there's never a need to recompute hashes. 4250 Normally there's never a need to recompute hashes.
4251 This is done only on first-access to a hash-table loaded from 4251 This is done only on first access to a hash-table loaded from
4252 the "pdump", because the object's addresses may have changed, thus 4252 the "pdump", because the objects' addresses may have changed, thus
4253 affecting their hash. */ 4253 affecting their hashes. */
4254void 4254void
4255hash_table_rehash (struct Lisp_Hash_Table *h) 4255hash_table_rehash (Lisp_Object hash)
4256{ 4256{
4257 ptrdiff_t size = HASH_TABLE_SIZE (h); 4257 struct Lisp_Hash_Table *h = XHASH_TABLE (hash);
4258 4258 ptrdiff_t i, count = h->count;
4259 /* These structures may have been purecopied and shared
4260 (bug#36447). */
4261 Lisp_Object hash = make_nil_vector (size);
4262 h->next = Fcopy_sequence (h->next);
4263 h->index = Fcopy_sequence (h->index);
4264 4259
4265 /* Recompute the actual hash codes for each entry in the table. 4260 /* Recompute the actual hash codes for each entry in the table.
4266 Order is still invalid. */ 4261 Order is still invalid. */
4267 for (ptrdiff_t i = 0; i < size; ++i) 4262 for (i = 0; i < count; i++)
4268 { 4263 {
4269 Lisp_Object key = HASH_KEY (h, i); 4264 Lisp_Object key = HASH_KEY (h, i);
4270 if (!EQ (key, Qunbound)) 4265 Lisp_Object hash_code = h->test.hashfn (key, h);
4271 ASET (hash, i, h->test.hashfn (key, h)); 4266 ptrdiff_t start_of_bucket = XUFIXNUM (hash_code) % ASIZE (h->index);
4267 set_hash_hash_slot (h, i, hash_code);
4268 set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
4269 set_hash_index_slot (h, start_of_bucket, i);
4270 eassert (HASH_NEXT (h, i) != i); /* Stop loops. */
4272 } 4271 }
4273 4272
4274 /* Reset the index so that any slot we don't fill below is marked 4273 ptrdiff_t size = ASIZE (h->next);
4275 invalid. */ 4274 for (; i + 1 < size; i++)
4276 Ffillarray (h->index, make_fixnum (-1)); 4275 set_hash_next_slot (h, i, i + 1);
4277
4278 /* Rebuild the collision chains. */
4279 for (ptrdiff_t i = 0; i < size; ++i)
4280 if (!NILP (AREF (hash, i)))
4281 {
4282 EMACS_UINT hash_code = XUFIXNUM (AREF (hash, i));
4283 ptrdiff_t start_of_bucket = hash_code % ASIZE (h->index);
4284 set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
4285 set_hash_index_slot (h, start_of_bucket, i);
4286 eassert (HASH_NEXT (h, i) != i); /* Stop loops. */
4287 }
4288
4289 /* Finally, mark the hash table as having a valid hash order.
4290 Do this last so that if we're interrupted, we retry on next
4291 access. */
4292 eassert (hash_rehash_needed_p (h));
4293 h->hash = hash;
4294 eassert (!hash_rehash_needed_p (h));
4295} 4276}
4296 4277
4297/* Lookup KEY in hash table H. If HASH is non-null, return in *HASH 4278/* Lookup KEY in hash table H. If HASH is non-null, return in *HASH
@@ -4303,8 +4284,6 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object *hash)
4303{ 4284{
4304 ptrdiff_t start_of_bucket, i; 4285 ptrdiff_t start_of_bucket, i;
4305 4286
4306 hash_rehash_if_needed (h);
4307
4308 Lisp_Object hash_code = h->test.hashfn (key, h); 4287 Lisp_Object hash_code = h->test.hashfn (key, h);
4309 if (hash) 4288 if (hash)
4310 *hash = hash_code; 4289 *hash = hash_code;
@@ -4339,8 +4318,6 @@ hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value,
4339{ 4318{
4340 ptrdiff_t start_of_bucket, i; 4319 ptrdiff_t start_of_bucket, i;
4341 4320
4342 hash_rehash_if_needed (h);
4343
4344 /* Increment count after resizing because resizing may fail. */ 4321 /* Increment count after resizing because resizing may fail. */
4345 maybe_resize_hash_table (h); 4322 maybe_resize_hash_table (h);
4346 h->count++; 4323 h->count++;
@@ -4373,8 +4350,6 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
4373 ptrdiff_t start_of_bucket = XUFIXNUM (hash_code) % ASIZE (h->index); 4350 ptrdiff_t start_of_bucket = XUFIXNUM (hash_code) % ASIZE (h->index);
4374 ptrdiff_t prev = -1; 4351 ptrdiff_t prev = -1;
4375 4352
4376 hash_rehash_if_needed (h);
4377
4378 for (ptrdiff_t i = HASH_INDEX (h, start_of_bucket); 4353 for (ptrdiff_t i = HASH_INDEX (h, start_of_bucket);
4379 0 <= i; 4354 0 <= i;
4380 i = HASH_NEXT (h, i)) 4355 i = HASH_NEXT (h, i))
@@ -4415,8 +4390,7 @@ hash_clear (struct Lisp_Hash_Table *h)
4415 if (h->count > 0) 4390 if (h->count > 0)
4416 { 4391 {
4417 ptrdiff_t size = HASH_TABLE_SIZE (h); 4392 ptrdiff_t size = HASH_TABLE_SIZE (h);
4418 if (!hash_rehash_needed_p (h)) 4393 memclear (xvector_contents (h->hash), size * word_size);
4419 memclear (xvector_contents (h->hash), size * word_size);
4420 for (ptrdiff_t i = 0; i < size; i++) 4394 for (ptrdiff_t i = 0; i < size; i++)
4421 { 4395 {
4422 set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1); 4396 set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1);
@@ -4452,9 +4426,7 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
4452 for (ptrdiff_t bucket = 0; bucket < n; ++bucket) 4426 for (ptrdiff_t bucket = 0; bucket < n; ++bucket)
4453 { 4427 {
4454 /* Follow collision chain, removing entries that don't survive 4428 /* Follow collision chain, removing entries that don't survive
4455 this garbage collection. It's okay if hash_rehash_needed_p 4429 this garbage collection. */
4456 (h) is true, since we're operating entirely on the cached
4457 hash values. */
4458 ptrdiff_t prev = -1; 4430 ptrdiff_t prev = -1;
4459 ptrdiff_t next; 4431 ptrdiff_t next;
4460 for (ptrdiff_t i = HASH_INDEX (h, bucket); 0 <= i; i = next) 4432 for (ptrdiff_t i = HASH_INDEX (h, bucket); 0 <= i; i = next)
@@ -4499,7 +4471,7 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
4499 set_hash_hash_slot (h, i, Qnil); 4471 set_hash_hash_slot (h, i, Qnil);
4500 4472
4501 eassert (h->count != 0); 4473 eassert (h->count != 0);
4502 h->count += h->count > 0 ? -1 : 1; 4474 h->count--;
4503 } 4475 }
4504 else 4476 else
4505 { 4477 {
@@ -4923,7 +4895,6 @@ DEFUN ("hash-table-count", Fhash_table_count, Shash_table_count, 1, 1, 0,
4923 (Lisp_Object table) 4895 (Lisp_Object table)
4924{ 4896{
4925 struct Lisp_Hash_Table *h = check_hash_table (table); 4897 struct Lisp_Hash_Table *h = check_hash_table (table);
4926 eassert (h->count >= 0);
4927 return make_fixnum (h->count); 4898 return make_fixnum (h->count);
4928} 4899}
4929 4900
diff --git a/src/json.c b/src/json.c
index 814afc6d741..8c9583631ad 100644
--- a/src/json.c
+++ b/src/json.c
@@ -479,9 +479,7 @@ lisp_to_json (Lisp_Object lisp, struct json_configuration *conf)
479 { 479 {
480 intmax_t low = TYPE_MINIMUM (json_int_t); 480 intmax_t low = TYPE_MINIMUM (json_int_t);
481 intmax_t high = TYPE_MAXIMUM (json_int_t); 481 intmax_t high = TYPE_MAXIMUM (json_int_t);
482 intmax_t value; 482 intmax_t value = check_integer_range (lisp, low, high);
483 if (! (integer_to_intmax (lisp, &value) && low <= value && value <= high))
484 args_out_of_range_3 (lisp, make_int (low), make_int (high));
485 return json_check (json_integer (value)); 483 return json_check (json_integer (value));
486 } 484 }
487 else if (FLOATP (lisp)) 485 else if (FLOATP (lisp))
diff --git a/src/lisp.h b/src/lisp.h
index 75ef6d30f97..5f913b72b45 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2286,11 +2286,7 @@ struct hash_table_test
2286 2286
2287struct Lisp_Hash_Table 2287struct Lisp_Hash_Table
2288{ 2288{
2289 /* Change pdumper.c if you change the fields here. 2289 /* Change pdumper.c if you change the fields here. */
2290
2291 IMPORTANT!!!!!!!
2292
2293 Call hash_rehash_if_needed() before accessing. */
2294 2290
2295 /* This is for Lisp; the hash table code does not refer to it. */ 2291 /* This is for Lisp; the hash table code does not refer to it. */
2296 union vectorlike_header header; 2292 union vectorlike_header header;
@@ -2409,20 +2405,7 @@ HASH_TABLE_SIZE (const struct Lisp_Hash_Table *h)
2409 return size; 2405 return size;
2410} 2406}
2411 2407
2412void hash_table_rehash (struct Lisp_Hash_Table *h); 2408void hash_table_rehash (Lisp_Object);
2413
2414INLINE bool
2415hash_rehash_needed_p (const struct Lisp_Hash_Table *h)
2416{
2417 return NILP (h->hash);
2418}
2419
2420INLINE void
2421hash_rehash_if_needed (struct Lisp_Hash_Table *h)
2422{
2423 if (hash_rehash_needed_p (h))
2424 hash_table_rehash (h);
2425}
2426 2409
2427/* Default size for hash tables if not specified. */ 2410/* Default size for hash tables if not specified. */
2428 2411
@@ -3975,7 +3958,8 @@ make_uninit_sub_char_table (int depth, int min_char)
3975 return v; 3958 return v;
3976} 3959}
3977 3960
3978/* Make a vector of SIZE nils. */ 3961/* Make a vector of SIZE nils - faster than make_vector (size, Qnil)
3962 if the OS already cleared the new memory. */
3979 3963
3980INLINE Lisp_Object 3964INLINE Lisp_Object
3981make_nil_vector (ptrdiff_t size) 3965make_nil_vector (ptrdiff_t size)
diff --git a/src/macfont.m b/src/macfont.m
index 21bc7dde5b3..c7430d32772 100644
--- a/src/macfont.m
+++ b/src/macfont.m
@@ -1120,7 +1120,10 @@ struct macfont_metrics
1120 glyph width. The `width_int' member is an integer that is 1120 glyph width. The `width_int' member is an integer that is
1121 closest to the width. The `width_frac' member is the fractional 1121 closest to the width. The `width_frac' member is the fractional
1122 adjustment representing a value in [-.5, .5], multiplied by 1122 adjustment representing a value in [-.5, .5], multiplied by
1123 WIDTH_FRAC_SCALE. For synthetic monospace fonts, they represent 1123 WIDTH_FRAC_SCALE. For monospace fonts, non-zero `width_frac'
1124 means `width_int' is further adjusted to a multiple of the
1125 (rounded) font width, and `width_frac' represents adjustment per
1126 unit character. For synthetic monospace fonts, they represent
1124 the advance delta for centering instead of the glyph width. */ 1127 the advance delta for centering instead of the glyph width. */
1125 signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS; 1128 signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1126}; 1129};
@@ -1148,6 +1151,27 @@ enum metrics_status
1148#define LCD_FONT_SMOOTHING_LEFT_MARGIN (0.396f) 1151#define LCD_FONT_SMOOTHING_LEFT_MARGIN (0.396f)
1149#define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f) 1152#define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1150 1153
1154/* If FONT is monospace and WIDTH can be regarded as a multiple of its
1155 width where the multiplier is greater than 1, then return the
1156 multiplier. Otherwise return 0. */
1157static int
1158macfont_monospace_width_multiplier (struct font *font, CGFloat width)
1159{
1160 struct macfont_info *macfont_info = (struct macfont_info *) font;
1161 int multiplier = 0;
1162
1163 if (macfont_info->spacing == MACFONT_SPACING_MONO
1164 && font->space_width != 0)
1165 {
1166 multiplier = lround (width / font->space_width);
1167 if (multiplier == 1
1168 || lround (width / multiplier) != font->space_width)
1169 multiplier = 0;
1170 }
1171
1172 return multiplier;
1173}
1174
1151static int 1175static int
1152macfont_glyph_extents (struct font *font, CGGlyph glyph, 1176macfont_glyph_extents (struct font *font, CGGlyph glyph,
1153 struct font_metrics *metrics, CGFloat *advance_delta, 1177 struct font_metrics *metrics, CGFloat *advance_delta,
@@ -1192,13 +1216,38 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph,
1192 else 1216 else
1193 fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph); 1217 fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1194 1218
1195 /* For synthetic mono fonts, cache->width_{int,frac} holds the 1219 if (macfont_info->spacing == MACFONT_SPACING_MONO)
1196 advance delta value. */ 1220 {
1197 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO) 1221 /* Some monospace fonts for programming languages contain
1198 fwidth = (font->pixel_size - fwidth) / 2; 1222 wider ligature glyphs consisting of multiple characters.
1199 cache->width_int = lround (fwidth); 1223 For such glyphs, simply rounding the combined fractional
1200 cache->width_frac = lround ((fwidth - cache->width_int) 1224 width to an integer can result in a value that is not a
1201 * WIDTH_FRAC_SCALE); 1225 multiple of the (rounded) font width. */
1226 int multiplier = macfont_monospace_width_multiplier (font, fwidth);
1227
1228 if (multiplier)
1229 {
1230 cache->width_int = font->space_width * multiplier;
1231 cache->width_frac = lround ((fwidth / multiplier
1232 - font->space_width)
1233 * WIDTH_FRAC_SCALE);
1234 }
1235 else
1236 {
1237 cache->width_int = lround (fwidth);
1238 cache->width_frac = 0;
1239 }
1240 }
1241 else
1242 {
1243 /* For synthetic mono fonts, cache->width_{int,frac} holds
1244 the advance delta value. */
1245 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1246 fwidth = (font->pixel_size - fwidth) / 2;
1247 cache->width_int = lround (fwidth);
1248 cache->width_frac = lround ((fwidth - cache->width_int)
1249 * WIDTH_FRAC_SCALE);
1250 }
1202 METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID); 1251 METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1203 } 1252 }
1204 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO) 1253 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
@@ -1235,6 +1284,10 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph,
1235 / (CGFloat) (WIDTH_FRAC_SCALE * 2)); 1284 / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1236 break; 1285 break;
1237 case MACFONT_SPACING_MONO: 1286 case MACFONT_SPACING_MONO:
1287 if (cache->width_frac)
1288 bounds.origin.x += - ((cache->width_frac
1289 / (CGFloat) (WIDTH_FRAC_SCALE * 2))
1290 * (cache->width_int / font->space_width));
1238 break; 1291 break;
1239 case MACFONT_SPACING_SYNTHETIC_MONO: 1292 case MACFONT_SPACING_SYNTHETIC_MONO:
1240 bounds.origin.x += (cache->width_int 1293 bounds.origin.x += (cache->width_int
@@ -1271,7 +1324,16 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph,
1271 / (CGFloat) (WIDTH_FRAC_SCALE * 2))); 1324 / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1272 break; 1325 break;
1273 case MACFONT_SPACING_MONO: 1326 case MACFONT_SPACING_MONO:
1274 *advance_delta = 0; 1327 if (cache->width_frac)
1328 *advance_delta = 0;
1329 else
1330 {
1331 CGFloat delta = - ((cache->width_frac
1332 / (CGFloat) (WIDTH_FRAC_SCALE * 2))
1333 * (cache->width_int / font->space_width));
1334
1335 *advance_delta = (force_integral_p ? round (delta) : delta);
1336 }
1275 break; 1337 break;
1276 case MACFONT_SPACING_SYNTHETIC_MONO: 1338 case MACFONT_SPACING_SYNTHETIC_MONO:
1277 *advance_delta = (force_integral_p ? cache->width_int 1339 *advance_delta = (force_integral_p ? cache->width_int
@@ -3015,7 +3077,7 @@ macfont_shape (Lisp_Object lgstring, Lisp_Object direction)
3015 struct mac_glyph_layout *gl = glyph_layouts + i; 3077 struct mac_glyph_layout *gl = glyph_layouts + i;
3016 EMACS_INT from, to; 3078 EMACS_INT from, to;
3017 struct font_metrics metrics; 3079 struct font_metrics metrics;
3018 int xoff, yoff, wadjust; 3080 int xoff, yoff, wadjust, multiplier;
3019 3081
3020 if (NILP (lglyph)) 3082 if (NILP (lglyph))
3021 { 3083 {
@@ -3068,7 +3130,11 @@ macfont_shape (Lisp_Object lgstring, Lisp_Object direction)
3068 3130
3069 xoff = lround (gl->advance_delta); 3131 xoff = lround (gl->advance_delta);
3070 yoff = lround (- gl->baseline_delta); 3132 yoff = lround (- gl->baseline_delta);
3071 wadjust = lround (gl->advance); 3133 multiplier = macfont_monospace_width_multiplier (font, gl->advance);
3134 if (multiplier)
3135 wadjust = font->space_width * multiplier;
3136 else
3137 wadjust = lround (gl->advance);
3072 if (xoff != 0 || yoff != 0 || wadjust != metrics.width) 3138 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3073 { 3139 {
3074 Lisp_Object vec = make_uninit_vector (3); 3140 Lisp_Object vec = make_uninit_vector (3);
diff --git a/src/minibuf.c b/src/minibuf.c
index 9d870ce3640..cb302c5a605 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1212,9 +1212,6 @@ is used to further constrain the set of candidates. */)
1212 bucket = AREF (collection, idx); 1212 bucket = AREF (collection, idx);
1213 } 1213 }
1214 1214
1215 if (HASH_TABLE_P (collection))
1216 hash_rehash_if_needed (XHASH_TABLE (collection));
1217
1218 while (1) 1215 while (1)
1219 { 1216 {
1220 /* Get the next element of the alist, obarray, or hash-table. */ 1217 /* Get the next element of the alist, obarray, or hash-table. */
diff --git a/src/nsterm.m b/src/nsterm.m
index 572b859a982..9f5916d78ed 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -49,6 +49,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
49#include "nsterm.h" 49#include "nsterm.h"
50#include "systime.h" 50#include "systime.h"
51#include "character.h" 51#include "character.h"
52#include "xwidget.h"
52#include "fontset.h" 53#include "fontset.h"
53#include "composite.h" 54#include "composite.h"
54#include "ccl.h" 55#include "ccl.h"
@@ -2600,7 +2601,8 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2600} 2601}
2601 2602
2602static int 2603static int
2603ns_note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y) 2604ns_note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y,
2605 BOOL dragging)
2604/* ------------------------------------------------------------------------ 2606/* ------------------------------------------------------------------------
2605 Called by EmacsView on mouseMovement events. Passes on 2607 Called by EmacsView on mouseMovement events. Passes on
2606 to emacs mainstream code if we moved off of a rect of interest 2608 to emacs mainstream code if we moved off of a rect of interest
@@ -2609,17 +2611,24 @@ ns_note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2609{ 2611{
2610 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame); 2612 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2611 NSRect *r; 2613 NSRect *r;
2614 BOOL force_update = NO;
2612 2615
2613 // NSTRACE ("note_mouse_movement"); 2616 // NSTRACE ("note_mouse_movement");
2614 2617
2615 dpyinfo->last_mouse_motion_frame = frame; 2618 dpyinfo->last_mouse_motion_frame = frame;
2616 r = &dpyinfo->last_mouse_glyph; 2619 r = &dpyinfo->last_mouse_glyph;
2617 2620
2621 /* If the last rect is too large (ex, xwidget webkit), update at
2622 every move, or resizing by dragging modeline or vertical split is
2623 very hard to make its way. */
2624 if (dragging && (r->size.width > 32 || r->size.height > 32))
2625 force_update = YES;
2626
2618 /* Note, this doesn't get called for enter/leave, since we don't have a 2627 /* Note, this doesn't get called for enter/leave, since we don't have a
2619 position. Those are taken care of in the corresponding NSView methods. */ 2628 position. Those are taken care of in the corresponding NSView methods. */
2620 2629
2621 /* Has movement gone beyond last rect we were tracking? */ 2630 /* Has movement gone beyond last rect we were tracking? */
2622 if (x < r->origin.x || x >= r->origin.x + r->size.width 2631 if (force_update || x < r->origin.x || x >= r->origin.x + r->size.width
2623 || y < r->origin.y || y >= r->origin.y + r->size.height) 2632 || y < r->origin.y || y >= r->origin.y + r->size.height)
2624 { 2633 {
2625 ns_update_begin (frame); 2634 ns_update_begin (frame);
@@ -4368,6 +4377,10 @@ ns_draw_glyph_string (struct glyph_string *s)
4368 ns_unfocus (s->f); 4377 ns_unfocus (s->f);
4369 break; 4378 break;
4370 4379
4380 case XWIDGET_GLYPH:
4381 x_draw_xwidget_glyph_string (s);
4382 break;
4383
4371 case STRETCH_GLYPH: 4384 case STRETCH_GLYPH:
4372 ns_dumpglyphs_stretch (s); 4385 ns_dumpglyphs_stretch (s);
4373 break; 4386 break;
@@ -7065,6 +7078,7 @@ not_in_argv (NSString *arg)
7065 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); 7078 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7066 Lisp_Object frame; 7079 Lisp_Object frame;
7067 NSPoint pt; 7080 NSPoint pt;
7081 BOOL dragging;
7068 7082
7069 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]"); 7083 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
7070 7084
@@ -7107,7 +7121,8 @@ not_in_argv (NSString *arg)
7107 last_mouse_window = window; 7121 last_mouse_window = window;
7108 } 7122 }
7109 7123
7110 if (!ns_note_mouse_movement (emacsframe, pt.x, pt.y)) 7124 dragging = (e.type == NSEventTypeLeftMouseDragged);
7125 if (!ns_note_mouse_movement (emacsframe, pt.x, pt.y, dragging))
7111 help_echo_string = previous_help_echo_string; 7126 help_echo_string = previous_help_echo_string;
7112 7127
7113 XSETFRAME (frame, emacsframe); 7128 XSETFRAME (frame, emacsframe);
diff --git a/src/nsxwidget.h b/src/nsxwidget.h
new file mode 100644
index 00000000000..3d91594c341
--- /dev/null
+++ b/src/nsxwidget.h
@@ -0,0 +1,80 @@
1/* Header for NS Cocoa part of xwidget and webkit widget.
2
3Copyright (C) 2019-2020 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 <http://www.gnu.org/licenses/>. */
19
20#ifndef NSXWIDGET_H_INCLUDED
21#define NSXWIDGET_H_INCLUDED
22
23/* This file can be included from non-objc files through 'xwidget.h'. */
24#ifdef __OBJC__
25#import <AppKit/NSView.h>
26#endif
27
28#include "dispextern.h"
29#include "lisp.h"
30#include "xwidget.h"
31
32/* Functions for xwidget webkit. */
33
34bool nsxwidget_is_web_view (struct xwidget *xw);
35Lisp_Object nsxwidget_webkit_uri (struct xwidget *xw);
36Lisp_Object nsxwidget_webkit_title (struct xwidget *xw);
37void nsxwidget_webkit_goto_uri (struct xwidget *xw, const char *uri);
38void nsxwidget_webkit_goto_history (struct xwidget *xw, int rel_pos);
39void nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change);
40void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
41 Lisp_Object fun);
42
43/* Functions for xwidget model. */
44
45#ifdef __OBJC__
46@interface XwWindow : NSView
47@property struct xwidget *xw;
48@end
49#endif
50
51void nsxwidget_init (struct xwidget *xw);
52void nsxwidget_kill (struct xwidget *xw);
53void nsxwidget_resize (struct xwidget *xw);
54Lisp_Object nsxwidget_get_size (struct xwidget *xw);
55
56/* Functions for xwidget view. */
57
58#ifdef __OBJC__
59@interface XvWindow : NSView
60@property struct xwidget *xw;
61@property struct xwidget_view *xv;
62@end
63#endif
64
65void nsxwidget_init_view (struct xwidget_view *xv,
66 struct xwidget *xww,
67 struct glyph_string *s,
68 int x, int y);
69void nsxwidget_delete_view (struct xwidget_view *xv);
70
71void nsxwidget_show_view (struct xwidget_view *xv);
72void nsxwidget_hide_view (struct xwidget_view *xv);
73void nsxwidget_resize_view (struct xwidget_view *xv,
74 int widget, int height);
75
76void nsxwidget_move_view (struct xwidget_view *xv, int x, int y);
77void nsxwidget_move_widget_in_view (struct xwidget_view *xv, int x, int y);
78void nsxwidget_set_needsdisplay (struct xwidget_view *xv);
79
80#endif /* NSXWIDGET_H_INCLUDED */
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
new file mode 100644
index 00000000000..370abee395c
--- /dev/null
+++ b/src/nsxwidget.m
@@ -0,0 +1,601 @@
1/* NS Cocoa part implementation of xwidget and webkit widget.
2
3Copyright (C) 2019-2020 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 <http://www.gnu.org/licenses/>. */
19
20#include <config.h>
21
22#include "lisp.h"
23#include "blockinput.h"
24#include "dispextern.h"
25#include "buffer.h"
26#include "frame.h"
27#include "nsterm.h"
28#include "xwidget.h"
29
30#import <AppKit/AppKit.h>
31#import <WebKit/WebKit.h>
32
33/* Thoughts on NS Cocoa xwidget and webkit2:
34
35 Webkit2 process architecture seems to be very hostile for offscreen
36 rendering techniques, which is used by GTK xwiget implementation;
37 Specifically NSView level view sharing / copying is not working.
38
39 *** So only one view can be associcated with a model. ***
40
41 With this decision, implementation is plain and can expect best out
42 of webkit2's rationale. But process and session structures will
43 diverge from GTK xwiget. Though, cosmetically similar usages can
44 be presented and will be preferred, if agreeable.
45
46 For other widget types, OSR seems possible, but will not care for a
47 while. */
48
49/* Xwidget webkit. */
50
51@interface XwWebView : WKWebView
52<WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler>
53@property struct xwidget *xw;
54/* Map url to whether javascript is blocked by
55 'Content-Security-Policy' sandbox without allow-scripts. */
56@property(retain) NSMutableDictionary *urlScriptBlocked;
57@end
58@implementation XwWebView : WKWebView
59
60- (id)initWithFrame:(CGRect)frame
61 configuration:(WKWebViewConfiguration *)configuration
62 xwidget:(struct xwidget *)xw
63{
64 /* Script controller to add script message handler and user script. */
65 WKUserContentController *scriptor = [[WKUserContentController alloc] init];
66 configuration.userContentController = scriptor;
67
68 /* Enable inspect element context menu item for debugging. */
69 [configuration.preferences setValue:@YES
70 forKey:@"developerExtrasEnabled"];
71
72 Lisp_Object enablePlugins =
73 Fintern (build_string ("xwidget-webkit-enable-plugins"), Qnil);
74 if (!EQ (Fsymbol_value (enablePlugins), Qnil))
75 configuration.preferences.plugInsEnabled = YES;
76
77 self = [super initWithFrame:frame configuration:configuration];
78 if (self)
79 {
80 self.xw = xw;
81 self.urlScriptBlocked = [[NSMutableDictionary alloc] init];
82 self.navigationDelegate = self;
83 self.UIDelegate = self;
84 self.customUserAgent =
85 @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)"
86 @" AppleWebKit/603.3.8 (KHTML, like Gecko)"
87 @" Version/11.0.1 Safari/603.3.8";
88 [scriptor addScriptMessageHandler:self name:@"keyDown"];
89 [scriptor addUserScript:[[WKUserScript alloc]
90 initWithSource:xwScript
91 injectionTime:
92 WKUserScriptInjectionTimeAtDocumentStart
93 forMainFrameOnly:NO]];
94 }
95 return self;
96}
97
98- (void)webView:(WKWebView *)webView
99didFinishNavigation:(WKNavigation *)navigation
100{
101 if (EQ (Fbuffer_live_p (self.xw->buffer), Qt))
102 store_xwidget_event_string (self.xw, "load-changed", "");
103}
104
105- (void)webView:(WKWebView *)webView
106decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
107decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
108{
109 switch (navigationAction.navigationType) {
110 case WKNavigationTypeLinkActivated:
111 decisionHandler (WKNavigationActionPolicyAllow);
112 break;
113 default:
114 // decisionHandler (WKNavigationActionPolicyCancel);
115 decisionHandler (WKNavigationActionPolicyAllow);
116 break;
117 }
118}
119
120- (void)webView:(WKWebView *)webView
121decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
122decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
123{
124 if (!navigationResponse.canShowMIMEType)
125 {
126 NSString *url = navigationResponse.response.URL.absoluteString;
127 NSString *mimetype = navigationResponse.response.MIMEType;
128 NSString *filename = navigationResponse.response.suggestedFilename;
129 decisionHandler (WKNavigationResponsePolicyCancel);
130 store_xwidget_download_callback_event (self.xw,
131 url.UTF8String,
132 mimetype.UTF8String,
133 filename.UTF8String);
134 return;
135 }
136 decisionHandler (WKNavigationResponsePolicyAllow);
137
138 self.urlScriptBlocked[navigationResponse.response.URL] =
139 [NSNumber numberWithBool:NO];
140 if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]])
141 {
142 NSDictionary *headers =
143 ((NSHTTPURLResponse *) navigationResponse.response).allHeaderFields;
144 NSString *value = headers[@"Content-Security-Policy"];
145 if (value)
146 {
147 /* TODO: Sloppy parsing of 'Content-Security-Policy' value. */
148 NSRange sandbox = [value rangeOfString:@"sandbox"];
149 if (sandbox.location != NSNotFound
150 && (sandbox.location == 0
151 || [value characterAtIndex:(sandbox.location - 1)] == ' '
152 || [value characterAtIndex:(sandbox.location - 1)] == ';'))
153 {
154 NSRange allowScripts = [value rangeOfString:@"allow-scripts"];
155 if (allowScripts.location == NSNotFound
156 || allowScripts.location < sandbox.location)
157 self.urlScriptBlocked[navigationResponse.response.URL] =
158 [NSNumber numberWithBool:YES];
159 }
160 }
161 }
162}
163
164/* No additional new webview or emacs window will be created
165 for <a ... target="_blank">. */
166- (WKWebView *)webView:(WKWebView *)webView
167createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
168 forNavigationAction:(WKNavigationAction *)navigationAction
169 windowFeatures:(WKWindowFeatures *)windowFeatures
170{
171 if (!navigationAction.targetFrame.isMainFrame)
172 [webView loadRequest:navigationAction.request];
173 return nil;
174}
175
176/* Open panel for file upload. */
177- (void)webView:(WKWebView *)webView
178runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters
179initiatedByFrame:(WKFrameInfo *)frame
180completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler
181{
182 NSOpenPanel *openPanel = [NSOpenPanel openPanel];
183 openPanel.canChooseFiles = YES;
184 openPanel.canChooseDirectories = NO;
185 openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection;
186 if ([openPanel runModal] == NSModalResponseOK)
187 completionHandler (openPanel.URLs);
188 else
189 completionHandler (nil);
190}
191
192/* By forwarding mouse events to emacs view (frame)
193 - Mouse click in webview selects the window contains the webview.
194 - Correct mouse hand/arrow/I-beam is displayed (TODO: not perfect yet).
195*/
196
197- (void)mouseDown:(NSEvent *)event
198{
199 [self.xw->xv->emacswindow mouseDown:event];
200 [super mouseDown:event];
201}
202
203- (void)mouseUp:(NSEvent *)event
204{
205 [self.xw->xv->emacswindow mouseUp:event];
206 [super mouseUp:event];
207}
208
209/* Basically we want keyboard events handled by emacs unless an input
210 element has focus. Especially, while incremental search, we set
211 emacs as first responder to avoid focus held in an input element
212 with matching text. */
213
214- (void)keyDown:(NSEvent *)event
215{
216 Lisp_Object var = Fintern (build_string ("isearch-mode"), Qnil);
217 Lisp_Object val = buffer_local_value (var, Fcurrent_buffer ());
218 if (!EQ (val, Qunbound) && !EQ (val, Qnil))
219 {
220 [self.window makeFirstResponder:self.xw->xv->emacswindow];
221 [self.xw->xv->emacswindow keyDown:event];
222 return;
223 }
224
225 /* Emacs handles keyboard events when javascript is blocked. */
226 if ([self.urlScriptBlocked[self.URL] boolValue])
227 {
228 [self.xw->xv->emacswindow keyDown:event];
229 return;
230 }
231
232 [self evaluateJavaScript:@"xwHasFocus()"
233 completionHandler:^(id result, NSError *error) {
234 if (error)
235 {
236 NSLog (@"xwHasFocus: %@", error);
237 [self.xw->xv->emacswindow keyDown:event];
238 }
239 else if (result)
240 {
241 NSNumber *hasFocus = result; /* __NSCFBoolean */
242 if (!hasFocus.boolValue)
243 [self.xw->xv->emacswindow keyDown:event];
244 else
245 [super keyDown:event];
246 }
247 }];
248}
249
250- (void)interpretKeyEvents:(NSArray<NSEvent *> *)eventArray
251{
252 /* We should do nothing and do not forward (default implementation
253 if we not override here) to let emacs collect key events and ask
254 interpretKeyEvents to its superclass. */
255}
256
257static NSString *xwScript;
258+ (void)initialize
259{
260 /* Find out if an input element has focus.
261 Message to script message handler when 'C-g' key down. */
262 if (!xwScript)
263 xwScript =
264 @"function xwHasFocus() {"
265 @" var ae = document.activeElement;"
266 @" if (ae) {"
267 @" var name = ae.nodeName;"
268 @" return name == 'INPUT' || name == 'TEXTAREA';"
269 @" } else {"
270 @" return false;"
271 @" }"
272 @"}"
273 @"function xwKeyDown(event) {"
274 @" if (event.ctrlKey && event.key == 'g') {"
275 @" window.webkit.messageHandlers.keyDown.postMessage('C-g');"
276 @" }"
277 @"}"
278 @"document.addEventListener('keydown', xwKeyDown);"
279 ;
280}
281
282/* Confirming to WKScriptMessageHandler, listens concerning keyDown in
283 webkit. Currently 'C-g'. */
284- (void)userContentController:(WKUserContentController *)userContentController
285 didReceiveScriptMessage:(WKScriptMessage *)message
286{
287 if ([message.body isEqualToString:@"C-g"])
288 {
289 /* Just give up focus, no relay "C-g" to emacs, another "C-g"
290 follows will be handled by emacs. */
291 [self.window makeFirstResponder:self.xw->xv->emacswindow];
292 }
293}
294
295@end
296
297/* Xwidget webkit commands. */
298
299static Lisp_Object build_string_with_nsstr (NSString *nsstr);
300
301bool
302nsxwidget_is_web_view (struct xwidget *xw)
303{
304 return xw->xwWidget != NULL &&
305 [xw->xwWidget isKindOfClass:WKWebView.class];
306}
307
308Lisp_Object
309nsxwidget_webkit_uri (struct xwidget *xw)
310{
311 XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
312 return build_string_with_nsstr (xwWebView.URL.absoluteString);
313}
314
315Lisp_Object
316nsxwidget_webkit_title (struct xwidget *xw)
317{
318 XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
319 return build_string_with_nsstr (xwWebView.title);
320}
321
322/* @Note ATS - Need application transport security in 'Info.plist' or
323 remote pages will not loaded. */
324void
325nsxwidget_webkit_goto_uri (struct xwidget *xw, const char *uri)
326{
327 XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
328 NSString *urlString = [NSString stringWithUTF8String:uri];
329 NSURL *url = [NSURL URLWithString:urlString];
330 NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
331 [xwWebView loadRequest:urlRequest];
332}
333
334void
335nsxwidget_webkit_goto_history (struct xwidget *xw, int rel_pos)
336{
337 XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
338 switch (rel_pos) {
339 case -1: [xwWebView goBack]; break;
340 case 0: [xwWebView reload]; break;
341 case 1: [xwWebView goForward]; break;
342 }
343}
344
345void
346nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change)
347{
348 XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
349 xwWebView.magnification += zoom_change;
350 /* TODO: setMagnification:centeredAtPoint. */
351}
352
353/* Build lisp string */
354static Lisp_Object
355build_string_with_nsstr (NSString *nsstr)
356{
357 const char *utfstr = [nsstr UTF8String];
358 NSUInteger bytes = [nsstr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
359 return make_string (utfstr, bytes);
360}
361
362/* Recursively convert an objc native type JavaScript value to a Lisp
363 value. Mostly copied from GTK xwidget 'webkit_js_to_lisp'. */
364static Lisp_Object
365js_to_lisp (id value)
366{
367 if (value == nil || [value isKindOfClass:NSNull.class])
368 return Qnil;
369 else if ([value isKindOfClass:NSString.class])
370 return build_string_with_nsstr ((NSString *) value);
371 else if ([value isKindOfClass:NSNumber.class])
372 {
373 NSNumber *nsnum = (NSNumber *) value;
374 char type = nsnum.objCType[0];
375 if (type == 'c') /* __NSCFBoolean has type character 'c'. */
376 return nsnum.boolValue? Qt : Qnil;
377 else
378 {
379 if (type == 'i' || type == 'l')
380 return make_int (nsnum.longValue);
381 else if (type == 'f' || type == 'd')
382 return make_float (nsnum.doubleValue);
383 /* else fall through. */
384 }
385 }
386 else if ([value isKindOfClass:NSArray.class])
387 {
388 NSArray *nsarr = (NSArray *) value;
389 EMACS_INT n = nsarr.count;
390 Lisp_Object obj;
391 struct Lisp_Vector *p = allocate_vector (n);
392
393 for (ptrdiff_t i = 0; i < n; ++i)
394 p->contents[i] = js_to_lisp ([nsarr objectAtIndex:i]);
395 XSETVECTOR (obj, p);
396 return obj;
397 }
398 else if ([value isKindOfClass:NSDictionary.class])
399 {
400 NSDictionary *nsdict = (NSDictionary *) value;
401 NSArray *keys = nsdict.allKeys;
402 ptrdiff_t n = keys.count;
403 Lisp_Object obj;
404 struct Lisp_Vector *p = allocate_vector (n);
405
406 for (ptrdiff_t i = 0; i < n; ++i)
407 {
408 NSString *prop_key = (NSString *) [keys objectAtIndex:i];
409 id prop_value = [nsdict valueForKey:prop_key];
410 p->contents[i] = Fcons (build_string_with_nsstr (prop_key),
411 js_to_lisp (prop_value));
412 }
413 XSETVECTOR (obj, p);
414 return obj;
415 }
416 NSLog (@"Unhandled type in javascript result");
417 return Qnil;
418}
419
420void
421nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
422 Lisp_Object fun)
423{
424 XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
425 if ([xwWebView.urlScriptBlocked[xwWebView.URL] boolValue])
426 {
427 message ("Javascript is blocked by 'CSP: sandbox'.");
428 return;
429 }
430
431 NSString *javascriptString = [NSString stringWithUTF8String:script];
432 [xwWebView evaluateJavaScript:javascriptString
433 completionHandler:^(id result, NSError *error) {
434 if (error)
435 {
436 NSLog (@"evaluateJavaScript error : %@", error.localizedDescription);
437 NSLog (@"error script=%@", javascriptString);
438 }
439 else if (result && FUNCTIONP (fun))
440 {
441 // NSLog (@"result=%@, type=%@", result, [result class]);
442 Lisp_Object lisp_value = js_to_lisp (result);
443 store_xwidget_js_callback_event (xw, fun, lisp_value);
444 }
445 }];
446}
447
448/* Window containing an xwidget. */
449
450@implementation XwWindow
451- (BOOL)isFlipped { return YES; }
452@end
453
454/* Xwidget model, macOS Cocoa part. */
455
456void
457nsxwidget_init(struct xwidget *xw)
458{
459 block_input ();
460 NSRect rect = NSMakeRect (0, 0, xw->width, xw->height);
461 xw->xwWidget = [[XwWebView alloc]
462 initWithFrame:rect
463 configuration:[[WKWebViewConfiguration alloc] init]
464 xwidget:xw];
465 xw->xwWindow = [[XwWindow alloc]
466 initWithFrame:rect];
467 [xw->xwWindow addSubview:xw->xwWidget];
468 xw->xv = NULL; /* for 1 to 1 relationship of webkit2. */
469 unblock_input ();
470}
471
472void
473nsxwidget_kill (struct xwidget *xw)
474{
475 if (xw)
476 {
477 WKUserContentController *scriptor =
478 ((XwWebView *) xw->xwWidget).configuration.userContentController;
479 [scriptor removeAllUserScripts];
480 [scriptor removeScriptMessageHandlerForName:@"keyDown"];
481 [scriptor release];
482 if (xw->xv)
483 xw->xv->model = Qnil; /* Make sure related view stale. */
484
485 /* This stops playing audio when a xwidget-webkit buffer is
486 killed. I could not find other solution. */
487 nsxwidget_webkit_goto_uri (xw, "about:blank");
488
489 [((XwWebView *) xw->xwWidget).urlScriptBlocked release];
490 [xw->xwWidget removeFromSuperviewWithoutNeedingDisplay];
491 [xw->xwWidget release];
492 [xw->xwWindow removeFromSuperviewWithoutNeedingDisplay];
493 [xw->xwWindow release];
494 xw->xwWidget = nil;
495 }
496}
497
498void
499nsxwidget_resize (struct xwidget *xw)
500{
501 if (xw->xwWidget)
502 {
503 [xw->xwWindow setFrameSize:NSMakeSize(xw->width, xw->height)];
504 [xw->xwWidget setFrameSize:NSMakeSize(xw->width, xw->height)];
505 }
506}
507
508Lisp_Object
509nsxwidget_get_size (struct xwidget *xw)
510{
511 return list2i (xw->xwWidget.frame.size.width,
512 xw->xwWidget.frame.size.height);
513}
514
515/* Xwidget view, macOS Cocoa part. */
516
517@implementation XvWindow : NSView
518- (BOOL)isFlipped { return YES; }
519@end
520
521void
522nsxwidget_init_view (struct xwidget_view *xv,
523 struct xwidget *xw,
524 struct glyph_string *s,
525 int x, int y)
526{
527 /* 'x_draw_xwidget_glyph_string' will calculate correct position and
528 size of clip to draw in emacs buffer window. Thus, just begin at
529 origin with no crop. */
530 xv->x = x;
531 xv->y = y;
532 xv->clip_left = 0;
533 xv->clip_right = xw->width;
534 xv->clip_top = 0;
535 xv->clip_bottom = xw->height;
536
537 xv->xvWindow = [[XvWindow alloc]
538 initWithFrame:NSMakeRect (x, y, xw->width, xw->height)];
539 xv->xvWindow.xw = xw;
540 xv->xvWindow.xv = xv;
541
542 xw->xv = xv; /* For 1 to 1 relationship of webkit2. */
543 [xv->xvWindow addSubview:xw->xwWindow];
544
545 xv->emacswindow = FRAME_NS_VIEW (s->f);
546 [xv->emacswindow addSubview:xv->xvWindow];
547}
548
549void
550nsxwidget_delete_view (struct xwidget_view *xv)
551{
552 if (!EQ (xv->model, Qnil))
553 {
554 struct xwidget *xw = XXWIDGET (xv->model);
555 [xw->xwWindow removeFromSuperviewWithoutNeedingDisplay];
556 xw->xv = NULL; /* Now model has no view. */
557 }
558 [xv->xvWindow removeFromSuperviewWithoutNeedingDisplay];
559 [xv->xvWindow release];
560}
561
562void
563nsxwidget_show_view (struct xwidget_view *xv)
564{
565 xv->hidden = NO;
566 [xv->xvWindow setFrameOrigin:NSMakePoint(xv->x + xv->clip_left,
567 xv->y + xv->clip_top)];
568}
569
570void
571nsxwidget_hide_view (struct xwidget_view *xv)
572{
573 xv->hidden = YES;
574 [xv->xvWindow setFrameOrigin:NSMakePoint(10000, 10000)];
575}
576
577void
578nsxwidget_resize_view (struct xwidget_view *xv, int width, int height)
579{
580 [xv->xvWindow setFrameSize:NSMakeSize(width, height)];
581}
582
583void
584nsxwidget_move_view (struct xwidget_view *xv, int x, int y)
585{
586 [xv->xvWindow setFrameOrigin:NSMakePoint (x, y)];
587}
588
589/* Move model window in container (view window). */
590void
591nsxwidget_move_widget_in_view (struct xwidget_view *xv, int x, int y)
592{
593 struct xwidget *xww = xv->xvWindow.xw;
594 [xww->xwWindow setFrameOrigin:NSMakePoint (x, y)];
595}
596
597void
598nsxwidget_set_needsdisplay (struct xwidget_view *xv)
599{
600 xv->xvWindow.needsDisplay = YES;
601}
diff --git a/src/pdumper.c b/src/pdumper.c
index de9c06c9d2c..c55b6f7bb43 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -71,17 +71,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
71#ifdef HAVE_PDUMPER 71#ifdef HAVE_PDUMPER
72 72
73#if GNUC_PREREQ (4, 7, 0) 73#if GNUC_PREREQ (4, 7, 0)
74# pragma GCC diagnostic error "-Wconversion"
75# pragma GCC diagnostic ignored "-Wsign-conversion"
76# pragma GCC diagnostic error "-Wshadow" 74# pragma GCC diagnostic error "-Wshadow"
77# define ALLOW_IMPLICIT_CONVERSION \
78 _Pragma ("GCC diagnostic push") \
79 _Pragma ("GCC diagnostic ignored \"-Wconversion\"")
80# define DISALLOW_IMPLICIT_CONVERSION \
81 _Pragma ("GCC diagnostic pop")
82#else
83# define ALLOW_IMPLICIT_CONVERSION ((void) 0)
84# define DISALLOW_IMPLICIT_CONVERSION ((void) 0)
85#endif 75#endif
86 76
87#define VM_POSIX 1 77#define VM_POSIX 1
@@ -105,17 +95,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
105# define VM_SUPPORTED 0 95# define VM_SUPPORTED 0
106#endif 96#endif
107 97
108/* PDUMPER_CHECK_REHASHING being true causes the portable dumper to
109 check, for each hash table it dumps, that the hash table means the
110 same thing after rehashing. */
111#ifndef PDUMPER_CHECK_REHASHING
112# if ENABLE_CHECKING
113# define PDUMPER_CHECK_REHASHING 1
114# else
115# define PDUMPER_CHECK_REHASHING 0
116# endif
117#endif
118
119/* Require an architecture in which pointers, ptrdiff_t and intptr_t 98/* Require an architecture in which pointers, ptrdiff_t and intptr_t
120 are the same size and have the same layout, and where bytes have 99 are the same size and have the same layout, and where bytes have
121 eight bits --- that is, a general-purpose computer made after 1990. 100 eight bits --- that is, a general-purpose computer made after 1990.
@@ -152,8 +131,11 @@ static int nr_remembered_data = 0;
152typedef int_least32_t dump_off; 131typedef int_least32_t dump_off;
153#define DUMP_OFF_MIN INT_LEAST32_MIN 132#define DUMP_OFF_MIN INT_LEAST32_MIN
154#define DUMP_OFF_MAX INT_LEAST32_MAX 133#define DUMP_OFF_MAX INT_LEAST32_MAX
134#define PRIdDUMP_OFF PRIdLEAST32
135
136enum { EMACS_INT_XDIGITS = (EMACS_INT_WIDTH + 3) / 4 };
155 137
156static void ATTRIBUTE_FORMAT ((printf, 1, 2)) 138static void ATTRIBUTE_FORMAT_PRINTF (1, 2)
157dump_trace (const char *fmt, ...) 139dump_trace (const char *fmt, ...)
158{ 140{
159 if (0) 141 if (0)
@@ -326,9 +308,7 @@ static void
326dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset) 308dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset)
327{ 309{
328 eassert (offset >= 0); 310 eassert (offset >= 0);
329 ALLOW_IMPLICIT_CONVERSION;
330 reloc->raw_offset = offset >> DUMP_RELOC_ALIGNMENT_BITS; 311 reloc->raw_offset = offset >> DUMP_RELOC_ALIGNMENT_BITS;
331 DISALLOW_IMPLICIT_CONVERSION;
332 if (dump_reloc_get_offset (*reloc) != offset) 312 if (dump_reloc_get_offset (*reloc) != offset)
333 error ("dump relocation out of range"); 313 error ("dump relocation out of range");
334} 314}
@@ -417,6 +397,9 @@ struct dump_header
417 The start of the cold region is always aligned on a page 397 The start of the cold region is always aligned on a page
418 boundary. */ 398 boundary. */
419 dump_off cold_start; 399 dump_off cold_start;
400
401 /* Offset of a vector of the dumped hash tables. */
402 dump_off hash_list;
420}; 403};
421 404
422/* Double-ended singly linked list. */ 405/* Double-ended singly linked list. */
@@ -575,8 +558,11 @@ struct dump_context
575 heap objects. */ 558 heap objects. */
576 Lisp_Object bignum_data; 559 Lisp_Object bignum_data;
577 560
578 unsigned number_hot_relocations; 561 /* List of hash tables that have been dumped. */
579 unsigned number_discardable_relocations; 562 Lisp_Object hash_tables;
563
564 dump_off number_hot_relocations;
565 dump_off number_discardable_relocations;
580}; 566};
581 567
582/* These special values for use as offsets in dump_remember_object and 568/* These special values for use as offsets in dump_remember_object and
@@ -763,10 +749,7 @@ dump_off_from_lisp (Lisp_Object value)
763{ 749{
764 intmax_t n = intmax_t_from_lisp (value); 750 intmax_t n = intmax_t_from_lisp (value);
765 eassert (DUMP_OFF_MIN <= n && n <= DUMP_OFF_MAX); 751 eassert (DUMP_OFF_MIN <= n && n <= DUMP_OFF_MAX);
766 ALLOW_IMPLICIT_CONVERSION; 752 return n;
767 dump_off converted = n;
768 DISALLOW_IMPLICIT_CONVERSION;
769 return converted;
770} 753}
771 754
772static Lisp_Object 755static Lisp_Object
@@ -983,11 +966,9 @@ dump_queue_init (struct dump_queue *dump_queue)
983static bool 966static bool
984dump_queue_empty_p (struct dump_queue *dump_queue) 967dump_queue_empty_p (struct dump_queue *dump_queue)
985{ 968{
986 bool is_empty = 969 ptrdiff_t count = XHASH_TABLE (dump_queue->sequence_numbers)->count;
987 EQ (Fhash_table_count (dump_queue->sequence_numbers), 970 bool is_empty = count == 0;
988 make_fixnum (0)); 971 eassert (count == XFIXNAT (Fhash_table_count (dump_queue->link_weights)));
989 eassert (EQ (Fhash_table_count (dump_queue->sequence_numbers),
990 Fhash_table_count (dump_queue->link_weights)));
991 if (!is_empty) 972 if (!is_empty)
992 { 973 {
993 eassert (!dump_tailq_empty_p (&dump_queue->zero_weight_objects) 974 eassert (!dump_tailq_empty_p (&dump_queue->zero_weight_objects)
@@ -1029,9 +1010,9 @@ dump_queue_enqueue (struct dump_queue *dump_queue,
1029 if (NILP (weights)) 1010 if (NILP (weights))
1030 { 1011 {
1031 /* Object is new. */ 1012 /* Object is new. */
1032 dump_trace ("new object %016x weight=%u\n", 1013 EMACS_UINT uobj = XLI (object);
1033 (unsigned) XLI (object), 1014 dump_trace ("new object %0*"pI"x weight=%d\n", EMACS_INT_XDIGITS, uobj,
1034 (unsigned) weight.value); 1015 weight.value);
1035 1016
1036 if (weight.value == WEIGHT_NONE.value) 1017 if (weight.value == WEIGHT_NONE.value)
1037 { 1018 {
@@ -1246,17 +1227,15 @@ dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis)
1246 + dump_tailq_length (&dump_queue->one_weight_normal_objects) 1227 + dump_tailq_length (&dump_queue->one_weight_normal_objects)
1247 + dump_tailq_length (&dump_queue->one_weight_strong_objects))); 1228 + dump_tailq_length (&dump_queue->one_weight_strong_objects)));
1248 1229
1249 bool dump_object_counts = true; 1230 dump_trace
1250 if (dump_object_counts) 1231 (("dump_queue_dequeue basis=%"PRIdDUMP_OFF" fancy=%"PRIdPTR
1251 dump_trace 1232 " zero=%"PRIdPTR" normal=%"PRIdPTR" strong=%"PRIdPTR" hash=%td\n"),
1252 ("dump_queue_dequeue basis=%d fancy=%u zero=%u " 1233 basis,
1253 "normal=%u strong=%u hash=%u\n", 1234 dump_tailq_length (&dump_queue->fancy_weight_objects),
1254 basis, 1235 dump_tailq_length (&dump_queue->zero_weight_objects),
1255 (unsigned) dump_tailq_length (&dump_queue->fancy_weight_objects), 1236 dump_tailq_length (&dump_queue->one_weight_normal_objects),
1256 (unsigned) dump_tailq_length (&dump_queue->zero_weight_objects), 1237 dump_tailq_length (&dump_queue->one_weight_strong_objects),
1257 (unsigned) dump_tailq_length (&dump_queue->one_weight_normal_objects), 1238 XHASH_TABLE (dump_queue->link_weights)->count);
1258 (unsigned) dump_tailq_length (&dump_queue->one_weight_strong_objects),
1259 (unsigned) XFIXNUM (Fhash_table_count (dump_queue->link_weights)));
1260 1239
1261 static const int nr_candidates = 3; 1240 static const int nr_candidates = 3;
1262 struct candidate 1241 struct candidate
@@ -1329,10 +1308,10 @@ dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis)
1329 else 1308 else
1330 emacs_abort (); 1309 emacs_abort ();
1331 1310
1332 dump_trace (" result score=%f src=%s object=%016x\n", 1311 EMACS_UINT uresult = XLI (result);
1312 dump_trace (" result score=%f src=%s object=%0*"pI"x\n",
1333 best < 0 ? -1.0 : (double) candidates[best].score, 1313 best < 0 ? -1.0 : (double) candidates[best].score,
1334 src, 1314 src, EMACS_INT_XDIGITS, uresult);
1335 (unsigned) XLI (result));
1336 1315
1337 { 1316 {
1338 Lisp_Object weights = Fgethash (result, dump_queue->link_weights, Qnil); 1317 Lisp_Object weights = Fgethash (result, dump_queue->link_weights, Qnil);
@@ -2017,11 +1996,7 @@ static dump_off
2017finish_dump_pvec (struct dump_context *ctx, 1996finish_dump_pvec (struct dump_context *ctx,
2018 union vectorlike_header *out_hdr) 1997 union vectorlike_header *out_hdr)
2019{ 1998{
2020 ALLOW_IMPLICIT_CONVERSION; 1999 return dump_object_finish (ctx, out_hdr, vectorlike_nbytes (out_hdr));
2021 dump_off result = dump_object_finish (ctx, out_hdr,
2022 vectorlike_nbytes (out_hdr));
2023 DISALLOW_IMPLICIT_CONVERSION;
2024 return result;
2025} 2000}
2026 2001
2027static void 2002static void
@@ -2633,78 +2608,65 @@ dump_vectorlike_generic (struct dump_context *ctx,
2633 return offset; 2608 return offset;
2634} 2609}
2635 2610
2636/* Determine whether the hash table's hash order is stable 2611/* Return a vector of KEY, VALUE pairs in the given hash table H. The
2637 across dump and load. If it is, we don't have to trigger 2612 first H->count pairs are valid, and the rest are unbound. */
2638 a rehash on access. */ 2613static Lisp_Object
2639static bool 2614hash_table_contents (struct Lisp_Hash_Table *h)
2640dump_hash_table_stable_p (const struct Lisp_Hash_Table *hash)
2641{ 2615{
2642 if (hash->test.hashfn == hashfn_user_defined) 2616 if (h->test.hashfn == hashfn_user_defined)
2643 error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */ 2617 error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */
2644 bool is_eql = hash->test.hashfn == hashfn_eql; 2618
2645 bool is_equal = hash->test.hashfn == hashfn_equal; 2619 ptrdiff_t size = HASH_TABLE_SIZE (h);
2646 ptrdiff_t size = HASH_TABLE_SIZE (hash); 2620 Lisp_Object key_and_value = make_uninit_vector (2 * size);
2647 for (ptrdiff_t i = 0; i < size; ++i) 2621 ptrdiff_t n = 0;
2622
2623 /* Make sure key_and_value ends up in the same order; charset.c
2624 relies on it by expecting hash table indices to stay constant
2625 across the dump. */
2626 for (ptrdiff_t i = 0; i < size; i++)
2627 if (!NILP (HASH_HASH (h, i)))
2628 {
2629 ASET (key_and_value, n++, HASH_KEY (h, i));
2630 ASET (key_and_value, n++, HASH_VALUE (h, i));
2631 }
2632
2633 while (n < 2 * size)
2648 { 2634 {
2649 Lisp_Object key = HASH_KEY (hash, i); 2635 ASET (key_and_value, n++, Qunbound);
2650 if (!EQ (key, Qunbound)) 2636 ASET (key_and_value, n++, Qnil);
2651 {
2652 bool key_stable = (dump_builtin_symbol_p (key)
2653 || FIXNUMP (key)
2654 || (is_equal
2655 && (STRINGP (key) || BOOL_VECTOR_P (key)))
2656 || ((is_equal || is_eql)
2657 && (FLOATP (key) || BIGNUMP (key))));
2658 if (!key_stable)
2659 return false;
2660 }
2661 } 2637 }
2662 2638
2663 return true; 2639 return key_and_value;
2664} 2640}
2665 2641
2666/* Return a list of (KEY . VALUE) pairs in the given hash table. */ 2642static dump_off
2667static Lisp_Object 2643dump_hash_table_list (struct dump_context *ctx)
2668hash_table_contents (Lisp_Object table)
2669{ 2644{
2670 Lisp_Object contents = Qnil; 2645 if (!NILP (ctx->hash_tables))
2671 struct Lisp_Hash_Table *h = XHASH_TABLE (table); 2646 return dump_object (ctx, CALLN (Fapply, Qvector, ctx->hash_tables));
2672 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) 2647 else
2673 { 2648 return 0;
2674 Lisp_Object key = HASH_KEY (h, i);
2675 if (!EQ (key, Qunbound))
2676 dump_push (&contents, Fcons (key, HASH_VALUE (h, i)));
2677 }
2678 return Fnreverse (contents);
2679} 2649}
2680 2650
2681/* Copy the given hash table, rehash it, and make sure that we can
2682 look up all the values in the original. */
2683static void 2651static void
2684check_hash_table_rehash (Lisp_Object table_orig) 2652hash_table_freeze (struct Lisp_Hash_Table *h)
2685{ 2653{
2686 ptrdiff_t count = XHASH_TABLE (table_orig)->count; 2654 ptrdiff_t npairs = ASIZE (h->key_and_value) / 2;
2687 hash_rehash_if_needed (XHASH_TABLE (table_orig)); 2655 h->key_and_value = hash_table_contents (h);
2688 Lisp_Object table_rehashed = Fcopy_hash_table (table_orig); 2656 h->next = h->hash = make_fixnum (npairs);
2689 eassert (!hash_rehash_needed_p (XHASH_TABLE (table_rehashed))); 2657 h->index = make_fixnum (ASIZE (h->index));
2690 XHASH_TABLE (table_rehashed)->hash = Qnil; 2658 h->next_free = (npairs == h->count ? -1 : h->count);
2691 eassert (count == 0 || hash_rehash_needed_p (XHASH_TABLE (table_rehashed))); 2659}
2692 hash_rehash_if_needed (XHASH_TABLE (table_rehashed));
2693 eassert (!hash_rehash_needed_p (XHASH_TABLE (table_rehashed)));
2694 Lisp_Object expected_contents = hash_table_contents (table_orig);
2695 while (!NILP (expected_contents))
2696 {
2697 Lisp_Object key_value_pair = dump_pop (&expected_contents);
2698 Lisp_Object key = XCAR (key_value_pair);
2699 Lisp_Object expected_value = XCDR (key_value_pair);
2700 Lisp_Object arbitrary = Qdump_emacs_portable__sort_predicate_copied;
2701 Lisp_Object found_value = Fgethash (key, table_rehashed, arbitrary);
2702 eassert (EQ (expected_value, found_value));
2703 Fremhash (key, table_rehashed);
2704 }
2705 2660
2706 eassert (EQ (Fhash_table_count (table_rehashed), 2661static void
2707 make_fixnum (0))); 2662hash_table_thaw (Lisp_Object hash)
2663{
2664 struct Lisp_Hash_Table *h = XHASH_TABLE (hash);
2665 h->hash = make_nil_vector (XFIXNUM (h->hash));
2666 h->next = Fmake_vector (h->next, make_fixnum (-1));
2667 h->index = Fmake_vector (h->index, make_fixnum (-1));
2668
2669 hash_table_rehash (hash);
2708} 2670}
2709 2671
2710static dump_off 2672static dump_off
@@ -2712,55 +2674,15 @@ dump_hash_table (struct dump_context *ctx,
2712 Lisp_Object object, 2674 Lisp_Object object,
2713 dump_off offset) 2675 dump_off offset)
2714{ 2676{
2715#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_12AFBF47AF 2677#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_6D63EDB618
2716# error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h." 2678# error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h."
2717#endif 2679#endif
2718 const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object); 2680 const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object);
2719 bool is_stable = dump_hash_table_stable_p (hash_in);
2720 /* If the hash table is likely to be modified in memory (either
2721 because we need to rehash, and thus toggle hash->count, or
2722 because we need to assemble a list of weak tables) punt the hash
2723 table to the end of the dump, where we can lump all such hash
2724 tables together. */
2725 if (!(is_stable || !NILP (hash_in->weak))
2726 && ctx->flags.defer_hash_tables)
2727 {
2728 if (offset != DUMP_OBJECT_ON_HASH_TABLE_QUEUE)
2729 {
2730 eassert (offset == DUMP_OBJECT_ON_NORMAL_QUEUE
2731 || offset == DUMP_OBJECT_NOT_SEEN);
2732 /* We still want to dump the actual keys and values now. */
2733 dump_enqueue_object (ctx, hash_in->key_and_value, WEIGHT_NONE);
2734 /* We'll get to the rest later. */
2735 offset = DUMP_OBJECT_ON_HASH_TABLE_QUEUE;
2736 dump_remember_object (ctx, object, offset);
2737 dump_push (&ctx->deferred_hash_tables, object);
2738 }
2739 return offset;
2740 }
2741
2742 if (PDUMPER_CHECK_REHASHING)
2743 check_hash_table_rehash (make_lisp_ptr ((void *) hash_in, Lisp_Vectorlike));
2744
2745 struct Lisp_Hash_Table hash_munged = *hash_in; 2681 struct Lisp_Hash_Table hash_munged = *hash_in;
2746 struct Lisp_Hash_Table *hash = &hash_munged; 2682 struct Lisp_Hash_Table *hash = &hash_munged;
2747 2683
2748 /* Remember to rehash this hash table on first access. After a 2684 hash_table_freeze (hash);
2749 dump reload, the hash table values will have changed, so we'll 2685 dump_push (&ctx->hash_tables, object);
2750 need to rebuild the index.
2751
2752 TODO: for EQ and EQL hash tables, it should be possible to rehash
2753 here using the preferred load address of the dump, eliminating
2754 the need to rehash-on-access if we can load the dump where we
2755 want. */
2756 if (hash->count > 0 && !is_stable)
2757 /* Hash codes will have to be recomputed anyway, so let's not dump them.
2758 Also set `hash` to nil for hash_rehash_needed_p.
2759 We could also refrain from dumping the `next' and `index' vectors,
2760 except that `next' is currently used for HASH_TABLE_SIZE and
2761 we'd have to rebuild the next_free list as well as adjust
2762 sweep_weak_hash_table for the case where there's no `index'. */
2763 hash->hash = Qnil;
2764 2686
2765 START_DUMP_PVEC (ctx, &hash->header, struct Lisp_Hash_Table, out); 2687 START_DUMP_PVEC (ctx, &hash->header, struct Lisp_Hash_Table, out);
2766 dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header); 2688 dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header);
@@ -3429,9 +3351,7 @@ static void
3429dump_cold_charset (struct dump_context *ctx, Lisp_Object data) 3351dump_cold_charset (struct dump_context *ctx, Lisp_Object data)
3430{ 3352{
3431 /* Dump charset lookup tables. */ 3353 /* Dump charset lookup tables. */
3432 ALLOW_IMPLICIT_CONVERSION;
3433 int cs_i = XFIXNUM (XCAR (data)); 3354 int cs_i = XFIXNUM (XCAR (data));
3434 DISALLOW_IMPLICIT_CONVERSION;
3435 dump_off cs_dump_offset = dump_off_from_lisp (XCDR (data)); 3355 dump_off cs_dump_offset = dump_off_from_lisp (XCDR (data));
3436 dump_remember_fixup_ptr_raw 3356 dump_remember_fixup_ptr_raw
3437 (ctx, 3357 (ctx,
@@ -3767,9 +3687,7 @@ static struct emacs_reloc
3767decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc) 3687decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3768{ 3688{
3769 struct emacs_reloc reloc = {0}; 3689 struct emacs_reloc reloc = {0};
3770 ALLOW_IMPLICIT_CONVERSION;
3771 int type = XFIXNUM (dump_pop (&lreloc)); 3690 int type = XFIXNUM (dump_pop (&lreloc));
3772 DISALLOW_IMPLICIT_CONVERSION;
3773 reloc.emacs_offset = dump_off_from_lisp (dump_pop (&lreloc)); 3691 reloc.emacs_offset = dump_off_from_lisp (dump_pop (&lreloc));
3774 dump_check_emacs_off (reloc.emacs_offset); 3692 dump_check_emacs_off (reloc.emacs_offset);
3775 switch (type) 3693 switch (type)
@@ -3780,9 +3698,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3780 reloc.u.dump_offset = dump_off_from_lisp (dump_pop (&lreloc)); 3698 reloc.u.dump_offset = dump_off_from_lisp (dump_pop (&lreloc));
3781 dump_check_dump_off (ctx, reloc.u.dump_offset); 3699 dump_check_dump_off (ctx, reloc.u.dump_offset);
3782 dump_off length = dump_off_from_lisp (dump_pop (&lreloc)); 3700 dump_off length = dump_off_from_lisp (dump_pop (&lreloc));
3783 ALLOW_IMPLICIT_CONVERSION;
3784 reloc.length = length; 3701 reloc.length = length;
3785 DISALLOW_IMPLICIT_CONVERSION;
3786 if (reloc.length != length) 3702 if (reloc.length != length)
3787 error ("relocation copy length too large"); 3703 error ("relocation copy length too large");
3788 } 3704 }
@@ -3793,9 +3709,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3793 intmax_t value = intmax_t_from_lisp (dump_pop (&lreloc)); 3709 intmax_t value = intmax_t_from_lisp (dump_pop (&lreloc));
3794 dump_off size = dump_off_from_lisp (dump_pop (&lreloc)); 3710 dump_off size = dump_off_from_lisp (dump_pop (&lreloc));
3795 reloc.u.immediate = value; 3711 reloc.u.immediate = value;
3796 ALLOW_IMPLICIT_CONVERSION;
3797 reloc.length = size; 3712 reloc.length = size;
3798 DISALLOW_IMPLICIT_CONVERSION;
3799 eassert (reloc.length == size); 3713 eassert (reloc.length == size);
3800 } 3714 }
3801 break; 3715 break;
@@ -3820,9 +3734,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3820 RELOC_EMACS_IMMEDIATE relocation instead. */ 3734 RELOC_EMACS_IMMEDIATE relocation instead. */
3821 eassert (!dump_object_self_representing_p (target_value)); 3735 eassert (!dump_object_self_representing_p (target_value));
3822 int tag_type = XTYPE (target_value); 3736 int tag_type = XTYPE (target_value);
3823 ALLOW_IMPLICIT_CONVERSION;
3824 reloc.length = tag_type; 3737 reloc.length = tag_type;
3825 DISALLOW_IMPLICIT_CONVERSION;
3826 eassert (reloc.length == tag_type); 3738 eassert (reloc.length == tag_type);
3827 3739
3828 if (type == RELOC_EMACS_EMACS_LV) 3740 if (type == RELOC_EMACS_EMACS_LV)
@@ -3897,9 +3809,7 @@ dump_merge_emacs_relocs (Lisp_Object lreloc_a, Lisp_Object lreloc_b)
3897 return Qnil; 3809 return Qnil;
3898 3810
3899 dump_off new_length = reloc_a.length + reloc_b.length; 3811 dump_off new_length = reloc_a.length + reloc_b.length;
3900 ALLOW_IMPLICIT_CONVERSION;
3901 reloc_a.length = new_length; 3812 reloc_a.length = new_length;
3902 DISALLOW_IMPLICIT_CONVERSION;
3903 if (reloc_a.length != new_length) 3813 if (reloc_a.length != new_length)
3904 return Qnil; /* Overflow */ 3814 return Qnil; /* Overflow */
3905 3815
@@ -4254,6 +4164,19 @@ types. */)
4254 || !NILP (ctx->deferred_hash_tables) 4164 || !NILP (ctx->deferred_hash_tables)
4255 || !NILP (ctx->deferred_symbols)); 4165 || !NILP (ctx->deferred_symbols));
4256 4166
4167 ctx->header.hash_list = ctx->offset;
4168 dump_hash_table_list (ctx);
4169
4170 do
4171 {
4172 dump_drain_deferred_hash_tables (ctx);
4173 dump_drain_deferred_symbols (ctx);
4174 dump_drain_normal_queue (ctx);
4175 }
4176 while (!dump_queue_empty_p (&ctx->dump_queue)
4177 || !NILP (ctx->deferred_hash_tables)
4178 || !NILP (ctx->deferred_symbols));
4179
4257 dump_sort_copied_objects (ctx); 4180 dump_sort_copied_objects (ctx);
4258 4181
4259 /* While we copy built-in symbols into the Emacs image, these 4182 /* While we copy built-in symbols into the Emacs image, these
@@ -4314,9 +4237,9 @@ types. */)
4314 for (int i = 0; i < RELOC_NUM_PHASES; ++i) 4237 for (int i = 0; i < RELOC_NUM_PHASES; ++i)
4315 drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger, 4238 drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger,
4316 &ctx->dump_relocs[i], &ctx->header.dump_relocs[i]); 4239 &ctx->dump_relocs[i], &ctx->header.dump_relocs[i]);
4317 unsigned number_hot_relocations = ctx->number_hot_relocations; 4240 dump_off number_hot_relocations = ctx->number_hot_relocations;
4318 ctx->number_hot_relocations = 0; 4241 ctx->number_hot_relocations = 0;
4319 unsigned number_discardable_relocations = ctx->number_discardable_relocations; 4242 dump_off number_discardable_relocations = ctx->number_discardable_relocations;
4320 ctx->number_discardable_relocations = 0; 4243 ctx->number_discardable_relocations = 0;
4321 drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger, 4244 drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger,
4322 &ctx->object_starts, &ctx->header.object_starts); 4245 &ctx->object_starts, &ctx->header.object_starts);
@@ -4341,14 +4264,17 @@ types. */)
4341 dump_seek (ctx, 0); 4264 dump_seek (ctx, 0);
4342 dump_write (ctx, &ctx->header, sizeof (ctx->header)); 4265 dump_write (ctx, &ctx->header, sizeof (ctx->header));
4343 4266
4267 dump_off
4268 header_bytes = header_end - header_start,
4269 hot_bytes = hot_end - hot_start,
4270 discardable_bytes = discardable_end - ctx->header.discardable_start,
4271 cold_bytes = cold_end - ctx->header.cold_start;
4344 fprintf (stderr, 4272 fprintf (stderr,
4345 ("Dump complete\n" 4273 ("Dump complete\n"
4346 "Byte counts: header=%lu hot=%lu discardable=%lu cold=%lu\n" 4274 "Byte counts: header=%"PRIdDUMP_OFF" hot=%"PRIdDUMP_OFF
4347 "Reloc counts: hot=%u discardable=%u\n"), 4275 " discardable=%"PRIdDUMP_OFF" cold=%"PRIdDUMP_OFF"\n"
4348 (unsigned long) (header_end - header_start), 4276 "Reloc counts: hot=%"PRIdDUMP_OFF" discardable=%"PRIdDUMP_OFF"\n"),
4349 (unsigned long) (hot_end - hot_start), 4277 header_bytes, hot_bytes, discardable_bytes, cold_bytes,
4350 (unsigned long) (discardable_end - ctx->header.discardable_start),
4351 (unsigned long) (cold_end - ctx->header.cold_start),
4352 number_hot_relocations, 4278 number_hot_relocations,
4353 number_discardable_relocations); 4279 number_discardable_relocations);
4354 4280
@@ -5214,14 +5140,13 @@ dump_read_all (int fd, void *buf, size_t bytes_to_read)
5214{ 5140{
5215 /* We don't want to use emacs_read, since that relies on the lisp 5141 /* We don't want to use emacs_read, since that relies on the lisp
5216 world, and we're not in the lisp world yet. */ 5142 world, and we're not in the lisp world yet. */
5217 eassert (bytes_to_read <= SSIZE_MAX);
5218 size_t bytes_read = 0; 5143 size_t bytes_read = 0;
5219 while (bytes_read < bytes_to_read) 5144 while (bytes_read < bytes_to_read)
5220 { 5145 {
5221 /* Some platforms accept only int-sized values to read. */ 5146 /* Some platforms accept only int-sized values to read.
5222 unsigned chunk_to_read = INT_MAX; 5147 Round this down to a page size (see MAX_RW_COUNT in sysdep.c). */
5223 if (bytes_to_read - bytes_read < chunk_to_read) 5148 int max_rw_count = INT_MAX >> 18 << 18;
5224 chunk_to_read = (unsigned) (bytes_to_read - bytes_read); 5149 int chunk_to_read = min (bytes_to_read - bytes_read, max_rw_count);
5225 ssize_t chunk = read (fd, (char *) buf + bytes_read, chunk_to_read); 5150 ssize_t chunk = read (fd, (char *) buf + bytes_read, chunk_to_read);
5226 if (chunk < 0) 5151 if (chunk < 0)
5227 return chunk; 5152 return chunk;
@@ -5485,6 +5410,9 @@ enum dump_section
5485 NUMBER_DUMP_SECTIONS, 5410 NUMBER_DUMP_SECTIONS,
5486 }; 5411 };
5487 5412
5413/* Pointer to a stack variable to avoid having to staticpro it. */
5414static Lisp_Object *pdumper_hashes = &zero_vector;
5415
5488/* Load a dump from DUMP_FILENAME. Return an error code. 5416/* Load a dump from DUMP_FILENAME. Return an error code.
5489 5417
5490 N.B. We run very early in initialization, so we can't use lisp, 5418 N.B. We run very early in initialization, so we can't use lisp,
@@ -5631,6 +5559,15 @@ pdumper_load (const char *dump_filename, char *argv0, char const *original_pwd)
5631 for (int i = 0; i < ARRAYELTS (sections); ++i) 5559 for (int i = 0; i < ARRAYELTS (sections); ++i)
5632 dump_mmap_reset (&sections[i]); 5560 dump_mmap_reset (&sections[i]);
5633 5561
5562 Lisp_Object hashes = zero_vector;
5563 if (header->hash_list)
5564 {
5565 struct Lisp_Vector *hash_tables =
5566 (struct Lisp_Vector *) (dump_base + header->hash_list);
5567 hashes = make_lisp_ptr (hash_tables, Lisp_Vectorlike);
5568 }
5569
5570 pdumper_hashes = &hashes;
5634 /* Run the functions Emacs registered for doing post-dump-load 5571 /* Run the functions Emacs registered for doing post-dump-load
5635 initialization. */ 5572 initialization. */
5636 for (int i = 0; i < nr_dump_hooks; ++i) 5573 for (int i = 0; i < nr_dump_hooks; ++i)
@@ -5707,6 +5644,19 @@ Value is nil if this session was not started using a dump file.*/)
5707#endif /* HAVE_PDUMPER */ 5644#endif /* HAVE_PDUMPER */
5708 5645
5709 5646
5647static void
5648thaw_hash_tables (void)
5649{
5650 Lisp_Object hash_tables = *pdumper_hashes;
5651 for (ptrdiff_t i = 0; i < ASIZE (hash_tables); i++)
5652 hash_table_thaw (AREF (hash_tables, i));
5653}
5654
5655void
5656init_pdumper_once (void)
5657{
5658 pdumper_do_now_and_after_load (thaw_hash_tables);
5659}
5710 5660
5711void 5661void
5712syms_of_pdumper (void) 5662syms_of_pdumper (void)
diff --git a/src/pdumper.h b/src/pdumper.h
index b92958e12bc..c4baeaf8f94 100644
--- a/src/pdumper.h
+++ b/src/pdumper.h
@@ -257,6 +257,7 @@ pdumper_clear_marks (void)
257 file was loaded. */ 257 file was loaded. */
258extern void pdumper_record_wd (const char *); 258extern void pdumper_record_wd (const char *);
259 259
260void init_pdumper_once (void);
260void syms_of_pdumper (void); 261void syms_of_pdumper (void);
261 262
262INLINE_HEADER_END 263INLINE_HEADER_END
diff --git a/src/timefns.c b/src/timefns.c
index 7bcc37d7c1e..94cfddf0da9 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -2048,7 +2048,7 @@ syms_of_timefns (void)
2048 defsubr (&Scurrent_time_zone); 2048 defsubr (&Scurrent_time_zone);
2049 defsubr (&Sset_time_zone_rule); 2049 defsubr (&Sset_time_zone_rule);
2050 2050
2051 flt_radix_power = make_vector (flt_radix_power_size, Qnil); 2051 flt_radix_power = make_nil_vector (flt_radix_power_size);
2052 staticpro (&flt_radix_power); 2052 staticpro (&flt_radix_power);
2053 2053
2054#ifdef NEED_ZTRILLION_INIT 2054#ifdef NEED_ZTRILLION_INIT
diff --git a/src/xfaces.c b/src/xfaces.c
index 585cfa1cf4a..2c6e593f631 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -2517,6 +2517,7 @@ merge_face_ref (struct window *w,
2517{ 2517{
2518 bool ok = true; /* Succeed without an error? */ 2518 bool ok = true; /* Succeed without an error? */
2519 Lisp_Object filtered_face_ref; 2519 Lisp_Object filtered_face_ref;
2520 bool attr_filter_passed = false;
2520 2521
2521 filtered_face_ref = face_ref; 2522 filtered_face_ref = face_ref;
2522 do 2523 do
@@ -2613,6 +2614,7 @@ merge_face_ref (struct window *w,
2613 || UNSPECIFIEDP (scratch_attrs[attr_filter])) 2614 || UNSPECIFIEDP (scratch_attrs[attr_filter]))
2614 return true; 2615 return true;
2615 } 2616 }
2617 attr_filter_passed = true;
2616 } 2618 }
2617 while (CONSP (face_ref) && CONSP (XCDR (face_ref))) 2619 while (CONSP (face_ref) && CONSP (XCDR (face_ref)))
2618 { 2620 {
@@ -2776,9 +2778,21 @@ merge_face_ref (struct window *w,
2776 { 2778 {
2777 /* This is not really very useful; it's just like a 2779 /* This is not really very useful; it's just like a
2778 normal face reference. */ 2780 normal face reference. */
2779 if (! merge_face_ref (w, f, value, to, 2781 if (attr_filter_passed)
2780 err_msgs, named_merge_points, 2782 {
2781 attr_filter)) 2783 /* We already know that this face was tested
2784 against attr_filter and was found applicable,
2785 so don't pass attr_filter to merge_face_ref.
2786 This is for when a face is specified like
2787 (:inherit FACE :extend t), but the parent
2788 FACE itself doesn't specify :extend. */
2789 if (! merge_face_ref (w, f, value, to,
2790 err_msgs, named_merge_points, 0))
2791 err = true;
2792 }
2793 else if (! merge_face_ref (w, f, value, to,
2794 err_msgs, named_merge_points,
2795 attr_filter))
2782 err = true; 2796 err = true;
2783 } 2797 }
2784 else if (EQ (keyword, QCextend)) 2798 else if (EQ (keyword, QCextend))
diff --git a/src/xwidget.c b/src/xwidget.c
index 0347f1e6483..c61f5bef88d 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -23,13 +23,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
23 23
24#include "lisp.h" 24#include "lisp.h"
25#include "blockinput.h" 25#include "blockinput.h"
26#include "dispextern.h"
26#include "frame.h" 27#include "frame.h"
27#include "keyboard.h" 28#include "keyboard.h"
28#include "gtkutil.h" 29#include "gtkutil.h"
29#include "sysstdio.h" 30#include "sysstdio.h"
31#include "termhooks.h"
32#include "window.h"
30 33
34/* Include xwidget bottom end headers. */
35#ifdef USE_GTK
31#include <webkit2/webkit2.h> 36#include <webkit2/webkit2.h>
32#include <JavaScriptCore/JavaScript.h> 37#include <JavaScriptCore/JavaScript.h>
38#elif defined NS_IMPL_COCOA
39#include "nsxwidget.h"
40#endif
33 41
34static struct xwidget * 42static struct xwidget *
35allocate_xwidget (void) 43allocate_xwidget (void)
@@ -48,6 +56,7 @@ allocate_xwidget_view (void)
48 56
49static struct xwidget_view *xwidget_view_lookup (struct xwidget *, 57static struct xwidget_view *xwidget_view_lookup (struct xwidget *,
50 struct window *); 58 struct window *);
59#ifdef USE_GTK
51static void webkit_view_load_changed_cb (WebKitWebView *, 60static void webkit_view_load_changed_cb (WebKitWebView *,
52 WebKitLoadEvent, 61 WebKitLoadEvent,
53 gpointer); 62 gpointer);
@@ -61,6 +70,7 @@ webkit_decide_policy_cb (WebKitWebView *,
61 WebKitPolicyDecision *, 70 WebKitPolicyDecision *,
62 WebKitPolicyDecisionType, 71 WebKitPolicyDecisionType,
63 gpointer); 72 gpointer);
73#endif
64 74
65 75
66DEFUN ("make-xwidget", 76DEFUN ("make-xwidget",
@@ -78,8 +88,10 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
78 Lisp_Object title, Lisp_Object width, Lisp_Object height, 88 Lisp_Object title, Lisp_Object width, Lisp_Object height,
79 Lisp_Object arguments, Lisp_Object buffer) 89 Lisp_Object arguments, Lisp_Object buffer)
80{ 90{
91#ifdef USE_GTK
81 if (!xg_gtk_initialized) 92 if (!xg_gtk_initialized)
82 error ("make-xwidget: GTK has not been initialized"); 93 error ("make-xwidget: GTK has not been initialized");
94#endif
83 CHECK_SYMBOL (type); 95 CHECK_SYMBOL (type);
84 CHECK_FIXNAT (width); 96 CHECK_FIXNAT (width);
85 CHECK_FIXNAT (height); 97 CHECK_FIXNAT (height);
@@ -94,10 +106,11 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
94 xw->kill_without_query = false; 106 xw->kill_without_query = false;
95 XSETXWIDGET (val, xw); 107 XSETXWIDGET (val, xw);
96 Vxwidget_list = Fcons (val, Vxwidget_list); 108 Vxwidget_list = Fcons (val, Vxwidget_list);
97 xw->widgetwindow_osr = NULL;
98 xw->widget_osr = NULL;
99 xw->plist = Qnil; 109 xw->plist = Qnil;
100 110
111#ifdef USE_GTK
112 xw->widgetwindow_osr = NULL;
113 xw->widget_osr = NULL;
101 if (EQ (xw->type, Qwebkit)) 114 if (EQ (xw->type, Qwebkit))
102 { 115 {
103 block_input (); 116 block_input ();
@@ -152,6 +165,9 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
152 165
153 unblock_input (); 166 unblock_input ();
154 } 167 }
168#elif defined NS_IMPL_COCOA
169 nsxwidget_init (xw);
170#endif
155 171
156 return val; 172 return val;
157} 173}
@@ -187,6 +203,7 @@ xwidget_hidden (struct xwidget_view *xv)
187 return xv->hidden; 203 return xv->hidden;
188} 204}
189 205
206#ifdef USE_GTK
190static void 207static void
191xwidget_show_view (struct xwidget_view *xv) 208xwidget_show_view (struct xwidget_view *xv)
192{ 209{
@@ -220,13 +237,14 @@ offscreen_damage_event (GtkWidget *widget, GdkEvent *event,
220 if (GTK_IS_WIDGET (xv_widget)) 237 if (GTK_IS_WIDGET (xv_widget))
221 gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); 238 gtk_widget_queue_draw (GTK_WIDGET (xv_widget));
222 else 239 else
223 printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", 240 message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
224 xv_widget); 241 xv_widget);
225 242
226 return FALSE; 243 return FALSE;
227} 244}
245#endif /* USE_GTK */
228 246
229static void 247void
230store_xwidget_event_string (struct xwidget *xw, const char *eventname, 248store_xwidget_event_string (struct xwidget *xw, const char *eventname,
231 const char *eventstr) 249 const char *eventstr)
232{ 250{
@@ -240,7 +258,27 @@ store_xwidget_event_string (struct xwidget *xw, const char *eventname,
240 kbd_buffer_store_event (&event); 258 kbd_buffer_store_event (&event);
241} 259}
242 260
243static void 261void
262store_xwidget_download_callback_event (struct xwidget *xw,
263 const char *url,
264 const char *mimetype,
265 const char *filename)
266{
267 struct input_event event;
268 Lisp_Object xwl;
269 XSETXWIDGET (xwl, xw);
270 EVENT_INIT (event);
271 event.kind = XWIDGET_EVENT;
272 event.frame_or_window = Qnil;
273 event.arg = list5 (intern ("download-callback"),
274 xwl,
275 build_string (url),
276 build_string (mimetype),
277 build_string (filename));
278 kbd_buffer_store_event (&event);
279}
280
281void
244store_xwidget_js_callback_event (struct xwidget *xw, 282store_xwidget_js_callback_event (struct xwidget *xw,
245 Lisp_Object proc, 283 Lisp_Object proc,
246 Lisp_Object argument) 284 Lisp_Object argument)
@@ -256,6 +294,7 @@ store_xwidget_js_callback_event (struct xwidget *xw,
256} 294}
257 295
258 296
297#ifdef USE_GTK
259void 298void
260webkit_view_load_changed_cb (WebKitWebView *webkitwebview, 299webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
261 WebKitLoadEvent load_event, 300 WebKitLoadEvent load_event,
@@ -486,6 +525,7 @@ xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event,
486 gtk_widget_get_window (xv->widget)); 525 gtk_widget_get_window (xv->widget));
487 return FALSE; 526 return FALSE;
488} 527}
528#endif /* USE_GTK */
489 529
490 530
491/* Initializes and does initial placement of an xwidget view on screen. */ 531/* Initializes and does initial placement of an xwidget view on screen. */
@@ -495,8 +535,10 @@ xwidget_init_view (struct xwidget *xww,
495 int x, int y) 535 int x, int y)
496{ 536{
497 537
538#ifdef USE_GTK
498 if (!xg_gtk_initialized) 539 if (!xg_gtk_initialized)
499 error ("xwidget_init_view: GTK has not been initialized"); 540 error ("xwidget_init_view: GTK has not been initialized");
541#endif
500 542
501 struct xwidget_view *xv = allocate_xwidget_view (); 543 struct xwidget_view *xv = allocate_xwidget_view ();
502 Lisp_Object val; 544 Lisp_Object val;
@@ -507,6 +549,7 @@ xwidget_init_view (struct xwidget *xww,
507 XSETWINDOW (xv->w, s->w); 549 XSETWINDOW (xv->w, s->w);
508 XSETXWIDGET (xv->model, xww); 550 XSETXWIDGET (xv->model, xww);
509 551
552#ifdef USE_GTK
510 if (EQ (xww->type, Qwebkit)) 553 if (EQ (xww->type, Qwebkit))
511 { 554 {
512 xv->widget = gtk_drawing_area_new (); 555 xv->widget = gtk_drawing_area_new ();
@@ -564,6 +607,10 @@ xwidget_init_view (struct xwidget *xww,
564 xv->x = x; 607 xv->x = x;
565 xv->y = y; 608 xv->y = y;
566 gtk_widget_show_all (xv->widgetwindow); 609 gtk_widget_show_all (xv->widgetwindow);
610#elif defined NS_IMPL_COCOA
611 nsxwidget_init_view (xv, xww, s, x, y);
612 nsxwidget_resize_view(xv, xww->width, xww->height);
613#endif
567 614
568 return xv; 615 return xv;
569} 616}
@@ -576,6 +623,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
576 initialization. */ 623 initialization. */
577 struct xwidget *xww = s->xwidget; 624 struct xwidget *xww = s->xwidget;
578 struct xwidget_view *xv = xwidget_view_lookup (xww, s->w); 625 struct xwidget_view *xv = xwidget_view_lookup (xww, s->w);
626 int text_area_x, text_area_y, text_area_width, text_area_height;
579 int clip_right; 627 int clip_right;
580 int clip_bottom; 628 int clip_bottom;
581 int clip_top; 629 int clip_top;
@@ -587,13 +635,47 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
587 /* Do initialization here in the display loop because there is no 635 /* Do initialization here in the display loop because there is no
588 other time to know things like window placement etc. Do not 636 other time to know things like window placement etc. Do not
589 create a new view if we have found one that is usable. */ 637 create a new view if we have found one that is usable. */
638#ifdef USE_GTK
590 if (!xv) 639 if (!xv)
591 xv = xwidget_init_view (xww, s, x, y); 640 xv = xwidget_init_view (xww, s, x, y);
592 641#elif defined NS_IMPL_COCOA
593 int text_area_x, text_area_y, text_area_width, text_area_height; 642 if (!xv)
643 {
644 /* Enforce 1 to 1, model and view for macOS Cocoa webkit2. */
645 if (xww->xv)
646 {
647 if (xwidget_hidden (xww->xv))
648 {
649 Lisp_Object xvl;
650 XSETXWIDGET_VIEW (xvl, xww->xv);
651 Fdelete_xwidget_view (xvl);
652 }
653 else
654 {
655 message ("You can't share an xwidget (webkit2) among windows.");
656 return;
657 }
658 }
659 xv = xwidget_init_view (xww, s, x, y);
660 }
661#endif
594 662
595 window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, 663 window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y,
596 &text_area_width, &text_area_height); 664 &text_area_width, &text_area_height);
665
666 /* Resize xwidget webkit if its container window size is changed in
667 some ways, for example, a buffer became hidden in small split
668 window, then it can appear front in merged whole window. */
669 if (EQ (xww->type, Qwebkit)
670 && (xww->width != text_area_width || xww->height != text_area_height))
671 {
672 Lisp_Object xwl;
673 XSETXWIDGET (xwl, xww);
674 Fxwidget_resize (xwl,
675 make_int (text_area_width),
676 make_int (text_area_height));
677 }
678
597 clip_left = max (0, text_area_x - x); 679 clip_left = max (0, text_area_x - x);
598 clip_right = max (clip_left, 680 clip_right = max (clip_left,
599 min (xww->width, text_area_x + text_area_width - x)); 681 min (xww->width, text_area_x + text_area_width - x));
@@ -616,8 +698,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
616 698
617 /* Has it moved? */ 699 /* Has it moved? */
618 if (moved) 700 if (moved)
619 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), 701 {
620 xv->widgetwindow, x + clip_left, y + clip_top); 702#ifdef USE_GTK
703 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
704 xv->widgetwindow, x + clip_left, y + clip_top);
705#elif defined NS_IMPL_COCOA
706 nsxwidget_move_view (xv, x + clip_left, y + clip_top);
707#endif
708 }
621 709
622 /* Clip the widget window if some parts happen to be outside 710 /* Clip the widget window if some parts happen to be outside
623 drawable area. An Emacs window is not a gtk window. A gtk window 711 drawable area. An Emacs window is not a gtk window. A gtk window
@@ -628,10 +716,16 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
628 || xv->clip_bottom != clip_bottom 716 || xv->clip_bottom != clip_bottom
629 || xv->clip_top != clip_top || xv->clip_left != clip_left) 717 || xv->clip_top != clip_top || xv->clip_left != clip_left)
630 { 718 {
719#ifdef USE_GTK
631 gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, 720 gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left,
632 clip_bottom - clip_top); 721 clip_bottom - clip_top);
633 gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, 722 gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left,
634 -clip_top); 723 -clip_top);
724#elif defined NS_IMPL_COCOA
725 nsxwidget_resize_view (xv, clip_right - clip_left,
726 clip_bottom - clip_top);
727 nsxwidget_move_widget_in_view (xv, -clip_left, -clip_top);
728#endif
635 729
636 xv->clip_right = clip_right; 730 xv->clip_right = clip_right;
637 xv->clip_bottom = clip_bottom; 731 xv->clip_bottom = clip_bottom;
@@ -645,22 +739,66 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
645 xwidgets background. It's just a visual glitch though. */ 739 xwidgets background. It's just a visual glitch though. */
646 if (!xwidget_hidden (xv)) 740 if (!xwidget_hidden (xv))
647 { 741 {
742#ifdef USE_GTK
648 gtk_widget_queue_draw (xv->widgetwindow); 743 gtk_widget_queue_draw (xv->widgetwindow);
649 gtk_widget_queue_draw (xv->widget); 744 gtk_widget_queue_draw (xv->widget);
745#elif defined NS_IMPL_COCOA
746 nsxwidget_set_needsdisplay (xv);
747#endif
650 } 748 }
651} 749}
652 750
653/* Macro that checks WEBKIT_IS_WEB_VIEW (xw->widget_osr) first. */ 751static bool
752xwidget_is_web_view (struct xwidget *xw)
753{
754#ifdef USE_GTK
755 return xw->widget_osr != NULL && WEBKIT_IS_WEB_VIEW (xw->widget_osr);
756#elif defined NS_IMPL_COCOA
757 return nsxwidget_is_web_view (xw);
758#endif
759}
760
761/* Macro that checks xwidget hold webkit web view first. */
654#define WEBKIT_FN_INIT() \ 762#define WEBKIT_FN_INIT() \
655 CHECK_XWIDGET (xwidget); \ 763 CHECK_XWIDGET (xwidget); \
656 struct xwidget *xw = XXWIDGET (xwidget); \ 764 struct xwidget *xw = XXWIDGET (xwidget); \
657 if (!xw->widget_osr || !WEBKIT_IS_WEB_VIEW (xw->widget_osr)) \ 765 if (!xwidget_is_web_view (xw)) \
658 { \ 766 { \
659 fputs ("ERROR xw->widget_osr does not hold a webkit instance\n", \ 767 fputs ("ERROR xw->widget_osr does not hold a webkit instance\n", \
660 stdout); \ 768 stdout); \
661 return Qnil; \ 769 return Qnil; \
662 } 770 }
663 771
772DEFUN ("xwidget-webkit-uri",
773 Fxwidget_webkit_uri, Sxwidget_webkit_uri,
774 1, 1, 0,
775 doc: /* Get the current URL of XWIDGET webkit. */)
776 (Lisp_Object xwidget)
777{
778 WEBKIT_FN_INIT ();
779#ifdef USE_GTK
780 WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
781 return build_string (webkit_web_view_get_uri (wkwv));
782#elif defined NS_IMPL_COCOA
783 return nsxwidget_webkit_uri (xw);
784#endif
785}
786
787DEFUN ("xwidget-webkit-title",
788 Fxwidget_webkit_title, Sxwidget_webkit_title,
789 1, 1, 0,
790 doc: /* Get the current title of XWIDGET webkit. */)
791 (Lisp_Object xwidget)
792{
793 WEBKIT_FN_INIT ();
794#ifdef USE_GTK
795 WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
796 return build_string (webkit_web_view_get_title (wkwv));
797#elif defined NS_IMPL_COCOA
798 return nsxwidget_webkit_title (xw);
799#endif
800}
801
664DEFUN ("xwidget-webkit-goto-uri", 802DEFUN ("xwidget-webkit-goto-uri",
665 Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri, 803 Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
666 2, 2, 0, 804 2, 2, 0,
@@ -670,7 +808,36 @@ DEFUN ("xwidget-webkit-goto-uri",
670 WEBKIT_FN_INIT (); 808 WEBKIT_FN_INIT ();
671 CHECK_STRING (uri); 809 CHECK_STRING (uri);
672 uri = ENCODE_FILE (uri); 810 uri = ENCODE_FILE (uri);
811#ifdef USE_GTK
673 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri)); 812 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
813#elif defined NS_IMPL_COCOA
814 nsxwidget_webkit_goto_uri (xw, SSDATA (uri));
815#endif
816 return Qnil;
817}
818
819DEFUN ("xwidget-webkit-goto-history",
820 Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
821 2, 2, 0,
822 doc: /* Make the XWIDGET webkit load REL-POS (-1, 0, 1) page in browse history. */)
823 (Lisp_Object xwidget, Lisp_Object rel_pos)
824{
825 WEBKIT_FN_INIT ();
826 /* Should be one of -1, 0, 1 */
827 if (XFIXNUM (rel_pos) < -1 || XFIXNUM (rel_pos) > 1)
828 args_out_of_range_3 (rel_pos, make_fixnum (-1), make_fixnum (1));
829
830#ifdef USE_GTK
831 WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
832 switch (XFIXNAT (rel_pos))
833 {
834 case -1: webkit_web_view_go_back (wkwv); break;
835 case 0: webkit_web_view_reload (wkwv); break;
836 case 1: webkit_web_view_go_forward (wkwv); break;
837 }
838#elif defined NS_IMPL_COCOA
839 nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
840#endif
674 return Qnil; 841 return Qnil;
675} 842}
676 843
@@ -684,14 +851,19 @@ DEFUN ("xwidget-webkit-zoom",
684 if (FLOATP (factor)) 851 if (FLOATP (factor))
685 { 852 {
686 double zoom_change = XFLOAT_DATA (factor); 853 double zoom_change = XFLOAT_DATA (factor);
854#ifdef USE_GTK
687 webkit_web_view_set_zoom_level 855 webkit_web_view_set_zoom_level
688 (WEBKIT_WEB_VIEW (xw->widget_osr), 856 (WEBKIT_WEB_VIEW (xw->widget_osr),
689 webkit_web_view_get_zoom_level 857 webkit_web_view_get_zoom_level
690 (WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change); 858 (WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change);
859#elif defined NS_IMPL_COCOA
860 nsxwidget_webkit_zoom (xw, zoom_change);
861#endif
691 } 862 }
692 return Qnil; 863 return Qnil;
693} 864}
694 865
866#ifdef USE_GTK
695/* Save script and fun in the script/callback save vector and return 867/* Save script and fun in the script/callback save vector and return
696 its index. */ 868 its index. */
697static ptrdiff_t 869static ptrdiff_t
@@ -713,6 +885,7 @@ save_script_callback (struct xwidget *xw, Lisp_Object script, Lisp_Object fun)
713 ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun)); 885 ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun));
714 return idx; 886 return idx;
715} 887}
888#endif
716 889
717DEFUN ("xwidget-webkit-execute-script", 890DEFUN ("xwidget-webkit-execute-script",
718 Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script, 891 Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
@@ -729,6 +902,7 @@ argument procedure FUN.*/)
729 902
730 script = ENCODE_SYSTEM (script); 903 script = ENCODE_SYSTEM (script);
731 904
905#ifdef USE_GTK
732 /* Protect script and fun during GC. */ 906 /* Protect script and fun during GC. */
733 intptr_t idx = save_script_callback (xw, script, fun); 907 intptr_t idx = save_script_callback (xw, script, fun);
734 908
@@ -742,6 +916,9 @@ argument procedure FUN.*/)
742 NULL, /* cancelable */ 916 NULL, /* cancelable */
743 webkit_javascript_finished_cb, 917 webkit_javascript_finished_cb,
744 (gpointer) idx); 918 (gpointer) idx);
919#elif defined NS_IMPL_COCOA
920 nsxwidget_webkit_execute_script (xw, SSDATA (script), fun);
921#endif
745 return Qnil; 922 return Qnil;
746} 923}
747 924
@@ -758,6 +935,7 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
758 xw->height = h; 935 xw->height = h;
759 936
760 /* If there is an offscreen widget resize it first. */ 937 /* If there is an offscreen widget resize it first. */
938#ifdef USE_GTK
761 if (xw->widget_osr) 939 if (xw->widget_osr)
762 { 940 {
763 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width, 941 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
@@ -766,6 +944,9 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
766 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, 944 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
767 xw->height); 945 xw->height);
768 } 946 }
947#elif defined NS_IMPL_COCOA
948 nsxwidget_resize (xw);
949#endif
769 950
770 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) 951 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
771 { 952 {
@@ -773,8 +954,14 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
773 { 954 {
774 struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); 955 struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
775 if (XXWIDGET (xv->model) == xw) 956 if (XXWIDGET (xv->model) == xw)
957 {
958#ifdef USE_GTK
776 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, 959 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
777 xw->height); 960 xw->height);
961#elif defined NS_IMPL_COCOA
962 nsxwidget_resize_view(xv, xw->width, xw->height);
963#endif
964 }
778 } 965 }
779 } 966 }
780 967
@@ -793,9 +980,13 @@ Emacs allocated area accordingly. */)
793 (Lisp_Object xwidget) 980 (Lisp_Object xwidget)
794{ 981{
795 CHECK_XWIDGET (xwidget); 982 CHECK_XWIDGET (xwidget);
983#ifdef USE_GTK
796 GtkRequisition requisition; 984 GtkRequisition requisition;
797 gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition); 985 gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
798 return list2i (requisition.width, requisition.height); 986 return list2i (requisition.width, requisition.height);
987#elif defined NS_IMPL_COCOA
988 return nsxwidget_get_size (XXWIDGET (xwidget));
989#endif
799} 990}
800 991
801DEFUN ("xwidgetp", 992DEFUN ("xwidgetp",
@@ -872,14 +1063,19 @@ DEFUN ("delete-xwidget-view",
872{ 1063{
873 CHECK_XWIDGET_VIEW (xwidget_view); 1064 CHECK_XWIDGET_VIEW (xwidget_view);
874 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); 1065 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1066#ifdef USE_GTK
875 gtk_widget_destroy (xv->widgetwindow); 1067 gtk_widget_destroy (xv->widgetwindow);
876 Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
877 /* xv->model still has signals pointing to the view. There can be 1068 /* xv->model still has signals pointing to the view. There can be
878 several views. Find the matching signals and delete them all. */ 1069 several views. Find the matching signals and delete them all. */
879 g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, 1070 g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr,
880 G_SIGNAL_MATCH_DATA, 1071 G_SIGNAL_MATCH_DATA,
881 0, 0, 0, 0, 1072 0, 0, 0, 0,
882 xv->widget); 1073 xv->widget);
1074#elif defined NS_IMPL_COCOA
1075 nsxwidget_delete_view (xv);
1076#endif
1077
1078 Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
883 return Qnil; 1079 return Qnil;
884} 1080}
885 1081
@@ -985,7 +1181,10 @@ syms_of_xwidget (void)
985 defsubr (&Sxwidget_query_on_exit_flag); 1181 defsubr (&Sxwidget_query_on_exit_flag);
986 defsubr (&Sset_xwidget_query_on_exit_flag); 1182 defsubr (&Sset_xwidget_query_on_exit_flag);
987 1183
1184 defsubr (&Sxwidget_webkit_uri);
1185 defsubr (&Sxwidget_webkit_title);
988 defsubr (&Sxwidget_webkit_goto_uri); 1186 defsubr (&Sxwidget_webkit_goto_uri);
1187 defsubr (&Sxwidget_webkit_goto_history);
989 defsubr (&Sxwidget_webkit_zoom); 1188 defsubr (&Sxwidget_webkit_zoom);
990 defsubr (&Sxwidget_webkit_execute_script); 1189 defsubr (&Sxwidget_webkit_execute_script);
991 DEFSYM (Qwebkit, "webkit"); 1190 DEFSYM (Qwebkit, "webkit");
@@ -1156,11 +1355,19 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1156 xwidget_end_redisplay (w->current_matrix); */ 1355 xwidget_end_redisplay (w->current_matrix); */
1157 struct xwidget_view *xv 1356 struct xwidget_view *xv
1158 = xwidget_view_lookup (glyph->u.xwidget, w); 1357 = xwidget_view_lookup (glyph->u.xwidget, w);
1358#ifdef USE_GTK
1159 /* FIXME: Is it safe to assume xwidget_view_lookup 1359 /* FIXME: Is it safe to assume xwidget_view_lookup
1160 always succeeds here? If so, this comment can be removed. 1360 always succeeds here? If so, this comment can be removed.
1161 If not, the code probably needs fixing. */ 1361 If not, the code probably needs fixing. */
1162 eassume (xv); 1362 eassume (xv);
1163 xwidget_touch (xv); 1363 xwidget_touch (xv);
1364#elif defined NS_IMPL_COCOA
1365 /* In NS xwidget, xv can be NULL for the second or
1366 later views for a model, the result of 1 to 1
1367 model view relation enforcement. */
1368 if (xv)
1369 xwidget_touch (xv);
1370#endif
1164 } 1371 }
1165 } 1372 }
1166 } 1373 }
@@ -1177,9 +1384,21 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1177 if (XWINDOW (xv->w) == w) 1384 if (XWINDOW (xv->w) == w)
1178 { 1385 {
1179 if (xwidget_touched (xv)) 1386 if (xwidget_touched (xv))
1180 xwidget_show_view (xv); 1387 {
1388#ifdef USE_GTK
1389 xwidget_show_view (xv);
1390#elif defined NS_IMPL_COCOA
1391 nsxwidget_show_view (xv);
1392#endif
1393 }
1181 else 1394 else
1182 xwidget_hide_view (xv); 1395 {
1396#ifdef USE_GTK
1397 xwidget_hide_view (xv);
1398#elif defined NS_IMPL_COCOA
1399 nsxwidget_hide_view (xv);
1400#endif
1401 }
1183 } 1402 }
1184 } 1403 }
1185 } 1404 }
@@ -1198,6 +1417,7 @@ kill_buffer_xwidgets (Lisp_Object buffer)
1198 { 1417 {
1199 CHECK_XWIDGET (xwidget); 1418 CHECK_XWIDGET (xwidget);
1200 struct xwidget *xw = XXWIDGET (xwidget); 1419 struct xwidget *xw = XXWIDGET (xwidget);
1420#ifdef USE_GTK
1201 if (xw->widget_osr && xw->widgetwindow_osr) 1421 if (xw->widget_osr && xw->widgetwindow_osr)
1202 { 1422 {
1203 gtk_widget_destroy (xw->widget_osr); 1423 gtk_widget_destroy (xw->widget_osr);
@@ -1211,6 +1431,9 @@ kill_buffer_xwidgets (Lisp_Object buffer)
1211 xfree (xmint_pointer (XCAR (cb))); 1431 xfree (xmint_pointer (XCAR (cb)));
1212 ASET (xw->script_callbacks, idx, Qnil); 1432 ASET (xw->script_callbacks, idx, Qnil);
1213 } 1433 }
1434#elif defined NS_IMPL_COCOA
1435 nsxwidget_kill (xw);
1436#endif
1214 } 1437 }
1215 } 1438 }
1216} 1439}
diff --git a/src/xwidget.h b/src/xwidget.h
index 99fa8bbd612..40ad8ae8334 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -29,7 +29,13 @@ struct xwidget_view;
29struct window; 29struct window;
30 30
31#ifdef HAVE_XWIDGETS 31#ifdef HAVE_XWIDGETS
32# include <gtk/gtk.h> 32
33#if defined (USE_GTK)
34#include <gtk/gtk.h>
35#elif defined (NS_IMPL_COCOA) && defined (__OBJC__)
36#import <AppKit/NSView.h>
37#import "nsxwidget.h"
38#endif
33 39
34struct xwidget 40struct xwidget
35{ 41{
@@ -54,9 +60,25 @@ struct xwidget
54 int height; 60 int height;
55 int width; 61 int width;
56 62
63#if defined (USE_GTK)
57 /* For offscreen widgets, unused if not osr. */ 64 /* For offscreen widgets, unused if not osr. */
58 GtkWidget *widget_osr; 65 GtkWidget *widget_osr;
59 GtkWidget *widgetwindow_osr; 66 GtkWidget *widgetwindow_osr;
67#elif defined (NS_IMPL_COCOA)
68# ifdef __OBJC__
69 /* For offscreen widgets, unused if not osr. */
70 NSView *xwWidget;
71 XwWindow *xwWindow;
72
73 /* Used only for xwidget types (such as webkit2) enforcing 1 to 1
74 relationship between model and view. */
75 struct xwidget_view *xv;
76# else
77 void *xwWidget;
78 void *xwWindow;
79 struct xwidget_view *xv;
80# endif
81#endif
60 82
61 /* Kill silently if Emacs is exited. */ 83 /* Kill silently if Emacs is exited. */
62 bool_bf kill_without_query : 1; 84 bool_bf kill_without_query : 1;
@@ -75,9 +97,20 @@ struct xwidget_view
75 /* The "live" instance isn't drawn. */ 97 /* The "live" instance isn't drawn. */
76 bool hidden; 98 bool hidden;
77 99
100#if defined (USE_GTK)
78 GtkWidget *widget; 101 GtkWidget *widget;
79 GtkWidget *widgetwindow; 102 GtkWidget *widgetwindow;
80 GtkWidget *emacswindow; 103 GtkWidget *emacswindow;
104#elif defined (NS_IMPL_COCOA)
105# ifdef __OBJC__
106 XvWindow *xvWindow;
107 NSView *emacswindow;
108# else
109 void *xvWindow;
110 void *emacswindow;
111# endif
112#endif
113
81 int x; 114 int x;
82 int y; 115 int y;
83 int clip_right; 116 int clip_right;
@@ -116,6 +149,19 @@ void x_draw_xwidget_glyph_string (struct glyph_string *);
116struct xwidget *lookup_xwidget (Lisp_Object spec); 149struct xwidget *lookup_xwidget (Lisp_Object spec);
117void xwidget_end_redisplay (struct window *, struct glyph_matrix *); 150void xwidget_end_redisplay (struct window *, struct glyph_matrix *);
118void kill_buffer_xwidgets (Lisp_Object); 151void kill_buffer_xwidgets (Lisp_Object);
152/* Defined in 'xwidget.c'. */
153void store_xwidget_event_string (struct xwidget *xw,
154 const char *eventname,
155 const char *eventstr);
156
157void store_xwidget_download_callback_event (struct xwidget *xw,
158 const char *url,
159 const char *mimetype,
160 const char *filename);
161
162void store_xwidget_js_callback_event (struct xwidget *xw,
163 Lisp_Object proc,
164 Lisp_Object argument);
119#else 165#else
120INLINE_HEADER_BEGIN 166INLINE_HEADER_BEGIN
121INLINE void syms_of_xwidget (void) {} 167INLINE void syms_of_xwidget (void) {}