diff options
| author | Andrea Corallo | 2020-12-12 15:31:33 +0100 |
|---|---|---|
| committer | Andrea Corallo | 2020-12-12 15:31:33 +0100 |
| commit | 0474fda62d79cb7eb250f34f19773c87f283c665 (patch) | |
| tree | df7418a6b22fbbfda725c56825ec0290f8e6be39 /src | |
| parent | be907b0ba82c2a65e0468d50653cae8a7cf5f16b (diff) | |
| parent | 4afef614cd6c93b4d4a57aa5bb211563649abc56 (diff) | |
| download | emacs-0474fda62d79cb7eb250f34f19773c87f283c665.tar.gz emacs-0474fda62d79cb7eb250f34f19773c87f283c665.zip | |
Merge remote-tracking branch 'savannah/master' into HEAD
Diffstat (limited to 'src')
| -rw-r--r-- | src/charset.c | 4 | ||||
| -rw-r--r-- | src/chartab.c | 6 | ||||
| -rw-r--r-- | src/data.c | 5 | ||||
| -rw-r--r-- | src/emacs.c | 13 | ||||
| -rw-r--r-- | src/eval.c | 11 | ||||
| -rw-r--r-- | src/fileio.c | 7 | ||||
| -rw-r--r-- | src/fns.c | 78 | ||||
| -rw-r--r-- | src/frame.c | 12 | ||||
| -rw-r--r-- | src/image.c | 124 | ||||
| -rw-r--r-- | src/lisp.h | 33 | ||||
| -rw-r--r-- | src/nsterm.m | 10 | ||||
| -rw-r--r-- | src/regex-emacs.c | 17 | ||||
| -rw-r--r-- | src/w32gui.h | 1 | ||||
| -rw-r--r-- | src/w32term.c | 11 | ||||
| -rw-r--r-- | src/window.c | 56 | ||||
| -rw-r--r-- | src/xdisp.c | 40 |
16 files changed, 314 insertions, 114 deletions
diff --git a/src/charset.c b/src/charset.c index 520dd3a9605..f6b5173fad4 100644 --- a/src/charset.c +++ b/src/charset.c | |||
| @@ -800,7 +800,9 @@ RANGE is a cons (FROM . TO), where FROM and TO indicate a range of | |||
| 800 | characters contained in CHARSET. | 800 | characters contained in CHARSET. |
| 801 | 801 | ||
| 802 | The optional 4th and 5th arguments FROM-CODE and TO-CODE specify the | 802 | The optional 4th and 5th arguments FROM-CODE and TO-CODE specify the |
| 803 | range of code points (in CHARSET) of target characters. */) | 803 | range of code points (in CHARSET) of target characters. Note that |
| 804 | these are not character codes, but code points in CHARSET; for the | ||
| 805 | difference see `decode-char' and `list-charset-chars'. */) | ||
| 804 | (Lisp_Object function, Lisp_Object charset, Lisp_Object arg, Lisp_Object from_code, Lisp_Object to_code) | 806 | (Lisp_Object function, Lisp_Object charset, Lisp_Object arg, Lisp_Object from_code, Lisp_Object to_code) |
| 805 | { | 807 | { |
| 806 | struct charset *cs; | 808 | struct charset *cs; |
diff --git a/src/chartab.c b/src/chartab.c index cb2ced568d9..331e8595ebe 100644 --- a/src/chartab.c +++ b/src/chartab.c | |||
| @@ -1000,10 +1000,10 @@ map_sub_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Object), | |||
| 1000 | "mapping table" or a "deunifier table" of a certain charset. | 1000 | "mapping table" or a "deunifier table" of a certain charset. |
| 1001 | 1001 | ||
| 1002 | If CHARSET is not NULL (this is the case that `map-charset-chars' | 1002 | If CHARSET is not NULL (this is the case that `map-charset-chars' |
| 1003 | is called with non-nil FROM-CODE and TO-CODE), it is a charset who | 1003 | is called with non-nil FROM-CODE and TO-CODE), it is a charset that |
| 1004 | owns TABLE, and the function is called only on a character in the | 1004 | owns TABLE, and the function is called only for characters in the |
| 1005 | range FROM and TO. FROM and TO are not character codes, but code | 1005 | range FROM and TO. FROM and TO are not character codes, but code |
| 1006 | points of a character in CHARSET. | 1006 | points of characters in CHARSET (see 'decode-char'). |
| 1007 | 1007 | ||
| 1008 | This function is called in these two cases: | 1008 | This function is called in these two cases: |
| 1009 | 1009 | ||
diff --git a/src/data.c b/src/data.c index fea39867c99..544b20d50cc 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -1700,8 +1700,9 @@ default_value (Lisp_Object symbol) | |||
| 1700 | 1700 | ||
| 1701 | DEFUN ("default-boundp", Fdefault_boundp, Sdefault_boundp, 1, 1, 0, | 1701 | DEFUN ("default-boundp", Fdefault_boundp, Sdefault_boundp, 1, 1, 0, |
| 1702 | doc: /* Return t if SYMBOL has a non-void default value. | 1702 | doc: /* Return t if SYMBOL has a non-void default value. |
| 1703 | This is the value that is seen in buffers that do not have their own values | 1703 | A variable may have a buffer-local or a `let'-bound local value. This |
| 1704 | for this variable. */) | 1704 | function says whether the variable has a non-void value outside of the |
| 1705 | current context. Also see `default-value'. */) | ||
| 1705 | (Lisp_Object symbol) | 1706 | (Lisp_Object symbol) |
| 1706 | { | 1707 | { |
| 1707 | register Lisp_Object value; | 1708 | register Lisp_Object value; |
diff --git a/src/emacs.c b/src/emacs.c index afcdb667821..afdfcade777 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -2398,10 +2398,13 @@ all of which are called before Emacs is actually killed. */ | |||
| 2398 | /* Fsignal calls emacs_abort () if it sees that waiting_for_input is | 2398 | /* Fsignal calls emacs_abort () if it sees that waiting_for_input is |
| 2399 | set. */ | 2399 | set. */ |
| 2400 | waiting_for_input = 0; | 2400 | waiting_for_input = 0; |
| 2401 | if (noninteractive) | 2401 | if (!NILP (find_symbol_value (Qkill_emacs_hook))) |
| 2402 | safe_run_hooks (Qkill_emacs_hook); | 2402 | { |
| 2403 | else | 2403 | if (noninteractive) |
| 2404 | run_hook (Qkill_emacs_hook); | 2404 | safe_run_hooks (Qkill_emacs_hook); |
| 2405 | else | ||
| 2406 | call1 (Qrun_hook_query_error_with_timeout, Qkill_emacs_hook); | ||
| 2407 | } | ||
| 2405 | 2408 | ||
| 2406 | #ifdef HAVE_X_WINDOWS | 2409 | #ifdef HAVE_X_WINDOWS |
| 2407 | /* Transfer any clipboards we own to the clipboard manager. */ | 2410 | /* Transfer any clipboards we own to the clipboard manager. */ |
| @@ -2927,6 +2930,8 @@ syms_of_emacs (void) | |||
| 2927 | DEFSYM (Qrisky_local_variable, "risky-local-variable"); | 2930 | DEFSYM (Qrisky_local_variable, "risky-local-variable"); |
| 2928 | DEFSYM (Qkill_emacs, "kill-emacs"); | 2931 | DEFSYM (Qkill_emacs, "kill-emacs"); |
| 2929 | DEFSYM (Qkill_emacs_hook, "kill-emacs-hook"); | 2932 | DEFSYM (Qkill_emacs_hook, "kill-emacs-hook"); |
| 2933 | DEFSYM (Qrun_hook_query_error_with_timeout, | ||
| 2934 | "run-hook-query-error-with-timeout"); | ||
| 2930 | 2935 | ||
| 2931 | #ifdef HAVE_UNEXEC | 2936 | #ifdef HAVE_UNEXEC |
| 2932 | defsubr (&Sdump_emacs); | 2937 | defsubr (&Sdump_emacs); |
diff --git a/src/eval.c b/src/eval.c index fb747c58838..2b31b91175b 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -1799,7 +1799,8 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit) | |||
| 1799 | debugging. Make sure to use `debug' unconditionally to not interfere with | 1799 | debugging. Make sure to use `debug' unconditionally to not interfere with |
| 1800 | ERT or other packages that install custom debuggers. */ | 1800 | ERT or other packages that install custom debuggers. */ |
| 1801 | if (!debugger_called && !NILP (error_symbol) | 1801 | if (!debugger_called && !NILP (error_symbol) |
| 1802 | && (NILP (clause) || EQ (h->tag_or_ch, Qerror)) && noninteractive) | 1802 | && (NILP (clause) || EQ (h->tag_or_ch, Qerror)) && noninteractive |
| 1803 | && backtrace_on_error_noninteractive) | ||
| 1803 | { | 1804 | { |
| 1804 | ptrdiff_t count = SPECPDL_INDEX (); | 1805 | ptrdiff_t count = SPECPDL_INDEX (); |
| 1805 | specbind (Vdebugger, Qdebug); | 1806 | specbind (Vdebugger, Qdebug); |
| @@ -4344,6 +4345,14 @@ Note that `debug-on-error', `debug-on-quit' and friends | |||
| 4344 | still determine whether to handle the particular condition. */); | 4345 | still determine whether to handle the particular condition. */); |
| 4345 | Vdebug_on_signal = Qnil; | 4346 | Vdebug_on_signal = Qnil; |
| 4346 | 4347 | ||
| 4348 | DEFVAR_BOOL ("backtrace-on-error-noninteractive", | ||
| 4349 | backtrace_on_error_noninteractive, | ||
| 4350 | doc: /* Non-nil means print backtrace on error in batch mode. | ||
| 4351 | If this is nil, errors in batch mode will just print the error | ||
| 4352 | message upon encountering an unhandled error, without showing | ||
| 4353 | the Lisp backtrace. */); | ||
| 4354 | backtrace_on_error_noninteractive = true; | ||
| 4355 | |||
| 4347 | /* The value of num_nonmacro_input_events as of the last time we | 4356 | /* The value of num_nonmacro_input_events as of the last time we |
| 4348 | started to enter the debugger. If we decide to enter the debugger | 4357 | started to enter the debugger. If we decide to enter the debugger |
| 4349 | again when this is still equal to num_nonmacro_input_events, then we | 4358 | again when this is still equal to num_nonmacro_input_events, then we |
diff --git a/src/fileio.c b/src/fileio.c index 283813ff89e..702c1438283 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -3757,9 +3757,10 @@ characters in the buffer. If VISIT is non-nil, BEG and END must be nil. | |||
| 3757 | If optional fifth argument REPLACE is non-nil, replace the current | 3757 | If optional fifth argument REPLACE is non-nil, replace the current |
| 3758 | buffer contents (in the accessible portion) with the file contents. | 3758 | buffer contents (in the accessible portion) with the file contents. |
| 3759 | This is better than simply deleting and inserting the whole thing | 3759 | This is better than simply deleting and inserting the whole thing |
| 3760 | because (1) it preserves some marker positions and (2) it puts less data | 3760 | because (1) it preserves some marker positions (in unchanged portions |
| 3761 | in the undo list. When REPLACE is non-nil, the second return value is | 3761 | at the start and end of the buffer) and (2) it puts less data in the |
| 3762 | the number of characters that replace previous buffer contents. | 3762 | undo list. When REPLACE is non-nil, the second return value is the |
| 3763 | number of characters that replace previous buffer contents. | ||
| 3763 | 3764 | ||
| 3764 | This function does code conversion according to the value of | 3765 | This function does code conversion according to the value of |
| 3765 | `coding-system-for-read' or `file-coding-system-alist', and sets the | 3766 | `coding-system-for-read' or `file-coding-system-alist', and sets the |
| @@ -4525,18 +4525,40 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p) | |||
| 4525 | EMACS_UINT | 4525 | EMACS_UINT |
| 4526 | hash_string (char const *ptr, ptrdiff_t len) | 4526 | hash_string (char const *ptr, ptrdiff_t len) |
| 4527 | { | 4527 | { |
| 4528 | char const *p = ptr; | 4528 | if (len < 16) |
| 4529 | char const *end = p + len; | ||
| 4530 | unsigned char c; | ||
| 4531 | EMACS_UINT hash = 0; | ||
| 4532 | |||
| 4533 | while (p != end) | ||
| 4534 | { | 4529 | { |
| 4535 | c = *p++; | 4530 | char const *p = ptr; |
| 4536 | hash = sxhash_combine (hash, c); | 4531 | char const *end = p + len; |
| 4532 | EMACS_UINT hash = len; | ||
| 4533 | |||
| 4534 | while (p < end) | ||
| 4535 | { | ||
| 4536 | unsigned char c = *p++; | ||
| 4537 | hash = sxhash_combine (hash, c); | ||
| 4538 | } | ||
| 4539 | |||
| 4540 | return hash; | ||
| 4537 | } | 4541 | } |
| 4542 | else | ||
| 4543 | { | ||
| 4544 | EMACS_UINT const *p = (EMACS_UINT const *) ptr; | ||
| 4545 | EMACS_UINT const *end = (EMACS_UINT const *) (ptr + len); | ||
| 4546 | EMACS_UINT hash = len; | ||
| 4547 | /* At most 8 steps. We could reuse SXHASH_MAX_LEN, of course, | ||
| 4548 | * but dividing by 8 is cheaper. */ | ||
| 4549 | ptrdiff_t step = max (1, (end - p) >> 3); | ||
| 4550 | |||
| 4551 | /* Beware: `end` might be unaligned, so `p < end` is not always the same | ||
| 4552 | * as `p <= end - 1`. */ | ||
| 4553 | while (p <= end - 1) | ||
| 4554 | { | ||
| 4555 | EMACS_UINT c = *p; | ||
| 4556 | p += step; | ||
| 4557 | hash = sxhash_combine (hash, c); | ||
| 4558 | } | ||
| 4538 | 4559 | ||
| 4539 | return hash; | 4560 | return hash; |
| 4561 | } | ||
| 4540 | } | 4562 | } |
| 4541 | 4563 | ||
| 4542 | /* Return a hash for string PTR which has length LEN. The hash | 4564 | /* Return a hash for string PTR which has length LEN. The hash |
| @@ -5418,7 +5440,8 @@ disregarding any coding systems. If nil, use the current buffer. | |||
| 5418 | 5440 | ||
| 5419 | This function is useful for comparing two buffers running in the same | 5441 | This function is useful for comparing two buffers running in the same |
| 5420 | Emacs, but is not guaranteed to return the same hash between different | 5442 | Emacs, but is not guaranteed to return the same hash between different |
| 5421 | Emacs versions. | 5443 | Emacs versions. It should be somewhat more efficient on larger |
| 5444 | buffers than `secure-hash' is, and should not allocate more memory. | ||
| 5422 | 5445 | ||
| 5423 | It should not be used for anything security-related. See | 5446 | It should not be used for anything security-related. See |
| 5424 | `secure-hash' for these applications. */ ) | 5447 | `secure-hash' for these applications. */ ) |
| @@ -5551,6 +5574,40 @@ Case is always significant and text properties are ignored. */) | |||
| 5551 | 5574 | ||
| 5552 | return make_int (string_byte_to_char (haystack, res - SSDATA (haystack))); | 5575 | return make_int (string_byte_to_char (haystack, res - SSDATA (haystack))); |
| 5553 | } | 5576 | } |
| 5577 | |||
| 5578 | static void | ||
| 5579 | collect_interval (INTERVAL interval, Lisp_Object collector) | ||
| 5580 | { | ||
| 5581 | nconc2 (collector, | ||
| 5582 | list1(list3 (make_fixnum (interval->position), | ||
| 5583 | make_fixnum (interval->position + LENGTH (interval)), | ||
| 5584 | interval->plist))); | ||
| 5585 | } | ||
| 5586 | |||
| 5587 | DEFUN ("object-intervals", Fobject_intervals, Sobject_intervals, 1, 1, 0, | ||
| 5588 | doc: /* Return a copy of the text properties of OBJECT. | ||
| 5589 | OBJECT must be a buffer or a string. | ||
| 5590 | |||
| 5591 | Altering this copy does not change the layout of the text properties | ||
| 5592 | in OBJECT. */) | ||
| 5593 | (register Lisp_Object object) | ||
| 5594 | { | ||
| 5595 | Lisp_Object collector = Fcons (Qnil, Qnil); | ||
| 5596 | INTERVAL intervals; | ||
| 5597 | |||
| 5598 | if (STRINGP (object)) | ||
| 5599 | intervals = string_intervals (object); | ||
| 5600 | else if (BUFFERP (object)) | ||
| 5601 | intervals = buffer_intervals (XBUFFER (object)); | ||
| 5602 | else | ||
| 5603 | wrong_type_argument (Qbuffer_or_string_p, object); | ||
| 5604 | |||
| 5605 | if (! intervals) | ||
| 5606 | return Qnil; | ||
| 5607 | |||
| 5608 | traverse_intervals (intervals, 0, collect_interval, collector); | ||
| 5609 | return CDR (collector); | ||
| 5610 | } | ||
| 5554 | 5611 | ||
| 5555 | 5612 | ||
| 5556 | void | 5613 | void |
| @@ -5592,6 +5649,7 @@ syms_of_fns (void) | |||
| 5592 | defsubr (&Smaphash); | 5649 | defsubr (&Smaphash); |
| 5593 | defsubr (&Sdefine_hash_table_test); | 5650 | defsubr (&Sdefine_hash_table_test); |
| 5594 | defsubr (&Sstring_search); | 5651 | defsubr (&Sstring_search); |
| 5652 | defsubr (&Sobject_intervals); | ||
| 5595 | 5653 | ||
| 5596 | /* Crypto and hashing stuff. */ | 5654 | /* Crypto and hashing stuff. */ |
| 5597 | DEFSYM (Qiv_auto, "iv-auto"); | 5655 | DEFSYM (Qiv_auto, "iv-auto"); |
diff --git a/src/frame.c b/src/frame.c index 17ec455d2d6..164c05cae85 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -3577,7 +3577,9 @@ window managers may refuse to honor a HEIGHT that is not an integer | |||
| 3577 | multiple of the default frame font height. | 3577 | multiple of the default frame font height. |
| 3578 | 3578 | ||
| 3579 | When called interactively, HEIGHT is the numeric prefix and the | 3579 | When called interactively, HEIGHT is the numeric prefix and the |
| 3580 | currently selected frame will be set to this height. */) | 3580 | currently selected frame will be set to this height. |
| 3581 | |||
| 3582 | If FRAME is nil, it defaults to the selected frame. */) | ||
| 3581 | (Lisp_Object frame, Lisp_Object height, Lisp_Object pretend, Lisp_Object pixelwise) | 3583 | (Lisp_Object frame, Lisp_Object height, Lisp_Object pretend, Lisp_Object pixelwise) |
| 3582 | { | 3584 | { |
| 3583 | struct frame *f = decode_live_frame (frame); | 3585 | struct frame *f = decode_live_frame (frame); |
| @@ -3600,7 +3602,9 @@ window managers may refuse to honor a WIDTH that is not an integer | |||
| 3600 | multiple of the default frame font width. | 3602 | multiple of the default frame font width. |
| 3601 | 3603 | ||
| 3602 | When called interactively, WIDTH is the numeric prefix and the | 3604 | When called interactively, WIDTH is the numeric prefix and the |
| 3603 | currently selected frame will be set to this width. */) | 3605 | currently selected frame will be set to this width. |
| 3606 | |||
| 3607 | If FRAME is nil, it defaults to the selected frame. */) | ||
| 3604 | (Lisp_Object frame, Lisp_Object width, Lisp_Object pretend, Lisp_Object pixelwise) | 3608 | (Lisp_Object frame, Lisp_Object width, Lisp_Object pretend, Lisp_Object pixelwise) |
| 3605 | { | 3609 | { |
| 3606 | struct frame *f = decode_live_frame (frame); | 3610 | struct frame *f = decode_live_frame (frame); |
| @@ -3616,7 +3620,9 @@ Optional argument PIXELWISE non-nil means to measure in pixels. Note: | |||
| 3616 | When `frame-resize-pixelwise' is nil, some window managers may refuse to | 3620 | When `frame-resize-pixelwise' is nil, some window managers may refuse to |
| 3617 | honor a WIDTH that is not an integer multiple of the default frame font | 3621 | honor a WIDTH that is not an integer multiple of the default frame font |
| 3618 | width or a HEIGHT that is not an integer multiple of the default frame | 3622 | width or a HEIGHT that is not an integer multiple of the default frame |
| 3619 | font height. */) | 3623 | font height. |
| 3624 | |||
| 3625 | If FRAME is nil, it defaults to the selected frame. */) | ||
| 3620 | (Lisp_Object frame, Lisp_Object width, Lisp_Object height, Lisp_Object pixelwise) | 3626 | (Lisp_Object frame, Lisp_Object width, Lisp_Object height, Lisp_Object pixelwise) |
| 3621 | { | 3627 | { |
| 3622 | struct frame *f = decode_live_frame (frame); | 3628 | struct frame *f = decode_live_frame (frame); |
diff --git a/src/image.c b/src/image.c index 5eb41322950..6b85ab78f61 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -1592,17 +1592,6 @@ make_image_cache (void) | |||
| 1592 | return c; | 1592 | return c; |
| 1593 | } | 1593 | } |
| 1594 | 1594 | ||
| 1595 | /* Compare two lists (one of which must be proper), comparing each | ||
| 1596 | element with `eq'. */ | ||
| 1597 | static bool | ||
| 1598 | equal_lists (Lisp_Object a, Lisp_Object b) | ||
| 1599 | { | ||
| 1600 | while (CONSP (a) && CONSP (b) && EQ (XCAR (a), XCAR (b))) | ||
| 1601 | a = XCDR (a), b = XCDR (b); | ||
| 1602 | |||
| 1603 | return EQ (a, b); | ||
| 1604 | } | ||
| 1605 | |||
| 1606 | /* Find an image matching SPEC in the cache, and return it. If no | 1595 | /* Find an image matching SPEC in the cache, and return it. If no |
| 1607 | image is found, return NULL. */ | 1596 | image is found, return NULL. */ |
| 1608 | static struct image * | 1597 | static struct image * |
| @@ -1630,7 +1619,7 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash, | |||
| 1630 | 1619 | ||
| 1631 | for (img = c->buckets[i]; img; img = img->next) | 1620 | for (img = c->buckets[i]; img; img = img->next) |
| 1632 | if (img->hash == hash | 1621 | if (img->hash == hash |
| 1633 | && equal_lists (img->spec, spec) | 1622 | && !NILP (Fequal (img->spec, spec)) |
| 1634 | && (ignore_colors || (img->face_foreground == foreground | 1623 | && (ignore_colors || (img->face_foreground == foreground |
| 1635 | && img->face_background == background))) | 1624 | && img->face_background == background))) |
| 1636 | break; | 1625 | break; |
| @@ -1644,12 +1633,13 @@ static void | |||
| 1644 | uncache_image (struct frame *f, Lisp_Object spec) | 1633 | uncache_image (struct frame *f, Lisp_Object spec) |
| 1645 | { | 1634 | { |
| 1646 | struct image *img; | 1635 | struct image *img; |
| 1636 | EMACS_UINT hash = sxhash (spec); | ||
| 1647 | 1637 | ||
| 1648 | /* Because the background colors are based on the current face, we | 1638 | /* Because the background colors are based on the current face, we |
| 1649 | can have multiple copies of an image with the same spec. We want | 1639 | can have multiple copies of an image with the same spec. We want |
| 1650 | to remove them all to ensure the user doesn't see an old version | 1640 | to remove them all to ensure the user doesn't see an old version |
| 1651 | of the image when the face changes. */ | 1641 | of the image when the face changes. */ |
| 1652 | while ((img = search_image_cache (f, spec, sxhash (spec), 0, 0, true))) | 1642 | while ((img = search_image_cache (f, spec, hash, 0, 0, true))) |
| 1653 | { | 1643 | { |
| 1654 | free_image (f, img); | 1644 | free_image (f, img); |
| 1655 | /* As display glyphs may still be referring to the image ID, we | 1645 | /* As display glyphs may still be referring to the image ID, we |
| @@ -1802,6 +1792,55 @@ which is then usually a filename. */) | |||
| 1802 | return Qnil; | 1792 | return Qnil; |
| 1803 | } | 1793 | } |
| 1804 | 1794 | ||
| 1795 | static size_t | ||
| 1796 | image_frame_cache_size (struct frame *f) | ||
| 1797 | { | ||
| 1798 | size_t total = 0; | ||
| 1799 | #if defined USE_CAIRO | ||
| 1800 | struct image_cache *c = FRAME_IMAGE_CACHE (f); | ||
| 1801 | |||
| 1802 | if (!c) | ||
| 1803 | return 0; | ||
| 1804 | |||
| 1805 | for (ptrdiff_t i = 0; i < c->used; ++i) | ||
| 1806 | { | ||
| 1807 | struct image *img = c->images[i]; | ||
| 1808 | |||
| 1809 | if (img && img->pixmap && img->pixmap != NO_PIXMAP) | ||
| 1810 | total += img->pixmap->width * img->pixmap->height * | ||
| 1811 | img->pixmap->bits_per_pixel / 8; | ||
| 1812 | } | ||
| 1813 | #elif defined HAVE_NTGUI | ||
| 1814 | struct image_cache *c = FRAME_IMAGE_CACHE (f); | ||
| 1815 | |||
| 1816 | if (!c) | ||
| 1817 | return 0; | ||
| 1818 | |||
| 1819 | for (ptrdiff_t i = 0; i < c->used; ++i) | ||
| 1820 | { | ||
| 1821 | struct image *img = c->images[i]; | ||
| 1822 | |||
| 1823 | if (img && img->pixmap && img->pixmap != NO_PIXMAP) | ||
| 1824 | total += w32_image_size (img); | ||
| 1825 | } | ||
| 1826 | #endif | ||
| 1827 | return total; | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | DEFUN ("image-cache-size", Fimage_cache_size, Simage_cache_size, 0, 0, 0, | ||
| 1831 | doc: /* Return the size of the image cache. */) | ||
| 1832 | (void) | ||
| 1833 | { | ||
| 1834 | Lisp_Object tail, frame; | ||
| 1835 | size_t total = 0; | ||
| 1836 | |||
| 1837 | FOR_EACH_FRAME (tail, frame) | ||
| 1838 | if (FRAME_WINDOW_P (XFRAME (frame))) | ||
| 1839 | total += image_frame_cache_size (XFRAME (frame)); | ||
| 1840 | |||
| 1841 | return make_int (total); | ||
| 1842 | } | ||
| 1843 | |||
| 1805 | 1844 | ||
| 1806 | DEFUN ("image-flush", Fimage_flush, Simage_flush, | 1845 | DEFUN ("image-flush", Fimage_flush, Simage_flush, |
| 1807 | 1, 2, 0, | 1846 | 1, 2, 0, |
| @@ -9453,6 +9492,7 @@ enum svg_keyword_index | |||
| 9453 | SVG_TYPE, | 9492 | SVG_TYPE, |
| 9454 | SVG_DATA, | 9493 | SVG_DATA, |
| 9455 | SVG_FILE, | 9494 | SVG_FILE, |
| 9495 | SVG_BASE_URI, | ||
| 9456 | SVG_ASCENT, | 9496 | SVG_ASCENT, |
| 9457 | SVG_MARGIN, | 9497 | SVG_MARGIN, |
| 9458 | SVG_RELIEF, | 9498 | SVG_RELIEF, |
| @@ -9472,6 +9512,7 @@ static const struct image_keyword svg_format[SVG_LAST] = | |||
| 9472 | {":type", IMAGE_SYMBOL_VALUE, 1}, | 9512 | {":type", IMAGE_SYMBOL_VALUE, 1}, |
| 9473 | {":data", IMAGE_STRING_VALUE, 0}, | 9513 | {":data", IMAGE_STRING_VALUE, 0}, |
| 9474 | {":file", IMAGE_STRING_VALUE, 0}, | 9514 | {":file", IMAGE_STRING_VALUE, 0}, |
| 9515 | {":base-uri", IMAGE_STRING_VALUE, 0}, | ||
| 9475 | {":ascent", IMAGE_ASCENT_VALUE, 0}, | 9516 | {":ascent", IMAGE_ASCENT_VALUE, 0}, |
| 9476 | {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0}, | 9517 | {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0}, |
| 9477 | {":relief", IMAGE_INTEGER_VALUE, 0}, | 9518 | {":relief", IMAGE_INTEGER_VALUE, 0}, |
| @@ -9544,6 +9585,9 @@ DEF_DLL_FN (gboolean, rsvg_handle_write, | |||
| 9544 | DEF_DLL_FN (gboolean, rsvg_handle_close, (RsvgHandle *, GError **)); | 9585 | DEF_DLL_FN (gboolean, rsvg_handle_close, (RsvgHandle *, GError **)); |
| 9545 | # endif | 9586 | # endif |
| 9546 | 9587 | ||
| 9588 | DEF_DLL_FN (void, rsvg_handle_set_dpi_x_y, | ||
| 9589 | (RsvgHandle * handle, double dpi_x, double dpi_y)); | ||
| 9590 | |||
| 9547 | # if LIBRSVG_CHECK_VERSION (2, 46, 0) | 9591 | # if LIBRSVG_CHECK_VERSION (2, 46, 0) |
| 9548 | DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions, | 9592 | DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions, |
| 9549 | (RsvgHandle *, gboolean *, RsvgLength *, gboolean *, | 9593 | (RsvgHandle *, gboolean *, RsvgLength *, gboolean *, |
| @@ -9600,6 +9644,7 @@ init_svg_functions (void) | |||
| 9600 | LOAD_DLL_FN (library, rsvg_handle_write); | 9644 | LOAD_DLL_FN (library, rsvg_handle_write); |
| 9601 | LOAD_DLL_FN (library, rsvg_handle_close); | 9645 | LOAD_DLL_FN (library, rsvg_handle_close); |
| 9602 | #endif | 9646 | #endif |
| 9647 | LOAD_DLL_FN (library, rsvg_handle_set_dpi_x_y); | ||
| 9603 | #if LIBRSVG_CHECK_VERSION (2, 46, 0) | 9648 | #if LIBRSVG_CHECK_VERSION (2, 46, 0) |
| 9604 | LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions); | 9649 | LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions); |
| 9605 | LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer); | 9650 | LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer); |
| @@ -9655,6 +9700,7 @@ init_svg_functions (void) | |||
| 9655 | # undef rsvg_handle_set_base_uri | 9700 | # undef rsvg_handle_set_base_uri |
| 9656 | # undef rsvg_handle_write | 9701 | # undef rsvg_handle_write |
| 9657 | # endif | 9702 | # endif |
| 9703 | # undef rsvg_handle_set_dpi_x_y | ||
| 9658 | 9704 | ||
| 9659 | # define gdk_pixbuf_get_bits_per_sample fn_gdk_pixbuf_get_bits_per_sample | 9705 | # define gdk_pixbuf_get_bits_per_sample fn_gdk_pixbuf_get_bits_per_sample |
| 9660 | # define gdk_pixbuf_get_colorspace fn_gdk_pixbuf_get_colorspace | 9706 | # define gdk_pixbuf_get_colorspace fn_gdk_pixbuf_get_colorspace |
| @@ -9688,6 +9734,7 @@ init_svg_functions (void) | |||
| 9688 | # define rsvg_handle_set_base_uri fn_rsvg_handle_set_base_uri | 9734 | # define rsvg_handle_set_base_uri fn_rsvg_handle_set_base_uri |
| 9689 | # define rsvg_handle_write fn_rsvg_handle_write | 9735 | # define rsvg_handle_write fn_rsvg_handle_write |
| 9690 | # endif | 9736 | # endif |
| 9737 | # define rsvg_handle_set_dpi_x_y fn_rsvg_handle_set_dpi_x_y | ||
| 9691 | 9738 | ||
| 9692 | # endif /* !WINDOWSNT */ | 9739 | # endif /* !WINDOWSNT */ |
| 9693 | 9740 | ||
| @@ -9698,10 +9745,11 @@ static bool | |||
| 9698 | svg_load (struct frame *f, struct image *img) | 9745 | svg_load (struct frame *f, struct image *img) |
| 9699 | { | 9746 | { |
| 9700 | bool success_p = 0; | 9747 | bool success_p = 0; |
| 9701 | Lisp_Object file_name; | 9748 | Lisp_Object file_name, base_uri; |
| 9702 | 9749 | ||
| 9703 | /* If IMG->spec specifies a file name, create a non-file spec from it. */ | 9750 | /* If IMG->spec specifies a file name, create a non-file spec from it. */ |
| 9704 | file_name = image_spec_value (img->spec, QCfile, NULL); | 9751 | file_name = image_spec_value (img->spec, QCfile, NULL); |
| 9752 | base_uri = image_spec_value (img->spec, QCbase_uri, NULL); | ||
| 9705 | if (STRINGP (file_name)) | 9753 | if (STRINGP (file_name)) |
| 9706 | { | 9754 | { |
| 9707 | int fd; | 9755 | int fd; |
| @@ -9721,15 +9769,16 @@ svg_load (struct frame *f, struct image *img) | |||
| 9721 | return 0; | 9769 | return 0; |
| 9722 | } | 9770 | } |
| 9723 | /* If the file was slurped into memory properly, parse it. */ | 9771 | /* If the file was slurped into memory properly, parse it. */ |
| 9724 | success_p = svg_load_image (f, img, contents, size, | 9772 | if (!STRINGP (base_uri)) |
| 9725 | SSDATA (ENCODE_FILE (file))); | 9773 | base_uri = ENCODE_FILE (file); |
| 9774 | success_p = svg_load_image (f, img, contents, size, SSDATA (base_uri)); | ||
| 9726 | xfree (contents); | 9775 | xfree (contents); |
| 9727 | } | 9776 | } |
| 9728 | /* Else it's not a file, it's a Lisp object. Load the image from a | 9777 | /* Else it's not a file, it's a Lisp object. Load the image from a |
| 9729 | Lisp object rather than a file. */ | 9778 | Lisp object rather than a file. */ |
| 9730 | else | 9779 | else |
| 9731 | { | 9780 | { |
| 9732 | Lisp_Object data, original_filename; | 9781 | Lisp_Object data; |
| 9733 | 9782 | ||
| 9734 | data = image_spec_value (img->spec, QCdata, NULL); | 9783 | data = image_spec_value (img->spec, QCdata, NULL); |
| 9735 | if (!STRINGP (data)) | 9784 | if (!STRINGP (data)) |
| @@ -9737,10 +9786,10 @@ svg_load (struct frame *f, struct image *img) | |||
| 9737 | image_error ("Invalid image data `%s'", data); | 9786 | image_error ("Invalid image data `%s'", data); |
| 9738 | return 0; | 9787 | return 0; |
| 9739 | } | 9788 | } |
| 9740 | original_filename = BVAR (current_buffer, filename); | 9789 | if (!STRINGP (base_uri)) |
| 9790 | base_uri = BVAR (current_buffer, filename); | ||
| 9741 | success_p = svg_load_image (f, img, SSDATA (data), SBYTES (data), | 9791 | success_p = svg_load_image (f, img, SSDATA (data), SBYTES (data), |
| 9742 | (NILP (original_filename) ? NULL | 9792 | (NILP (base_uri) ? NULL : SSDATA (base_uri))); |
| 9743 | : SSDATA (original_filename))); | ||
| 9744 | } | 9793 | } |
| 9745 | 9794 | ||
| 9746 | return success_p; | 9795 | return success_p; |
| @@ -9748,11 +9797,8 @@ svg_load (struct frame *f, struct image *img) | |||
| 9748 | 9797 | ||
| 9749 | #if LIBRSVG_CHECK_VERSION (2, 46, 0) | 9798 | #if LIBRSVG_CHECK_VERSION (2, 46, 0) |
| 9750 | static double | 9799 | static double |
| 9751 | svg_css_length_to_pixels (RsvgLength length) | 9800 | svg_css_length_to_pixels (RsvgLength length, double dpi) |
| 9752 | { | 9801 | { |
| 9753 | /* FIXME: 96 appears to be a pretty standard DPI but we should | ||
| 9754 | probably use the real DPI if we can get it. */ | ||
| 9755 | double dpi = 96; | ||
| 9756 | double value = length.length; | 9802 | double value = length.length; |
| 9757 | 9803 | ||
| 9758 | switch (length.unit) | 9804 | switch (length.unit) |
| @@ -9826,6 +9872,9 @@ svg_load_image (struct frame *f, struct image *img, char *contents, | |||
| 9826 | rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file, | 9872 | rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file, |
| 9827 | RSVG_HANDLE_FLAGS_NONE, | 9873 | RSVG_HANDLE_FLAGS_NONE, |
| 9828 | NULL, &err); | 9874 | NULL, &err); |
| 9875 | rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx, | ||
| 9876 | FRAME_DISPLAY_INFO (f)->resy); | ||
| 9877 | |||
| 9829 | if (base_file) | 9878 | if (base_file) |
| 9830 | g_object_unref (base_file); | 9879 | g_object_unref (base_file); |
| 9831 | g_object_unref (input_stream); | 9880 | g_object_unref (input_stream); |
| @@ -9837,7 +9886,11 @@ svg_load_image (struct frame *f, struct image *img, char *contents, | |||
| 9837 | rsvg_handle = rsvg_handle_new (); | 9886 | rsvg_handle = rsvg_handle_new (); |
| 9838 | eassume (rsvg_handle); | 9887 | eassume (rsvg_handle); |
| 9839 | 9888 | ||
| 9889 | rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx, | ||
| 9890 | FRAME_DISPLAY_INFO (f)->resy); | ||
| 9891 | |||
| 9840 | /* Set base_uri for properly handling referenced images (via 'href'). | 9892 | /* Set base_uri for properly handling referenced images (via 'href'). |
| 9893 | Can be explicitly specified using `:base_uri' image property. | ||
| 9841 | See rsvg bug 596114 - "image refs are relative to curdir, not .svg file" | 9894 | See rsvg bug 596114 - "image refs are relative to curdir, not .svg file" |
| 9842 | <https://gitlab.gnome.org/GNOME/librsvg/issues/33>. */ | 9895 | <https://gitlab.gnome.org/GNOME/librsvg/issues/33>. */ |
| 9843 | if (filename) | 9896 | if (filename) |
| @@ -9860,6 +9913,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents, | |||
| 9860 | /* Try the instrinsic dimensions first. */ | 9913 | /* Try the instrinsic dimensions first. */ |
| 9861 | gboolean has_width, has_height, has_viewbox; | 9914 | gboolean has_width, has_height, has_viewbox; |
| 9862 | RsvgLength iwidth, iheight; | 9915 | RsvgLength iwidth, iheight; |
| 9916 | double dpi = FRAME_DISPLAY_INFO (f)->resx; | ||
| 9863 | 9917 | ||
| 9864 | rsvg_handle_get_intrinsic_dimensions (rsvg_handle, | 9918 | rsvg_handle_get_intrinsic_dimensions (rsvg_handle, |
| 9865 | &has_width, &iwidth, | 9919 | &has_width, &iwidth, |
| @@ -9869,19 +9923,19 @@ svg_load_image (struct frame *f, struct image *img, char *contents, | |||
| 9869 | if (has_width && has_height) | 9923 | if (has_width && has_height) |
| 9870 | { | 9924 | { |
| 9871 | /* Success! We can use these values directly. */ | 9925 | /* Success! We can use these values directly. */ |
| 9872 | viewbox_width = svg_css_length_to_pixels (iwidth); | 9926 | viewbox_width = svg_css_length_to_pixels (iwidth, dpi); |
| 9873 | viewbox_height = svg_css_length_to_pixels (iheight); | 9927 | viewbox_height = svg_css_length_to_pixels (iheight, dpi); |
| 9874 | } | 9928 | } |
| 9875 | else if (has_width && has_viewbox) | 9929 | else if (has_width && has_viewbox) |
| 9876 | { | 9930 | { |
| 9877 | viewbox_width = svg_css_length_to_pixels (iwidth); | 9931 | viewbox_width = svg_css_length_to_pixels (iwidth, dpi); |
| 9878 | viewbox_height = svg_css_length_to_pixels (iwidth) | 9932 | viewbox_height = svg_css_length_to_pixels (iwidth, dpi) |
| 9879 | * viewbox.width / viewbox.height; | 9933 | * viewbox.width / viewbox.height; |
| 9880 | } | 9934 | } |
| 9881 | else if (has_height && has_viewbox) | 9935 | else if (has_height && has_viewbox) |
| 9882 | { | 9936 | { |
| 9883 | viewbox_height = svg_css_length_to_pixels (iheight); | 9937 | viewbox_height = svg_css_length_to_pixels (iheight, dpi); |
| 9884 | viewbox_width = svg_css_length_to_pixels (iheight) | 9938 | viewbox_width = svg_css_length_to_pixels (iheight, dpi) |
| 9885 | * viewbox.height / viewbox.width; | 9939 | * viewbox.height / viewbox.width; |
| 9886 | } | 9940 | } |
| 9887 | else if (has_viewbox) | 9941 | else if (has_viewbox) |
| @@ -9990,6 +10044,10 @@ svg_load_image (struct frame *f, struct image *img, char *contents, | |||
| 9990 | rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file, | 10044 | rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file, |
| 9991 | RSVG_HANDLE_FLAGS_NONE, | 10045 | RSVG_HANDLE_FLAGS_NONE, |
| 9992 | NULL, &err); | 10046 | NULL, &err); |
| 10047 | |||
| 10048 | rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx, | ||
| 10049 | FRAME_DISPLAY_INFO (f)->resy); | ||
| 10050 | |||
| 9993 | if (base_file) | 10051 | if (base_file) |
| 9994 | g_object_unref (base_file); | 10052 | g_object_unref (base_file); |
| 9995 | g_object_unref (input_stream); | 10053 | g_object_unref (input_stream); |
| @@ -10001,7 +10059,11 @@ svg_load_image (struct frame *f, struct image *img, char *contents, | |||
| 10001 | rsvg_handle = rsvg_handle_new (); | 10059 | rsvg_handle = rsvg_handle_new (); |
| 10002 | eassume (rsvg_handle); | 10060 | eassume (rsvg_handle); |
| 10003 | 10061 | ||
| 10062 | rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx, | ||
| 10063 | FRAME_DISPLAY_INFO (f)->resy); | ||
| 10064 | |||
| 10004 | /* Set base_uri for properly handling referenced images (via 'href'). | 10065 | /* Set base_uri for properly handling referenced images (via 'href'). |
| 10066 | Can be explicitly specified using `:base_uri' image property. | ||
| 10005 | See rsvg bug 596114 - "image refs are relative to curdir, not .svg file" | 10067 | See rsvg bug 596114 - "image refs are relative to curdir, not .svg file" |
| 10006 | <https://gitlab.gnome.org/GNOME/librsvg/issues/33>. */ | 10068 | <https://gitlab.gnome.org/GNOME/librsvg/issues/33>. */ |
| 10007 | if (filename) | 10069 | if (filename) |
| @@ -10684,6 +10746,7 @@ non-numeric, there is no explicit limit on the size of images. */); | |||
| 10684 | 10746 | ||
| 10685 | #if defined (HAVE_RSVG) | 10747 | #if defined (HAVE_RSVG) |
| 10686 | DEFSYM (Qsvg, "svg"); | 10748 | DEFSYM (Qsvg, "svg"); |
| 10749 | DEFSYM (QCbase_uri, ":base-uri"); | ||
| 10687 | add_image_type (Qsvg); | 10750 | add_image_type (Qsvg); |
| 10688 | #ifdef HAVE_NTGUI | 10751 | #ifdef HAVE_NTGUI |
| 10689 | /* Other libraries used directly by svg code. */ | 10752 | /* Other libraries used directly by svg code. */ |
| @@ -10713,6 +10776,7 @@ non-numeric, there is no explicit limit on the size of images. */); | |||
| 10713 | defsubr (&Simage_size); | 10776 | defsubr (&Simage_size); |
| 10714 | defsubr (&Simage_mask_p); | 10777 | defsubr (&Simage_mask_p); |
| 10715 | defsubr (&Simage_metadata); | 10778 | defsubr (&Simage_metadata); |
| 10779 | defsubr (&Simage_cache_size); | ||
| 10716 | 10780 | ||
| 10717 | #ifdef GLYPH_DEBUG | 10781 | #ifdef GLYPH_DEBUG |
| 10718 | defsubr (&Simagep); | 10782 | defsubr (&Simagep); |
diff --git a/src/lisp.h b/src/lisp.h index a5a90cce1b4..5900b8d25e4 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -1900,16 +1900,17 @@ ASCII_CHAR_P (intmax_t c) | |||
| 1900 | return 0 <= c && c < 0x80; | 1900 | return 0 <= c && c < 0x80; |
| 1901 | } | 1901 | } |
| 1902 | 1902 | ||
| 1903 | /* A char-table is a kind of vectorlike, with contents are like a | 1903 | /* A char-table is a kind of vectorlike, with contents like a vector, |
| 1904 | vector but with a few other slots. For some purposes, it makes | 1904 | but with a few additional slots. For some purposes, it makes sense |
| 1905 | sense to handle a char-table with type struct Lisp_Vector. An | 1905 | to handle a char-table as type 'struct Lisp_Vector'. An element of |
| 1906 | element of a char table can be any Lisp objects, but if it is a sub | 1906 | a char-table can be any Lisp object, but if it is a sub-char-table, |
| 1907 | char-table, we treat it a table that contains information of a | 1907 | we treat it as a table that contains information of a specific |
| 1908 | specific range of characters. A sub char-table is like a vector but | 1908 | range of characters. A sub-char-table is like a vector, but with |
| 1909 | with two integer fields between the header and Lisp data, which means | 1909 | two integer fields between the header and Lisp data, which means |
| 1910 | that it has to be marked with some precautions (see mark_char_table | 1910 | that it has to be marked with some precautions (see mark_char_table |
| 1911 | in alloc.c). A sub char-table appears only in an element of a char-table, | 1911 | in alloc.c). A sub-char-table appears only in an element of a |
| 1912 | and there's no way to access it directly from Emacs Lisp program. */ | 1912 | char-table, and there's no way to access it directly from a Lisp |
| 1913 | program. */ | ||
| 1913 | 1914 | ||
| 1914 | enum CHARTAB_SIZE_BITS | 1915 | enum CHARTAB_SIZE_BITS |
| 1915 | { | 1916 | { |
| @@ -1929,11 +1930,11 @@ struct Lisp_Char_Table | |||
| 1929 | contents, and extras slots. */ | 1930 | contents, and extras slots. */ |
| 1930 | union vectorlike_header header; | 1931 | union vectorlike_header header; |
| 1931 | 1932 | ||
| 1932 | /* This holds a default value, | 1933 | /* This holds the default value, which is used whenever the value |
| 1933 | which is used whenever the value for a specific character is nil. */ | 1934 | for a specific character is nil. */ |
| 1934 | Lisp_Object defalt; | 1935 | Lisp_Object defalt; |
| 1935 | 1936 | ||
| 1936 | /* This points to another char table, which we inherit from when the | 1937 | /* This points to another char table, from which we inherit when the |
| 1937 | value for a specific character is nil. The `defalt' slot takes | 1938 | value for a specific character is nil. The `defalt' slot takes |
| 1938 | precedence over this. */ | 1939 | precedence over this. */ |
| 1939 | Lisp_Object parent; | 1940 | Lisp_Object parent; |
| @@ -1942,8 +1943,8 @@ struct Lisp_Char_Table | |||
| 1942 | meant for. */ | 1943 | meant for. */ |
| 1943 | Lisp_Object purpose; | 1944 | Lisp_Object purpose; |
| 1944 | 1945 | ||
| 1945 | /* The bottom sub char-table for characters of the range 0..127. It | 1946 | /* The bottom sub char-table for characters in the range 0..127. It |
| 1946 | is nil if none of ASCII character has a specific value. */ | 1947 | is nil if no ASCII character has a specific value. */ |
| 1947 | Lisp_Object ascii; | 1948 | Lisp_Object ascii; |
| 1948 | 1949 | ||
| 1949 | Lisp_Object contents[(1 << CHARTAB_SIZE_BITS_0)]; | 1950 | Lisp_Object contents[(1 << CHARTAB_SIZE_BITS_0)]; |
| @@ -2018,7 +2019,7 @@ CHAR_TABLE_REF_ASCII (Lisp_Object ct, ptrdiff_t idx) | |||
| 2018 | } | 2019 | } |
| 2019 | 2020 | ||
| 2020 | /* Almost equivalent to Faref (CT, IDX) with optimization for ASCII | 2021 | /* Almost equivalent to Faref (CT, IDX) with optimization for ASCII |
| 2021 | characters. Do not check validity of CT. */ | 2022 | characters. Does not check validity of CT. */ |
| 2022 | INLINE Lisp_Object | 2023 | INLINE Lisp_Object |
| 2023 | CHAR_TABLE_REF (Lisp_Object ct, int idx) | 2024 | CHAR_TABLE_REF (Lisp_Object ct, int idx) |
| 2024 | { | 2025 | { |
| @@ -2028,7 +2029,7 @@ CHAR_TABLE_REF (Lisp_Object ct, int idx) | |||
| 2028 | } | 2029 | } |
| 2029 | 2030 | ||
| 2030 | /* Equivalent to Faset (CT, IDX, VAL) with optimization for ASCII and | 2031 | /* Equivalent to Faset (CT, IDX, VAL) with optimization for ASCII and |
| 2031 | 8-bit European characters. Do not check validity of CT. */ | 2032 | 8-bit European characters. Does not check validity of CT. */ |
| 2032 | INLINE void | 2033 | INLINE void |
| 2033 | CHAR_TABLE_SET (Lisp_Object ct, int idx, Lisp_Object val) | 2034 | CHAR_TABLE_SET (Lisp_Object ct, int idx, Lisp_Object val) |
| 2034 | { | 2035 | { |
diff --git a/src/nsterm.m b/src/nsterm.m index 0729c961bdf..7972fa4dabb 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -1166,7 +1166,6 @@ ns_update_end (struct frame *f) | |||
| 1166 | { | 1166 | { |
| 1167 | #endif | 1167 | #endif |
| 1168 | [NSGraphicsContext setCurrentContext:nil]; | 1168 | [NSGraphicsContext setCurrentContext:nil]; |
| 1169 | [view setNeedsDisplay:YES]; | ||
| 1170 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 | 1169 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 |
| 1171 | } | 1170 | } |
| 1172 | else | 1171 | else |
| @@ -3056,7 +3055,7 @@ ns_clear_under_internal_border (struct frame *f) | |||
| 3056 | if (!face) | 3055 | if (!face) |
| 3057 | return; | 3056 | return; |
| 3058 | 3057 | ||
| 3059 | ns_focus (f, &frame_rect, 1); | 3058 | ns_focus (f, NULL, 1); |
| 3060 | [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set]; | 3059 | [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set]; |
| 3061 | for (int i = 0; i < 4 ; i++) | 3060 | for (int i = 0; i < 4 ; i++) |
| 3062 | { | 3061 | { |
| @@ -4987,8 +4986,8 @@ ns_set_vertical_scroll_bar (struct window *window, | |||
| 4987 | [bar removeFromSuperview]; | 4986 | [bar removeFromSuperview]; |
| 4988 | wset_vertical_scroll_bar (window, Qnil); | 4987 | wset_vertical_scroll_bar (window, Qnil); |
| 4989 | [bar release]; | 4988 | [bar release]; |
| 4989 | ns_clear_frame_area (f, left, top, width, height); | ||
| 4990 | } | 4990 | } |
| 4991 | ns_clear_frame_area (f, left, top, width, height); | ||
| 4992 | unblock_input (); | 4991 | unblock_input (); |
| 4993 | return; | 4992 | return; |
| 4994 | } | 4993 | } |
| @@ -5010,7 +5009,7 @@ ns_set_vertical_scroll_bar (struct window *window, | |||
| 5010 | r.size.width = oldRect.size.width; | 5009 | r.size.width = oldRect.size.width; |
| 5011 | if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) | 5010 | if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) |
| 5012 | { | 5011 | { |
| 5013 | if (oldRect.origin.x != r.origin.x) | 5012 | if (! NSEqualRects (oldRect, r)) |
| 5014 | ns_clear_frame_area (f, left, top, width, height); | 5013 | ns_clear_frame_area (f, left, top, width, height); |
| 5015 | [bar setFrame: r]; | 5014 | [bar setFrame: r]; |
| 5016 | } | 5015 | } |
| @@ -5088,8 +5087,7 @@ ns_set_horizontal_scroll_bar (struct window *window, | |||
| 5088 | oldRect = [bar frame]; | 5087 | oldRect = [bar frame]; |
| 5089 | if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) | 5088 | if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) |
| 5090 | { | 5089 | { |
| 5091 | if (oldRect.origin.y != r.origin.y) | 5090 | ns_clear_frame_area (f, left, top, width, height); |
| 5092 | ns_clear_frame_area (f, left, top, width, height); | ||
| 5093 | [bar setFrame: r]; | 5091 | [bar setFrame: r]; |
| 5094 | update_p = YES; | 5092 | update_p = YES; |
| 5095 | } | 5093 | } |
diff --git a/src/regex-emacs.c b/src/regex-emacs.c index 971a5f63749..904ca0c7b95 100644 --- a/src/regex-emacs.c +++ b/src/regex-emacs.c | |||
| @@ -3575,9 +3575,11 @@ skip_noops (re_char *p, re_char *pend) | |||
| 3575 | opcode. When the function finishes, *PP will be advanced past that opcode. | 3575 | opcode. When the function finishes, *PP will be advanced past that opcode. |
| 3576 | C is character to test (possibly after translations) and CORIG is original | 3576 | C is character to test (possibly after translations) and CORIG is original |
| 3577 | character (i.e. without any translations). UNIBYTE denotes whether c is | 3577 | character (i.e. without any translations). UNIBYTE denotes whether c is |
| 3578 | unibyte or multibyte character. */ | 3578 | unibyte or multibyte character. |
| 3579 | CANON_TABLE is the canonicalisation table for case folding or Qnil. */ | ||
| 3579 | static bool | 3580 | static bool |
| 3580 | execute_charset (re_char **pp, int c, int corig, bool unibyte) | 3581 | execute_charset (re_char **pp, int c, int corig, bool unibyte, |
| 3582 | Lisp_Object canon_table) | ||
| 3581 | { | 3583 | { |
| 3582 | eassume (0 <= c && 0 <= corig); | 3584 | eassume (0 <= c && 0 <= corig); |
| 3583 | re_char *p = *pp, *rtp = NULL; | 3585 | re_char *p = *pp, *rtp = NULL; |
| @@ -3617,11 +3619,9 @@ execute_charset (re_char **pp, int c, int corig, bool unibyte) | |||
| 3617 | (class_bits & BIT_BLANK && ISBLANK (c)) || | 3619 | (class_bits & BIT_BLANK && ISBLANK (c)) || |
| 3618 | (class_bits & BIT_WORD && ISWORD (c)) || | 3620 | (class_bits & BIT_WORD && ISWORD (c)) || |
| 3619 | ((class_bits & BIT_UPPER) && | 3621 | ((class_bits & BIT_UPPER) && |
| 3620 | (ISUPPER (c) || (corig != c && | 3622 | (ISUPPER (corig) || (!NILP (canon_table) && ISLOWER (corig)))) || |
| 3621 | c == downcase (corig) && ISLOWER (c)))) || | ||
| 3622 | ((class_bits & BIT_LOWER) && | 3623 | ((class_bits & BIT_LOWER) && |
| 3623 | (ISLOWER (c) || (corig != c && | 3624 | (ISLOWER (corig) || (!NILP (canon_table) && ISUPPER (corig)))) || |
| 3624 | c == upcase (corig) && ISUPPER(c)))) || | ||
| 3625 | (class_bits & BIT_PUNCT && ISPUNCT (c)) || | 3625 | (class_bits & BIT_PUNCT && ISPUNCT (c)) || |
| 3626 | (class_bits & BIT_GRAPH && ISGRAPH (c)) || | 3626 | (class_bits & BIT_GRAPH && ISGRAPH (c)) || |
| 3627 | (class_bits & BIT_PRINT && ISPRINT (c))) | 3627 | (class_bits & BIT_PRINT && ISPRINT (c))) |
| @@ -3696,7 +3696,8 @@ mutually_exclusive_p (struct re_pattern_buffer *bufp, re_char *p1, | |||
| 3696 | else if ((re_opcode_t) *p1 == charset | 3696 | else if ((re_opcode_t) *p1 == charset |
| 3697 | || (re_opcode_t) *p1 == charset_not) | 3697 | || (re_opcode_t) *p1 == charset_not) |
| 3698 | { | 3698 | { |
| 3699 | if (!execute_charset (&p1, c, c, !multibyte || ASCII_CHAR_P (c))) | 3699 | if (!execute_charset (&p1, c, c, !multibyte || ASCII_CHAR_P (c), |
| 3700 | Qnil)) | ||
| 3700 | { | 3701 | { |
| 3701 | DEBUG_PRINT (" No match => fast loop.\n"); | 3702 | DEBUG_PRINT (" No match => fast loop.\n"); |
| 3702 | return true; | 3703 | return true; |
| @@ -4367,7 +4368,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, | |||
| 4367 | } | 4368 | } |
| 4368 | 4369 | ||
| 4369 | p -= 1; | 4370 | p -= 1; |
| 4370 | if (!execute_charset (&p, c, corig, unibyte_char)) | 4371 | if (!execute_charset (&p, c, corig, unibyte_char, translate)) |
| 4371 | goto fail; | 4372 | goto fail; |
| 4372 | 4373 | ||
| 4373 | d += len; | 4374 | d += len; |
diff --git a/src/w32gui.h b/src/w32gui.h index dfec1f08617..fc8131130fb 100644 --- a/src/w32gui.h +++ b/src/w32gui.h | |||
| @@ -46,6 +46,7 @@ extern int w32_load_image (struct frame *f, struct image *img, | |||
| 46 | Lisp_Object spec_file, Lisp_Object spec_data); | 46 | Lisp_Object spec_file, Lisp_Object spec_data); |
| 47 | extern bool w32_can_use_native_image_api (Lisp_Object); | 47 | extern bool w32_can_use_native_image_api (Lisp_Object); |
| 48 | extern void w32_gdiplus_shutdown (void); | 48 | extern void w32_gdiplus_shutdown (void); |
| 49 | extern size_t w32_image_size (struct image *); | ||
| 49 | 50 | ||
| 50 | #define FACE_DEFAULT (~0) | 51 | #define FACE_DEFAULT (~0) |
| 51 | 52 | ||
diff --git a/src/w32term.c b/src/w32term.c index 23cb380040b..dc5cd1f6997 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -1991,6 +1991,17 @@ w32_draw_image_foreground (struct glyph_string *s) | |||
| 1991 | RestoreDC (s->hdc ,-1); | 1991 | RestoreDC (s->hdc ,-1); |
| 1992 | } | 1992 | } |
| 1993 | 1993 | ||
| 1994 | size_t | ||
| 1995 | w32_image_size (struct image *img) | ||
| 1996 | { | ||
| 1997 | BITMAP bm_info; | ||
| 1998 | size_t rv = 0; | ||
| 1999 | |||
| 2000 | if (GetObject (img->pixmap, sizeof (BITMAP), &bm_info)) | ||
| 2001 | rv = bm_info.bmWidth * bm_info.bmHeight * bm_info.bmBitsPixel / 8; | ||
| 2002 | return rv; | ||
| 2003 | } | ||
| 2004 | |||
| 1994 | 2005 | ||
| 1995 | /* Draw a relief around the image glyph string S. */ | 2006 | /* Draw a relief around the image glyph string S. */ |
| 1996 | 2007 | ||
diff --git a/src/window.c b/src/window.c index 6cd3122b43b..8e75e460b2b 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -5669,7 +5669,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5669 | if (whole) | 5669 | if (whole) |
| 5670 | { | 5670 | { |
| 5671 | ptrdiff_t start_pos = IT_CHARPOS (it); | 5671 | ptrdiff_t start_pos = IT_CHARPOS (it); |
| 5672 | int dy = frame_line_height; | 5672 | int flh = frame_line_height; |
| 5673 | int ht = window_box_height (w); | 5673 | int ht = window_box_height (w); |
| 5674 | int nscls = sanitize_next_screen_context_lines (); | 5674 | int nscls = sanitize_next_screen_context_lines (); |
| 5675 | /* In the below we divide the window box height by the frame's | 5675 | /* In the below we divide the window box height by the frame's |
| @@ -5677,14 +5677,37 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5677 | box is not an integral multiple of the line height. This is | 5677 | box is not an integral multiple of the line height. This is |
| 5678 | important to ensure we get back to the same position when | 5678 | important to ensure we get back to the same position when |
| 5679 | scrolling up, then down. */ | 5679 | scrolling up, then down. */ |
| 5680 | dy = n * max (dy, (ht / dy - nscls) * dy); | 5680 | int dy = n * max (flh, (ht / flh - nscls) * flh); |
| 5681 | int goal_y; | ||
| 5682 | void *it_data; | ||
| 5681 | 5683 | ||
| 5682 | /* Note that move_it_vertically always moves the iterator to the | 5684 | /* Note that move_it_vertically always moves the iterator to the |
| 5683 | start of a line. So, if the last line doesn't have a newline, | 5685 | start of a line. So, if the last line doesn't have a newline, |
| 5684 | we would end up at the start of the line ending at ZV. */ | 5686 | we would end up at the start of the line ending at ZV. */ |
| 5685 | if (dy <= 0) | 5687 | if (dy <= 0) |
| 5686 | { | 5688 | { |
| 5689 | goal_y = it.current_y - dy; | ||
| 5687 | move_it_vertically_backward (&it, -dy); | 5690 | move_it_vertically_backward (&it, -dy); |
| 5691 | /* Extra precision for people who want us to preserve the | ||
| 5692 | screen position of the cursor: effectively round DY to the | ||
| 5693 | nearest screen line, instead of rounding to zero; the latter | ||
| 5694 | causes point to move by one line after C-v followed by M-v, | ||
| 5695 | if the buffer has lines of different height. */ | ||
| 5696 | if (!NILP (Vscroll_preserve_screen_position) | ||
| 5697 | && it.current_y - goal_y > 0.5 * flh) | ||
| 5698 | { | ||
| 5699 | it_data = bidi_shelve_cache (); | ||
| 5700 | struct it it2 = it; | ||
| 5701 | |||
| 5702 | move_it_by_lines (&it, -1); | ||
| 5703 | if (it.current_y < goal_y - 0.5 * flh) | ||
| 5704 | { | ||
| 5705 | it = it2; | ||
| 5706 | bidi_unshelve_cache (it_data, false); | ||
| 5707 | } | ||
| 5708 | else | ||
| 5709 | bidi_unshelve_cache (it_data, true); | ||
| 5710 | } | ||
| 5688 | /* Ensure we actually do move, e.g. in case we are currently | 5711 | /* Ensure we actually do move, e.g. in case we are currently |
| 5689 | looking at an image that is taller that the window height. */ | 5712 | looking at an image that is taller that the window height. */ |
| 5690 | while (start_pos == IT_CHARPOS (it) | 5713 | while (start_pos == IT_CHARPOS (it) |
| @@ -5693,8 +5716,25 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5693 | } | 5716 | } |
| 5694 | else if (dy > 0) | 5717 | else if (dy > 0) |
| 5695 | { | 5718 | { |
| 5696 | move_it_to (&it, ZV, -1, it.current_y + dy, -1, | 5719 | goal_y = it.current_y + dy; |
| 5697 | MOVE_TO_POS | MOVE_TO_Y); | 5720 | move_it_to (&it, ZV, -1, goal_y, -1, MOVE_TO_POS | MOVE_TO_Y); |
| 5721 | /* See the comment above, for the reasons of this | ||
| 5722 | extra-precision. */ | ||
| 5723 | if (!NILP (Vscroll_preserve_screen_position) | ||
| 5724 | && goal_y - it.current_y > 0.5 * flh) | ||
| 5725 | { | ||
| 5726 | it_data = bidi_shelve_cache (); | ||
| 5727 | struct it it2 = it; | ||
| 5728 | |||
| 5729 | move_it_by_lines (&it, 1); | ||
| 5730 | if (it.current_y > goal_y + 0.5 * flh) | ||
| 5731 | { | ||
| 5732 | it = it2; | ||
| 5733 | bidi_unshelve_cache (it_data, false); | ||
| 5734 | } | ||
| 5735 | else | ||
| 5736 | bidi_unshelve_cache (it_data, true); | ||
| 5737 | } | ||
| 5698 | /* Ensure we actually do move, e.g. in case we are currently | 5738 | /* Ensure we actually do move, e.g. in case we are currently |
| 5699 | looking at an image that is taller that the window height. */ | 5739 | looking at an image that is taller that the window height. */ |
| 5700 | while (start_pos == IT_CHARPOS (it) | 5740 | while (start_pos == IT_CHARPOS (it) |
| @@ -8206,11 +8246,17 @@ is displayed in the `mode-line' face. */); | |||
| 8206 | DEFVAR_LISP ("scroll-preserve-screen-position", | 8246 | DEFVAR_LISP ("scroll-preserve-screen-position", |
| 8207 | Vscroll_preserve_screen_position, | 8247 | Vscroll_preserve_screen_position, |
| 8208 | doc: /* Controls if scroll commands move point to keep its screen position unchanged. | 8248 | doc: /* Controls if scroll commands move point to keep its screen position unchanged. |
| 8249 | |||
| 8209 | A value of nil means point does not keep its screen position except | 8250 | A value of nil means point does not keep its screen position except |
| 8210 | at the scroll margin or window boundary respectively. | 8251 | at the scroll margin or window boundary respectively. |
| 8252 | |||
| 8211 | A value of t means point keeps its screen position if the scroll | 8253 | A value of t means point keeps its screen position if the scroll |
| 8212 | command moved it vertically out of the window, e.g. when scrolling | 8254 | command moved it vertically out of the window, e.g. when scrolling |
| 8213 | by full screens. | 8255 | by full screens. If point is within `next-screen-context-lines' lines |
| 8256 | from the edges of the window, point will typically not keep its screen | ||
| 8257 | position when doing commands like `scroll-up-command'/`scroll-down-command' | ||
| 8258 | and the like. | ||
| 8259 | |||
| 8214 | Any other value means point always keeps its screen position. | 8260 | Any other value means point always keeps its screen position. |
| 8215 | Scroll commands should have the `scroll-command' property | 8261 | Scroll commands should have the `scroll-command' property |
| 8216 | on their symbols to be controlled by this variable. */); | 8262 | on their symbols to be controlled by this variable. */); |
diff --git a/src/xdisp.c b/src/xdisp.c index ed1d4761b95..689b87df421 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -1925,12 +1925,12 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1925 | /* If it3_moved stays false after the 'while' loop | 1925 | /* If it3_moved stays false after the 'while' loop |
| 1926 | below, that means we already were at a newline | 1926 | below, that means we already were at a newline |
| 1927 | before the loop (e.g., the display string begins | 1927 | before the loop (e.g., the display string begins |
| 1928 | with a newline), so we don't need to (and cannot) | 1928 | with a newline), so we don't need to return to |
| 1929 | inspect the glyphs of it3.glyph_row, because | 1929 | the last position before the display string, |
| 1930 | PRODUCE_GLYPHS will not produce anything for a | 1930 | because PRODUCE_GLYPHS will not produce anything |
| 1931 | newline, and thus it3.glyph_row stays at its | 1931 | for a newline. */ |
| 1932 | stale content it got at top of the window. */ | ||
| 1933 | bool it3_moved = false; | 1932 | bool it3_moved = false; |
| 1933 | int top_x_before_string = it3.current_x; | ||
| 1934 | /* Finally, advance the iterator until we hit the | 1934 | /* Finally, advance the iterator until we hit the |
| 1935 | first display element whose character position is | 1935 | first display element whose character position is |
| 1936 | CHARPOS, or until the first newline from the | 1936 | CHARPOS, or until the first newline from the |
| @@ -1938,6 +1938,8 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1938 | display line. */ | 1938 | display line. */ |
| 1939 | while (get_next_display_element (&it3)) | 1939 | while (get_next_display_element (&it3)) |
| 1940 | { | 1940 | { |
| 1941 | if (!EQ (it3.object, string)) | ||
| 1942 | top_x_before_string = it3.current_x; | ||
| 1941 | PRODUCE_GLYPHS (&it3); | 1943 | PRODUCE_GLYPHS (&it3); |
| 1942 | if (IT_CHARPOS (it3) == charpos | 1944 | if (IT_CHARPOS (it3) == charpos |
| 1943 | || ITERATOR_AT_END_OF_LINE_P (&it3)) | 1945 | || ITERATOR_AT_END_OF_LINE_P (&it3)) |
| @@ -1952,32 +1954,26 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1952 | if (!it3.line_number_produced_p) | 1954 | if (!it3.line_number_produced_p) |
| 1953 | { | 1955 | { |
| 1954 | if (it3.lnum_pixel_width > 0) | 1956 | if (it3.lnum_pixel_width > 0) |
| 1955 | top_x += it3.lnum_pixel_width; | 1957 | { |
| 1958 | top_x += it3.lnum_pixel_width; | ||
| 1959 | top_x_before_string += it3.lnum_pixel_width; | ||
| 1960 | } | ||
| 1956 | else if (it.line_number_produced_p) | 1961 | else if (it.line_number_produced_p) |
| 1957 | top_x += it.lnum_pixel_width; | 1962 | { |
| 1963 | top_x += it.lnum_pixel_width; | ||
| 1964 | top_x_before_string += it3.lnum_pixel_width; | ||
| 1965 | } | ||
| 1958 | } | 1966 | } |
| 1959 | /* Normally, we would exit the above loop because we | 1967 | /* Normally, we would exit the above loop because we |
| 1960 | found the display element whose character | 1968 | found the display element whose character |
| 1961 | position is CHARPOS. For the contingency that we | 1969 | position is CHARPOS. For the contingency that we |
| 1962 | didn't, and stopped at the first newline from the | 1970 | didn't, and stopped at the first newline from the |
| 1963 | display string, move back over the glyphs | 1971 | display string, reset top_x to the coordinate of |
| 1964 | produced from the string, until we find the | 1972 | the rightmost glyph not from the string. */ |
| 1965 | rightmost glyph not from the string. */ | ||
| 1966 | if (it3_moved | 1973 | if (it3_moved |
| 1967 | && newline_in_string | 1974 | && newline_in_string |
| 1968 | && IT_CHARPOS (it3) != charpos && EQ (it3.object, string)) | 1975 | && IT_CHARPOS (it3) != charpos && EQ (it3.object, string)) |
| 1969 | { | 1976 | top_x = top_x_before_string; |
| 1970 | struct glyph *g = it3.glyph_row->glyphs[TEXT_AREA] | ||
| 1971 | + it3.glyph_row->used[TEXT_AREA]; | ||
| 1972 | |||
| 1973 | while (EQ ((g - 1)->object, string)) | ||
| 1974 | { | ||
| 1975 | --g; | ||
| 1976 | top_x -= g->pixel_width; | ||
| 1977 | } | ||
| 1978 | eassert (g < it3.glyph_row->glyphs[TEXT_AREA] | ||
| 1979 | + it3.glyph_row->used[TEXT_AREA]); | ||
| 1980 | } | ||
| 1981 | } | 1977 | } |
| 1982 | } | 1978 | } |
| 1983 | 1979 | ||