commit f248960c71444a92cb91646e64d57b44523af884 (HEAD, refs/remotes/origin/master) Author: Dmitry Gutov Date: Wed Dec 20 00:22:47 2023 +0200 Add "back" button on top of the pre-rename vc-print-log buffer * lisp/vc/vc.el (log-view-vc-prev-revision) (log-view-vc-prev-fileset): New dynamic variables (bug#55871). (vc-print-log-renamed-add-button): Extract from 'vc-print-log-setup-buttons'. Bind the above variables to convey the current revision and fileset to 'vc-print-log-internal'. (vc-print-log-internal): Use it also here, to print a "back" button above the log when 'log-view-vc-prev-fileset' is set. diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 4e6581f7f27..3cd835a9d6b 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -2689,6 +2689,10 @@ vc-log-short-style (defvar log-view-vc-fileset) (defvar log-view-message-re) +;; XXX: File might have been renamed multiple times, so to support +;; multiple jumps back, this probably should be a stack of entries. +(defvar log-view-vc-prev-revision nil) +(defvar log-view-vc-prev-fileset nil) (defun vc-print-log-setup-buttons (working-revision is-start-revision limit pl-return) "Insert at the end of the current buffer buttons to show more log entries. @@ -2721,41 +2725,16 @@ vc-print-log-setup-buttons (matching-changes (cl-delete-if-not (lambda (f) (member f log-view-vc-fileset)) name-changes :key #'cdr)) - (old-names (delq nil (mapcar #'car matching-changes))) - (relatives (mapcar #'file-relative-name old-names))) + (old-names (delq nil (mapcar #'car matching-changes)))) (when old-names (goto-char (point-max)) (unless (looking-back "\n\n" (- (point) 2)) (insert "\n")) - (insert - (format - "Renamed from %s" - (mapconcat (lambda (s) - (propertize s 'font-lock-face - 'log-view-file)) - relatives ", ")) - " ") - ;; TODO: Also print a different button somewhere in the - ;; created buffer to be able to go back easily. Might - ;; require some sort of stack/history because a file can - ;; be renamed multiple times. - (insert-text-button - "View log" - 'action (lambda (&rest _ignore) - (let ((backend log-view-vc-backend)) - (with-current-buffer vc-parent-buffer - ;; To set up parent buffer in the new viewer. - (vc-print-log-internal backend old-names - last-revision t limit)))) - ;; XXX: Showing the full history for OLD-NAMES (with - ;; IS-START-REVISION=nil) can be better sometimes - ;; (e.g. when some edits still occurred after a rename - ;; -- multiple branches scenario), but it also can hurt - ;; in others because of Git's automatic history - ;; simplification: as a result, the logs for some - ;; use-package's files before merge could not be found. - 'help-echo - "Show the log for the file name(s) before the rename"))) + (vc-print-log-renamed-add-button old-names log-view-vc-backend + log-view-vc-fileset + working-revision + last-revision + limit))) ;; Perhaps there are more entries in the log. (goto-char (point-max)) (insert "\n") @@ -2777,6 +2756,49 @@ vc-print-log-setup-buttons 'help-echo "Show the log again, including all entries") (insert "\n"))))) +(defun vc-print-log-renamed-add-button ( renamed-files backend + current-fileset + current-revision + revision limit) + "Print the button for jump to the log for a different fileset. +RENAMED-FILES is the fileset to use. BACKEND is the VC backend. +REVISION is the revision from which to start the new log. +CURRENT-FILESET, if non-nil, is the fileset to use in the \"back\" +button for. Same for CURRENT-REVISION. LIMIT means the usual." + (let ((relatives (mapcar #'file-relative-name renamed-files)) + (from-to (if current-fileset "from" "to")) + (before-after (if current-fileset "before" "after"))) + (insert + (format + "Renamed %s %s" + from-to + (mapconcat (lambda (s) + (propertize s 'font-lock-face + 'log-view-file)) + relatives + ", ")) + " ") + (insert-text-button + "View log" + 'action (lambda (&rest _ignore) + ;; To set up parent buffer in the new viewer. + (with-current-buffer vc-parent-buffer + (let ((log-view-vc-prev-fileset current-fileset) + (log-view-vc-prev-revision current-revision)) + (vc-print-log-internal backend renamed-files + revision t limit)))) + ;; XXX: Showing the full history for OLD-NAMES (with + ;; IS-START-REVISION=nil) can be better sometimes + ;; (e.g. when some edits still occurred after a rename + ;; -- multiple branches scenario), but it also can hurt + ;; in others because of Git's automatic history + ;; simplification: as a result, the logs for some + ;; use-package's files before merge could not be found. + 'help-echo + (format + "Show the log for the file name(s) %s the rename" + before-after)))) + (defun vc-print-log-internal (backend files working-revision &optional is-start-revision limit type) "For specified BACKEND and FILES, show the VC log. @@ -2795,8 +2817,22 @@ vc-print-log-internal (vc-log-internal-common backend buffer-name files type (lambda (bk buf _type-arg files-arg) - (vc-call-backend bk 'print-log files-arg buf shortlog - (when is-start-revision working-revision) limit)) + (vc-call-backend bk 'print-log files-arg buf shortlog + (when is-start-revision working-revision) limit) + (when log-view-vc-prev-fileset + (with-current-buffer buf + (let ((inhibit-read-only t) + (pmark (process-mark (get-buffer-process buf)))) + (goto-char (point-min)) + (vc-print-log-renamed-add-button log-view-vc-prev-fileset + backend + nil + nil + log-view-vc-prev-revision + limit) + (insert "\n\n") + (when (< pmark (point)) + (set-marker pmark (point))))))) (lambda (_bk _files-arg ret) (save-excursion (vc-print-log-setup-buttons working-revision commit 7c1c2519167d51931a5d17f27529c8c8358c7c61 Author: Mattias Engdegård Date: Tue Dec 19 17:10:42 2023 +0100 Calc: speed up math-read-preprocess-string (bug#67536) `math-read-preprocess-string` is one of the bottlenecks of `calc-eval` and was unnecessarily slow even with no substitutions made. This affected org-mode in particular, where `calc-eval` is called repeatedly to recalculate tables. Reported by Raffael Stocker who also wrote the unit tests here. * lisp/calc/calc-aent.el (math--read-preprocess-re-cache): New. (math-read-preprocess-string): Use math--read-preprocess-re-cache, first computing it if necessary. * test/lisp/calc/calc-tests.el (calc-math-read-preprocess-string): New test. diff --git a/lisp/calc/calc-aent.el b/lisp/calc/calc-aent.el index 66ede3295ae..2aafa653e5a 100644 --- a/lisp/calc/calc-aent.el +++ b/lisp/calc/calc-aent.el @@ -547,22 +547,41 @@ math-read-subscripts "₀₁₂₃₄₅₆₇₈₉₊₋₍₎" ; 0123456789+-() "A string consisting of the subscripts allowed by Calc.") +(defvar math--read-preprocess-re-cache nil + "Cached regexp and tag: (REGEXP REPLACEMENTS SUPERSCRIPTS SUBSCRIPTS)") + ;;;###autoload (defun math-read-preprocess-string (str) "Replace some substrings of STR by Calc equivalents." - (setq str - (replace-regexp-in-string (concat "[" math-read-superscripts "]+") - "^(\\&)" str)) - (setq str - (replace-regexp-in-string (concat "[" math-read-subscripts "]+") - "_(\\&)" str)) - (let ((rep-list math-read-replacement-list)) - (while rep-list - (setq str - (replace-regexp-in-string (nth 0 (car rep-list)) - (nth 1 (car rep-list)) str)) - (setq rep-list (cdr rep-list)))) - str) + (unless (and (eq (nth 1 math--read-preprocess-re-cache) + math-read-replacement-list) + (eq (nth 2 math--read-preprocess-re-cache) + math-read-superscripts) + (eq (nth 3 math--read-preprocess-re-cache) + math-read-subscripts)) + ;; Cache invalid, recompute. + (setq math--read-preprocess-re-cache + (list (rx-to-string + `(or (or (+ (in ,math-read-superscripts)) + (group (+ (in ,math-read-subscripts)))) + (group (or ,@(mapcar #'car math-read-replacement-list)))) + t) + math-read-replacement-list + math-read-superscripts + math-read-subscripts))) + (replace-regexp-in-string + (nth 0 math--read-preprocess-re-cache) + (lambda (s) + (if (match-beginning 2) + (cadr (assoc s math-read-replacement-list)) ; not super/subscript + (concat (if (match-beginning 1) "_" "^") + "(" + (mapconcat (lambda (c) + (cadr (assoc (char-to-string c) + math-read-replacement-list))) + s) + ")"))) + str t)) ;; The next few variables are local to math-read-exprs (and math-read-expr ;; in calc-ext.el), but are set in functions they call. diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el index 5b11dd950ba..74eaf9093e8 100644 --- a/test/lisp/calc/calc-tests.el +++ b/test/lisp/calc/calc-tests.el @@ -816,5 +816,43 @@ calc-nth-root (x (calc-tests--calc-to-number (math-pow 8 '(frac 1 6))))) (should (< (abs (- x (sqrt 2.0))) 1.0e-10)))) +(require 'calc-aent) + +(ert-deftest calc-math-read-preprocess-string () + "Test replacement of allowed special Unicode symbols." + ;; ... doesn't change an empty string + (should (string= "" (math-read-preprocess-string ""))) + ;; ... doesn't change a string without characters from + ;; ‘math-read-replacement-list’ + (let ((str "don't replace here")) + (should (string= str (math-read-preprocess-string str)))) + ;; ... replaces irrespective of position in input string + (should (string= "^(1)" (math-read-preprocess-string "¹"))) + (should (string= "some^(1)" (math-read-preprocess-string "some¹"))) + (should (string= "^(1)time" (math-read-preprocess-string "¹time"))) + (should (string= "some^(1)else" (math-read-preprocess-string "some¹else"))) + ;; ... replaces every element of ‘math-read-replacement-list’ correctly, + ;; in particular combining consecutive super-/subscripts into one + ;; exponent/subscript + (should (string= (concat "+/-*:-/*inf<=>=<=>=μ(1:4)(1:2)(3:4)(1:3)(2:3)" + "(1:5)(2:5)(3:5)(4:5)(1:6)(5:6)" + "(1:8)(3:8)(5:8)(7:8)1:^(0123456789+-()ni)" + "_(0123456789+-())") + (math-read-preprocess-string + (mapconcat #'car math-read-replacement-list)))) + ;; ... replaces strings of more than a single character correctly + (let ((math-read-replacement-list (append + math-read-replacement-list + '(("𝚤𝚥" "ij")) + '(("¼½" "(1:4)(1:2)"))))) + (should (string= "(1:4)(1:2)ij" + (math-read-preprocess-string "¼½𝚤𝚥")))) + ;; ... handles an empty replacement list gracefully + (let ((math-read-replacement-list '())) + (should (string= "¼" (math-read-preprocess-string "¼")))) + ;; ... signals an error if the argument is not a string + (should-error (math-read-preprocess-string nil)) + (should-error (math-read-preprocess-string 42))) + (provide 'calc-tests) ;;; calc-tests.el ends here commit ade814a2268285475675872760e3c358ec24a130 Author: Mattias Engdegård Date: Tue Dec 19 17:07:24 2023 +0100 ; * lisp/progmodes/rust-ts-mode.el: Escape asterisks in regexp. diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el index ac860969daf..b4609509798 100644 --- a/lisp/progmodes/rust-ts-mode.el +++ b/lisp/progmodes/rust-ts-mode.el @@ -298,7 +298,8 @@ rust-ts-mode--comment-docstring (let* ((beg (treesit-node-start node)) (face (save-excursion (goto-char beg) - (if (looking-at "/\\(?:/\\(?:/[^/]\\|!\\)\\|*\\(?:*[^*/]\\|!\\)\\)" t) + (if (looking-at-p + "/\\(?:/\\(?:/[^/]\\|!\\)\\|\\*\\(?:\\*[^*/]\\|!\\)\\)") 'font-lock-doc-face 'font-lock-comment-face)))) (treesit-fontify-with-override beg (treesit-node-end node) commit 281be72422f42fcc84d43f50723a3e91b7d03cbc Author: Eli Zaretskii Date: Tue Dec 19 14:20:24 2023 +0200 ; * src/eval.c (syms_of_eval) : Doc fix. diff --git a/src/eval.c b/src/eval.c index 419285eb694..5c9052cb9ab 100644 --- a/src/eval.c +++ b/src/eval.c @@ -4347,14 +4347,14 @@ syms_of_eval (void) DEFSYM (Qdebugger, "debugger"); DEFVAR_LISP ("debugger", Vdebugger, doc: /* Function to call to invoke debugger. -If due to frame exit, args are `exit' and the value being returned; +If due to frame exit, arguments are `exit' and the value being returned; this function's value will be returned instead of that. -If due to error, args are `error' and a list of the args to `signal'. -If due to `apply' or `funcall' entry, one arg, `lambda'. -If due to `eval' entry, one arg, t. +If due to error, arguments are `error' and a list of arguments to `signal'. +If due to `apply' or `funcall' entry, one argument, `lambda'. +If due to `eval' entry, one argument, t. IF the desired entry point of the debugger is higher in the call stack, -it can can be specified with the keyword argument `:backtrace-base' -whose format should be the same as the BASE arg of `backtrace-frame'. */); +it can be specified with the keyword argument `:backtrace-base', whose +format should be the same as the BASE argument of `backtrace-frame'. */); Vdebugger = Qdebug_early; DEFVAR_LISP ("signal-hook-function", Vsignal_hook_function, commit c0c79b0b4602d7c3505c41e08596386f725c2afd Author: João Távora Date: Tue Dec 19 04:06:45 2023 -0600 Fido-mode: don't error if case-fold-search is globally nil bug#67884 To prevent errors, the same case-fold-search setting used for originally selecting the candidate should be used when scoring it. * lisp/minibuffer.el (completion--flex-score): Fix diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 1af890968d0..905ccacb2a7 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -4059,15 +4059,16 @@ completion--flex-score-last-md (defun completion--flex-score (str re &optional dont-error) "Compute flex score of completion STR based on RE. If DONT-ERROR, just return nil if RE doesn't match STR." - (cond ((string-match re str) - (let* ((match-end (match-end 0)) - (md (cddr - (setq - completion--flex-score-last-md - (match-data t completion--flex-score-last-md))))) - (completion--flex-score-1 md match-end (length str)))) - ((not dont-error) - (error "Internal error: %s does not match %s" re str)))) + (let ((case-fold-search completion-ignore-case)) + (cond ((string-match re str) + (let* ((match-end (match-end 0)) + (md (cddr + (setq + completion--flex-score-last-md + (match-data t completion--flex-score-last-md))))) + (completion--flex-score-1 md match-end (length str)))) + ((not dont-error) + (error "Internal error: %s does not match %s" re str))))) (defvar completion-pcm--regexp nil "Regexp from PCM pattern in `completion-pcm--hilit-commonality'.") commit 0a57e1cd2c97db3a990f88043dc4a53619390228 Author: Po Lu Date: Tue Dec 19 16:42:38 2023 +0800 Improve efficiency of operations involving font interpreter scale * src/sfnt.c (sfnt_mul_f26dot6_fixed): Correct rounding constant. (sfnt_make_interpreter, SSW, WCVTF, sfnt_compute_phantom_points) (sfnt_interpret_simple_glyph, sfnt_interpret_compound_glyph_1) (sfnt_vary_interpreter, sfnt_check_ssw): Account for the fractional bits in a f26dot6 when computing the interpreter scale factor. diff --git a/src/sfnt.c b/src/sfnt.c index c33f21215a6..eb3add7390e 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -6456,7 +6456,8 @@ sfnt_mul_f26dot6_fixed (sfnt_f26dot6 x, sfnt_fixed y) product = (uint64_t) y * (uint64_t) x; /* This can be done quickly with int64_t. */ - return ((int64_t) (product + 32676) / (int64_t) 65536) * sign; + return ((int64_t) (product + 32768) + / (int64_t) 65536) * sign; #else struct sfnt_large_integer temp; int sign; @@ -6685,7 +6686,7 @@ sfnt_make_interpreter (struct sfnt_maxp_table *maxp, /* Now compute the scale. Then, scale up the control value table values. */ interpreter->scale - = sfnt_div_fixed (pixel_size, head->units_per_em); + = sfnt_div_fixed (pixel_size * 64, head->units_per_em); /* Set the PPEM. */ interpreter->ppem = pixel_size; @@ -6701,7 +6702,7 @@ sfnt_make_interpreter (struct sfnt_maxp_table *maxp, /* Load the control value table. */ for (i = 0; i < interpreter->cvt_size; ++i) interpreter->cvt[i] - = sfnt_mul_f26dot6_fixed (cvt->values[i] * 64, + = sfnt_mul_f26dot6_fixed (cvt->values[i], interpreter->scale); /* Fill in the default values for phase, period and threshold. */ @@ -7016,8 +7017,8 @@ #define SSW() \ single_width = POP (); \ \ interpreter->state.single_width_value \ - = (interpreter->scale * single_width \ - / 1024); \ + = sfnt_mul_fixed (single_width, \ + interpreter->scale); \ } #define DUP() \ @@ -7545,8 +7546,8 @@ #define WCVTF() \ TRAP ("WCVTF out of bounds"); \ \ interpreter->cvt[location] \ - = (interpreter->scale * value \ - / 1024); \ + = sfnt_mul_fixed (value, \ + interpreter->scale); \ } #define JROT() \ @@ -12258,8 +12259,8 @@ sfnt_compute_phantom_points (struct sfnt_glyph *glyph, f2 += glyph->advance_distortion; /* Next, scale both up. */ - *s1 = sfnt_mul_f26dot6_fixed (f1 * 64, scale); - *s2 = sfnt_mul_f26dot6_fixed (f2 * 64, scale); + *s1 = sfnt_mul_f26dot6_fixed (f1, scale); + *s2 = sfnt_mul_f26dot6_fixed (f2, scale); /* While not expressly provided in the manual, the phantom points (at times termed the advance and origin points) represent pixel @@ -12343,7 +12344,7 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph, tem = glyph->simple->x_coordinates[i]; /* Scale that fword. */ - tem = sfnt_mul_f26dot6_fixed (tem * 64, interpreter->scale); + tem = sfnt_mul_f26dot6_fixed (tem, interpreter->scale); /* Set x_points and x_current. */ zone->x_points[i] = tem; @@ -12371,7 +12372,7 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph, /* Scale that fword. Make sure not to round Y, as this could lead to Y spilling over to the next line. */ - tem = sfnt_mul_fixed (tem * 64, interpreter->scale); + tem = sfnt_mul_f26dot6_fixed (tem, interpreter->scale); /* Set y_points and y_current. */ zone->y_points[i] = tem; @@ -12824,14 +12825,14 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph, if (!(component->flags & 01)) /* ARG_1_AND_2_ARE_WORDS */ { /* X and Y are signed bytes. */ - x = component->argument1.b * 64; - y = component->argument2.b * 64; + x = component->argument1.b; + y = component->argument2.b; } else { /* X and Y are signed words. */ - x = component->argument1.d * 64; - y = component->argument2.d * 64; + x = component->argument1.d; + y = component->argument2.d; } /* Now convert X and Y into device coordinates. */ @@ -16335,7 +16336,7 @@ sfnt_vary_interpreter (struct sfnt_interpreter *interpreter, /* Multiply the delta by the interpreter scale factor and then the tuple scale factor. */ - delta = sfnt_mul_f26dot6_fixed (variation->deltas[j] * 64, + delta = sfnt_mul_f26dot6_fixed (variation->deltas[j], interpreter->scale); delta = sfnt_mul_fixed_round (delta, scale); @@ -17352,13 +17353,13 @@ sfnt_check_ssw (struct sfnt_interpreter *interpreter, } if (interpreter->state.single_width_value - != sfnt_mul_f26dot6_fixed (-64, interpreter->scale)) + != sfnt_mul_f26dot6_fixed (-1, interpreter->scale)) { fprintf (stderr, "failed, got %d at scale %d," " expected %d\n", interpreter->state.single_width_value, interpreter->scale, - sfnt_mul_f26dot6_fixed (-64, interpreter->scale)); + sfnt_mul_f26dot6_fixed (-1, interpreter->scale)); return; } @@ -20532,8 +20533,8 @@ main (int argc, char **argv) return 1; } -#define FANCY_PPEM 14 -#define EASY_PPEM 14 +#define FANCY_PPEM 12 +#define EASY_PPEM 12 interpreter = NULL; head = sfnt_read_head_table (fd, font); commit d0e3dfa764cdb5c15c2a525b455df495097a86bb Author: Po Lu Date: Tue Dec 19 14:39:28 2023 +0800 Properly sign-extend freedom and projection vector values * src/sfnt.c (GPV, GFV): Cast versors to int32_t. diff --git a/src/sfnt.c b/src/sfnt.c index 1b4cdf38bd0..c33f21215a6 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -8080,8 +8080,8 @@ #define GPV() \ vector \ = interpreter->state.projection_vector; \ \ - PUSH ((uint16_t) vector.x); \ - PUSH ((uint16_t) vector.y); \ + PUSH ((int32_t) vector.x); \ + PUSH ((int32_t) vector.y); \ } #define GFV() \ @@ -8091,8 +8091,8 @@ #define GFV() \ vector \ = interpreter->state.freedom_vector; \ \ - PUSH ((uint16_t) vector.x); \ - PUSH ((uint16_t) vector.y); \ + PUSH ((int32_t) vector.x); \ + PUSH ((int32_t) vector.y); \ } #define SFVTPV() \ commit f2693751dd20caa790aa8f0216d50499653f61d4 Author: Po Lu Date: Tue Dec 19 13:41:16 2023 +0800 Further corrections to font scaling * src/sfnt.c (sfnt_dot_fix_14): Correct typo in final division. (sfnt_compute_phantom_points): New parameters S1 and S2, into which unrounded phantom point coordinates are saved. (sfnt_interpret_simple_glyph, sfnt_interpret_compound_glyph_2) (sfnt_interpret_compound_glyph_1): Adjust correspondingly. * src/sfntfont.c (sfntfont_get_glyph_outline): Delete redundant branch. diff --git a/src/sfnt.c b/src/sfnt.c index 131b4fd409c..1b4cdf38bd0 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -10499,7 +10499,7 @@ sfnt_dot_fix_14 (int32_t ax, int32_t ay, int bx, int by) yy = xx >> 63; xx += 0x2000 + yy; - return (int32_t) (xx / (2 << 14)); + return (int32_t) (xx / (1 << 14)); #endif } @@ -12227,17 +12227,20 @@ sfnt_build_instructed_outline (struct sfnt_instructed_outline *instructed) scale SCALE. Place the X and Y coordinates of the first phantom point in *X1 and - *Y1, and those of the second phantom point in *X2 and *Y2. */ + *Y1, and those of the second phantom point in *X2 and *Y2. + + Place the unrounded X coordinates of both phantom points in *S1 and + *S2 respectively. */ static void sfnt_compute_phantom_points (struct sfnt_glyph *glyph, struct sfnt_glyph_metrics *metrics, sfnt_fixed scale, sfnt_f26dot6 *x1, sfnt_f26dot6 *y1, - sfnt_f26dot6 *x2, sfnt_f26dot6 *y2) + sfnt_f26dot6 *x2, sfnt_f26dot6 *y2, + sfnt_f26dot6 *s1, sfnt_f26dot6 *s2) { sfnt_fword f1, f2; - sfnt_fixed s1, s2; /* Two ``phantom points'' are appended to each outline by the scaler prior to instruction interpretation. One of these points @@ -12255,14 +12258,14 @@ sfnt_compute_phantom_points (struct sfnt_glyph *glyph, f2 += glyph->advance_distortion; /* Next, scale both up. */ - s1 = sfnt_mul_f26dot6_fixed (f1 * 64, scale); - s2 = sfnt_mul_f26dot6_fixed (f2 * 64, scale); + *s1 = sfnt_mul_f26dot6_fixed (f1 * 64, scale); + *s2 = sfnt_mul_f26dot6_fixed (f2 * 64, scale); /* While not expressly provided in the manual, the phantom points (at times termed the advance and origin points) represent pixel coordinates within the raster, and are therefore rounded. */ - *x1 = sfnt_round_f26dot6 (s1); - *x2 = sfnt_round_f26dot6 (s2); + *x1 = sfnt_round_f26dot6 (*s1); + *x2 = sfnt_round_f26dot6 (*s2); /* Clear y1 and y2. */ *y1 = 0; @@ -12285,9 +12288,7 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph, size_t zone_size, temp, outline_size, i; struct sfnt_interpreter_zone *zone; struct sfnt_interpreter_zone *volatile preserved_zone; - sfnt_f26dot6 phantom_point_1_x; sfnt_f26dot6 phantom_point_1_y; - sfnt_f26dot6 phantom_point_2_x; sfnt_f26dot6 phantom_point_2_y; sfnt_f26dot6 tem; volatile bool zone_was_allocated; @@ -12349,16 +12350,18 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph, zone->x_current[i] = tem; } - /* Compute phantom points. */ + /* Compute and load phantom points. */ sfnt_compute_phantom_points (glyph, metrics, interpreter->scale, - &phantom_point_1_x, &phantom_point_1_y, - &phantom_point_2_x, &phantom_point_2_y); - - /* Load phantom points. */ - zone->x_points[i] = phantom_point_1_x; - zone->x_points[i + 1] = phantom_point_2_x; - zone->x_current[i] = phantom_point_1_x; - zone->x_current[i + 1] = phantom_point_2_x; + &zone->x_current[i], &phantom_point_1_y, + &zone->x_current[i + 1], &phantom_point_2_y, + /* Phantom points are rounded to the + pixel grid once they are inserted + into the glyph zone, but the + original coordinates must remain + untouched, as fonts rely on this to + interpolate points by this + scale. */ + &zone->x_points[i], &zone->x_points[i + 1]); /* Load y_points and y_current, along with flags. */ for (i = 0; i < glyph->simple->number_of_points; ++i) @@ -12553,6 +12556,11 @@ sfnt_transform_f26dot6 (struct sfnt_compound_glyph_component *component, In addition, CONTEXT also contains two additional ``phantom points'' supplying the left and right side bearings of GLYPH. + S1 and S2 are the unrounded values of the last two phantom points, + which supply the original values saved into the glyph zone. In + practical terms, they are set as the last two values of the glyph + zone's original position array. + Value is NULL upon success, or a description of the error upon failure. */ @@ -12561,7 +12569,8 @@ sfnt_interpret_compound_glyph_2 (struct sfnt_glyph *glyph, struct sfnt_interpreter *interpreter, struct sfnt_compound_glyph_context *context, size_t base_index, size_t base_contour, - struct sfnt_glyph_metrics *metrics) + struct sfnt_glyph_metrics *metrics, + sfnt_f26dot6 s1, sfnt_f26dot6 s2) { size_t num_points, num_contours, i; size_t zone_size, temp; @@ -12651,6 +12660,11 @@ sfnt_interpret_compound_glyph_2 (struct sfnt_glyph *glyph, & ~SFNT_POINT_TOUCHED_BOTH); } + /* Copy S1 and S2 into the glyph zone. */ + assert (num_points >= 2); + zone->x_points[num_points - 1] = s2; + zone->x_points[num_points - 2] = s1; + /* Load the compound glyph program. */ interpreter->IP = 0; interpreter->SP = interpreter->stack; @@ -12756,6 +12770,8 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph, sfnt_f26dot6 phantom_point_1_y; sfnt_f26dot6 phantom_point_2_x; sfnt_f26dot6 phantom_point_2_y; + sfnt_f26dot6 phantom_point_1_s; + sfnt_f26dot6 phantom_point_2_s; error = NULL; @@ -13096,7 +13112,8 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph, /* Compute phantom points. */ sfnt_compute_phantom_points (glyph, metrics, interpreter->scale, &phantom_point_1_x, &phantom_point_1_y, - &phantom_point_2_x, &phantom_point_2_y); + &phantom_point_2_x, &phantom_point_2_y, + &phantom_point_1_s, &phantom_point_2_s); /* Grow various arrays to include those points. */ rc = sfnt_expand_compound_glyph_context (context, @@ -13123,7 +13140,9 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph, error = sfnt_interpret_compound_glyph_2 (glyph, interpreter, context, base_index, base_contour, - metrics); + metrics, + phantom_point_1_s, + phantom_point_2_s); } return error; diff --git a/src/sfntfont.c b/src/sfntfont.c index 0a8797bfb3b..cecdbeafb8d 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -2290,22 +2290,12 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, } if (!outline) - { - if (!interpreter) - outline = sfnt_build_glyph_outline (glyph, scale, - &temp, - sfntfont_get_glyph, - sfntfont_free_glyph, - sfntfont_get_metrics, - &dcontext); - else - outline = sfnt_build_glyph_outline (glyph, scale, - &temp, - sfntfont_get_glyph, - sfntfont_free_glyph, - sfntfont_get_metrics, - &dcontext); - } + outline = sfnt_build_glyph_outline (glyph, scale, + &temp, + sfntfont_get_glyph, + sfntfont_free_glyph, + sfntfont_get_metrics, + &dcontext); /* At this point, the glyph metrics are unscaled. Scale them up. If INTERPRETER is set, use the scale placed within. */ commit 20e39a12e491ce82ee581b6d99a4e2770218e0c6 Author: João Távora Date: Mon Dec 18 17:59:29 2023 -0600 ; Small copyedits to doc/misc/eglot.texi Motivated in part by bug#67870 and bug#67609. * doc/misc/eglot.texi (Quick Start): Reword (Eglot Features): Reword. (Eglot Commands): Fix typo. diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi index 5243a6530dc..eda93d84aff 100644 --- a/doc/misc/eglot.texi +++ b/doc/misc/eglot.texi @@ -138,11 +138,10 @@ Quick Start To start using Eglot for a project, type @kbd{M-x eglot @key{RET}} in a buffer visiting any file that belongs to the project. This starts the language server configured for the programming language of that -buffer, and causes Eglot to start managing all the files of the -project which use the same programming language. This includes files -of a given project that are already visited at the time the -@code{eglot} command is invoked as well as files visited after this -invocation. +buffer, and causes Eglot to start @dfn{managing} file-visiting buffers +related to that programming language. This includes files that are +already visited at the time the @code{eglot} command is invoked, as +well as any files visited after this invocation. The notion of a ``project'' used by Eglot is the same Emacs uses (@pxref{Projects,,, emacs, GNU Emacs Manual}): in the simplest case, @@ -405,11 +404,13 @@ Eglot Features @section Eglot Features @cindex features in buffers supported by Eglot -Once Eglot is enabled in a buffer, it uses LSP and the language-server -capabilities to activate, enable, and enhance modern IDE features in -Emacs. The features themselves are usually provided via other Emacs -packages. Here's the list of the main features that Eglot enables and -provides: +While Eglot is enabled in a buffer, it is said to be @dfn{managing} +it, using LSP and the specific capabilities of the language server to +activate and enhance modern IDE features in Emacs. Some of these +features are provided via other Emacs packages, and some via Eglot +directly (@pxref{Eglot Commands}). + +Here's an overview of the main features that Eglot provides: @itemize @bullet @item @@ -422,10 +423,11 @@ Eglot Features the program identifiers. @item -On-the-fly diagnostic annotations with server-suggested fixes, via the -Flymake package (@pxref{Top,,, flymake, GNU Flymake manual}). This -improves and enhances the Flymake diagnostics, replacing the other -Flymake backends. +On-the-fly diagnostic annotations, via the Flymake package +(@pxref{Top,,, flymake, GNU Flymake manual}). Eglot's Flymake backend +replaces other Flymake backends while it is managing a buffer, and +enhances diagnostics with interactive server-suggested fixes +(so-called @dfn{code actions}, @pxref{Eglot Commands}) @item Finding definitions and uses of identifiers, via Xref (@pxref{Xref,,, @@ -484,9 +486,17 @@ Eglot Features Not all servers support the full set of LSP capabilities, but most of them support enough to enable the basic set of features mentioned -above. Conversely, some servers offer capabilities for which no -equivalent Emacs package exists yet, and so Eglot cannot (yet) expose -these capabilities to Emacs users. +above. + +Conversely, some servers offer capabilities for which no equivalent +Emacs package exists yet, and so Eglot cannot (yet) expose these +capabilities to Emacs users. However, @xref{Extending Eglot}. + +Finally, it's worth noting that, by default, Eglot generally turns on +all features that it @emph{can} turn on. It's possible to opt out of +some features via user options (@pxref{Customizing Eglot}) and a hook +that runs after Eglot starts managing a buffer (@pxref{Eglot and +Buffers}). @node Eglot and Buffers @section Buffers, Projects, and Eglot @@ -694,7 +704,7 @@ Eglot Commands correcting, refactoring or beautifying your code. These commands may affect more than one visited file belonging to the project. -The command @code{eglot-code-actions} asks the server if there any +The command @code{eglot-code-actions} asks the server if there are any code actions for any point in the buffer or contained in the active region. If there are, you have the choice to execute one of them via the minibuffer. commit 6937182a0e7735e83377c757ae13292692b0cb85 Author: Stefan Monnier Date: Mon Dec 18 17:42:37 2023 -0500 debug.el: Straighten the code that find the "base" of the backtrace Let the caller tell us clearly where is the base of the backtrace, if it's not `debug`. This is done by passing a new `:backtrace-base` keyword argument to `debug`. Then use this info systematically in all the places where we access the real C-level backtrace, to try and avoid inconsistencies and brittle code that tries to enumerate the expected frames we're in. * src/eval.c (get_backtrace_starting_at): Add support for offsets in the `base` argument. (Fbacktrace_debug): Add optional `base` argument. * lisp/emacs-lisp/debug.el (debug, debugger-frame, debugger-frame-clear): Use `debugger--backtrace-base` when calling `backtrace-debug`. (debugger-setup-buffer): Use `debugger--backtrace-base` when calling `backtrace-get-frames`. (debugger-frame-number): Drop `skip-base` arg, assume it's never nil. Add sanity check. (debugger--backtrace-base): Use the `:backtrace-base` info in `debugger-args`. (debugger-eval-expression): Adjust call to `debugger-frame-number`. (debug--implement-debug-on-entry): Pass appropriate `:backtrace-base`. diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el index 5411088189d..e0b6ca31b9e 100644 --- a/lisp/emacs-lisp/debug.el +++ b/lisp/emacs-lisp/debug.el @@ -237,12 +237,11 @@ debug (unwind-protect (save-excursion (when (eq (car debugger-args) 'debug) - ;; Skip the frames for backtrace-debug, byte-code, - ;; debug--implement-debug-on-entry and the advice's `apply'. - (backtrace-debug 4 t) - ;; Place an extra debug-on-exit for macro's. - (when (eq 'lambda (car-safe (cadr (backtrace-frame 4)))) - (backtrace-debug 5 t))) + (let ((base (debugger--backtrace-base))) + (backtrace-debug 1 t base) ;FIXME! + ;; Place an extra debug-on-exit for macro's. + (when (eq 'lambda (car-safe (cadr (backtrace-frame 1 base)))) + (backtrace-debug 2 t base)))) (with-current-buffer debugger-buffer (unless (derived-mode-p 'debugger-mode) (debugger-mode)) @@ -343,11 +342,10 @@ debugger-insert-backtrace (defun debugger-setup-buffer (args) "Initialize the `*Backtrace*' buffer for entry to the debugger. That buffer should be current already and in `debugger-mode'." - (setq backtrace-frames (nthcdr - ;; Remove debug--implement-debug-on-entry and the - ;; advice's `apply' frame. - (if (eq (car args) 'debug) 3 1) - (backtrace-get-frames 'debug))) + (setq backtrace-frames + ;; The `base' frame is the one that gets index 0 and it is the entry to + ;; the debugger, so drop it with `cdr'. + (cdr (backtrace-get-frames (debugger--backtrace-base)))) (when (eq (car-safe args) 'exit) (setq debugger-value (nth 1 args)) (setf (cl-getf (backtrace-frame-flags (car backtrace-frames)) @@ -477,26 +475,29 @@ debugger-reenable (setq debugger-jumping-flag nil) (remove-hook 'post-command-hook 'debugger-reenable)) -(defun debugger-frame-number (&optional skip-base) +(defun debugger-frame-number () "Return number of frames in backtrace before the one point points at." - (let ((index (backtrace-get-index)) - (count 0)) + (let ((index (backtrace-get-index))) (unless index (error "This line is not a function call")) - (unless skip-base - (while (not (eq (cadr (backtrace-frame count)) 'debug)) - (setq count (1+ count))) - ;; Skip debug--implement-debug-on-entry frame. - (when (eq 'debug--implement-debug-on-entry - (cadr (backtrace-frame (1+ count)))) - (setq count (+ 2 count)))) - (+ count index))) + ;; We have 3 representations of the backtrace: the real in C in `specpdl', + ;; the one stored in `backtrace-frames' and the textual version in + ;; the buffer. Check here that the one from `backtrace-frames' is in sync + ;; with the one from `specpdl'. + (cl-assert (equal (backtrace-frame-fun (nth index backtrace-frames)) + (nth 1 (backtrace-frame (1+ index) + (debugger--backtrace-base))))) + ;; The `base' frame is the one that gets index 0 and it is the entry to + ;; the debugger, so the first non-debugger frame is 1. + ;; This `+1' skips the same frame as the `cdr' in + ;; `debugger-setup-buffer'. + (1+ index))) (defun debugger-frame () "Request entry to debugger when this frame exits. Applies to the frame whose line point is on in the backtrace." (interactive) - (backtrace-debug (debugger-frame-number) t) + (backtrace-debug (debugger-frame-number) t (debugger--backtrace-base)) (setf (cl-getf (backtrace-frame-flags (nth (backtrace-get-index) backtrace-frames)) :debug-on-exit) @@ -507,7 +508,7 @@ debugger-frame-clear "Do not enter debugger when this frame exits. Applies to the frame whose line point is on in the backtrace." (interactive) - (backtrace-debug (debugger-frame-number) nil) + (backtrace-debug (debugger-frame-number) nil (debugger--backtrace-base)) (setf (cl-getf (backtrace-frame-flags (nth (backtrace-get-index) backtrace-frames)) :debug-on-exit) @@ -526,10 +527,8 @@ debugger-env-macro (defun debugger--backtrace-base () "Return the function name that marks the top of the backtrace. See `backtrace-frame'." - (cond ((eq 'debug--implement-debug-on-entry - (cadr (backtrace-frame 1 'debug))) - 'debug--implement-debug-on-entry) - (t 'debug))) + (or (cadr (memq :backtrace-base debugger-args)) + #'debug)) (defun debugger-eval-expression (exp &optional nframe) "Eval an expression, in an environment like that outside the debugger. @@ -537,7 +536,7 @@ debugger-eval-expression (interactive (list (read--expression "Eval in stack frame: "))) (let ((nframe (or nframe - (condition-case nil (1+ (debugger-frame-number 'skip-base)) + (condition-case nil (debugger-frame-number) (error 0)))) ;; If on first line. (base (debugger--backtrace-base))) (debugger-env-macro @@ -670,7 +669,10 @@ debug--implement-debug-on-entry (if (or inhibit-debug-on-entry debugger-jumping-flag) nil (let ((inhibit-debug-on-entry t)) - (funcall debugger 'debug)))) + (funcall debugger 'debug :backtrace-base + ;; An offset of 1 because we need to skip the advice + ;; OClosure that called us. + '(1 . debug--implement-debug-on-entry))))) ;;;###autoload (defun debug-on-entry (function) diff --git a/lisp/subr.el b/lisp/subr.el index 7b52f4f68f9..93428c4a518 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -6384,13 +6384,14 @@ backtrace-frames nearest activation frame are discarded." (let ((frames nil)) (mapbacktrace (lambda (&rest frame) (push frame frames)) - (or base 'backtrace-frames)) + (or base #'backtrace-frames)) (nreverse frames))) (defun backtrace-frame (nframes &optional base) "Return the function and arguments NFRAMES up from current execution point. If non-nil, BASE should be a function, and NFRAMES counts from its -nearest activation frame. +nearest activation frame. BASE can also be of the form (OFFSET . FUNCTION) +in which case OFFSET will be added to NFRAMES. If the frame has not evaluated the arguments yet (or is a special form), the value is (nil FUNCTION ARG-FORMS...). If the frame has evaluated its arguments and called its function already, @@ -6401,7 +6402,7 @@ backtrace-frame If NFRAMES is more than the number of frames, the value is nil." (backtrace-frame--internal (lambda (evald func args _) `(,evald ,func ,@args)) - nframes (or base 'backtrace-frame))) + nframes (or base #'backtrace-frame))) (defvar called-interactively-p-functions nil diff --git a/src/eval.c b/src/eval.c index 12e811ce264..419285eb694 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3806,10 +3806,18 @@ get_backtrace_starting_at (Lisp_Object base) if (!NILP (base)) { /* Skip up to `base'. */ + int offset = 0; + if (CONSP (base) && FIXNUMP (XCAR (base))) + { + offset = XFIXNUM (XCAR (base)); + base = XCDR (base); + } base = Findirect_function (base, Qt); while (backtrace_p (pdl) && !EQ (base, Findirect_function (backtrace_function (pdl), Qt))) pdl = backtrace_next (pdl); + while (backtrace_p (pdl) && offset-- > 0) + pdl = backtrace_next (pdl); } return pdl; @@ -3849,13 +3857,14 @@ backtrace_frame_apply (Lisp_Object function, union specbinding *pdl) } } -DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0, +DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 3, 0, doc: /* Set the debug-on-exit flag of eval frame LEVEL levels down to FLAG. +LEVEL and BASE specify the activation frame to use, as in `backtrace-frame'. The debugger is entered when that frame exits, if the flag is non-nil. */) - (Lisp_Object level, Lisp_Object flag) + (Lisp_Object level, Lisp_Object flag, Lisp_Object base) { CHECK_FIXNUM (level); - union specbinding *pdl = get_backtrace_frame(level, Qnil); + union specbinding *pdl = get_backtrace_frame (level, base); if (backtrace_p (pdl)) set_backtrace_debug_on_exit (pdl, !NILP (flag)); @@ -4342,7 +4351,10 @@ syms_of_eval (void) this function's value will be returned instead of that. If due to error, args are `error' and a list of the args to `signal'. If due to `apply' or `funcall' entry, one arg, `lambda'. -If due to `eval' entry, one arg, t. */); +If due to `eval' entry, one arg, t. +IF the desired entry point of the debugger is higher in the call stack, +it can can be specified with the keyword argument `:backtrace-base' +whose format should be the same as the BASE arg of `backtrace-frame'. */); Vdebugger = Qdebug_early; DEFVAR_LISP ("signal-hook-function", Vsignal_hook_function, commit 1d5d2f16c330e98a42c94fbea3728802f7535918 Author: Po Lu Date: Mon Dec 18 22:14:22 2023 +0800 Further fixes for problems uncovered by the previous fix * src/sfnt.c (sfnt_deltap): Enable deltap instructions again, since they now serve a purpose. (sfnt_compute_phantom_points): Round phantom points to match the behavior of other TrueType scalers. diff --git a/src/sfnt.c b/src/sfnt.c index f67857c1893..131b4fd409c 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -6829,7 +6829,7 @@ #define LOOK() \ ? (TRAP ("stack underflow"), 0) \ : *(interpreter->SP - 1)) -#if !defined TEST || !0 +#if !defined TEST #define PUSH(value) \ { \ @@ -6847,7 +6847,7 @@ #define PUSH_UNCHECKED(value) \ interpreter->SP++; \ } -#else /* TEST && 0 */ +#else /* TEST */ #define PUSH(value) \ { \ @@ -9799,12 +9799,10 @@ sfnt_interpret_mdap (struct sfnt_interpreter *interpreter, static void sfnt_deltap (int number, struct sfnt_interpreter *interpreter, - unsigned char operand, unsigned int index) + unsigned char operand, unsigned int p) { int ppem, delta; - return; - /* Extract the ppem from OPERAND. The format is the same as in sfnt_deltac. */ @@ -9908,8 +9906,8 @@ sfnt_deltap (int number, struct sfnt_interpreter *interpreter, delta *= 1l << (6 - interpreter->state.delta_shift); /* Move the point. */ - sfnt_check_zp0 (interpreter, index); - sfnt_move_zp0 (interpreter, index, 1, delta); + sfnt_check_zp0 (interpreter, p); + sfnt_move_zp0 (interpreter, p, 1, delta); } /* Needed by sfnt_interpret_call. */ @@ -12239,6 +12237,7 @@ sfnt_compute_phantom_points (struct sfnt_glyph *glyph, sfnt_f26dot6 *x2, sfnt_f26dot6 *y2) { sfnt_fword f1, f2; + sfnt_fixed s1, s2; /* Two ``phantom points'' are appended to each outline by the scaler prior to instruction interpretation. One of these points @@ -12256,8 +12255,14 @@ sfnt_compute_phantom_points (struct sfnt_glyph *glyph, f2 += glyph->advance_distortion; /* Next, scale both up. */ - *x1 = sfnt_mul_f26dot6_fixed (f1 * 64, scale); - *x2 = sfnt_mul_f26dot6_fixed (f2 * 64, scale); + s1 = sfnt_mul_f26dot6_fixed (f1 * 64, scale); + s2 = sfnt_mul_f26dot6_fixed (f2 * 64, scale); + + /* While not expressly provided in the manual, the phantom points + (at times termed the advance and origin points) represent pixel + coordinates within the raster, and are therefore rounded. */ + *x1 = sfnt_round_f26dot6 (s1); + *x2 = sfnt_round_f26dot6 (s2); /* Clear y1 and y2. */ *y1 = 0; commit 1abba7bfa4518923109ae95055ca268909f0ae98 Author: Po Lu Date: Mon Dec 18 20:58:53 2023 +0800 ; * src/sfnt.c: Fix typo. diff --git a/src/sfnt.c b/src/sfnt.c index 4d8d3d4b72f..f67857c1893 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -4983,7 +4983,7 @@ sfnt_fedge_sort (struct sfnt_fedge *edges, size_t size) guarantee that no steps generated extend past WIDTH, steps starting after width might be omitted, and as such it must be accurate. */ -TEST_STATIC void +static void sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges, size_t height, size_t width, sfnt_step_raster_proc proc, void *dcontext) commit a54bec26c44b44bd10936bbeb93b1018c7270a23 Author: Po Lu Date: Mon Dec 18 20:57:24 2023 +0800 * src/sfnt.c (sfnt_interpret_mdap): Correct MDAP opcode. diff --git a/src/sfnt.c b/src/sfnt.c index 8bc37c1b978..4d8d3d4b72f 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -9756,7 +9756,7 @@ sfnt_deltac (int number, struct sfnt_interpreter *interpreter, Touch the point P (within the zone specified in zp0) in the directions specified in the freedom vector. Then, if OPCODE is - 0x7f, round the point and move it the rounded distance along the + 0x2f, round the point and move it the rounded distance along the freedom vector. Finally, set the RP0 and RP1 registers to P. */ @@ -9772,7 +9772,7 @@ sfnt_interpret_mdap (struct sfnt_interpreter *interpreter, /* Measure the current distance. */ here = sfnt_project_vector (interpreter, px, py); - if (opcode == 0x7f) + if (opcode == 0x2f) { /* Measure distance, round, then move to the distance. */ distance = sfnt_project_vector (interpreter, px, py); @@ -20508,8 +20508,8 @@ main (int argc, char **argv) return 1; } -#define FANCY_PPEM 12 -#define EASY_PPEM 12 +#define FANCY_PPEM 14 +#define EASY_PPEM 14 interpreter = NULL; head = sfnt_read_head_table (fd, font);