* Android Startup:: Starting up Emacs on Android.
* Android File System:: The Android file system.
* Android Environment:: Running Emacs under Android.
+* Android Fonts:: Font selection under Android.
@end menu
@node What is Android?
Otherwise, Emacs can only run in the background for a limited amount
of time before the process is killed completely.
-@c TODO: write more documentation here about what is supported and
-@c what is not, and fonts.
+@cindex windowing limitations, android
+@cindex frame parameters, android
+Due to the unusual nature of the Android windowing environment, Emacs
+only supports a limited subset of GUI features. Here is a list of
+known limitations, and features which are not implemented:
+
+@itemize @bullet
+@item
+The functions @code{raise-frame} and @code{lower-frame} are
+non-functional, because of bugs in the window system.
+
+@item
+Scroll bars are not supported, as they are close to useless on Android
+devices.
+
+@item
+The @code{alpha}, @code{alpha-background}, @code{z-group},
+@code{override-redirect}, @code{mouse-color}, @code{cursor-color},
+@code{cursor-type}, @code{title}, @code{wait-for-wm}, @code{sticky},
+@code{undecorated} and @code{tool-bar-position} frame parameters
+(@pxref{Frame Parameters,,, elisp, the Emacs Lisp Reference Manual})
+are unsupported.
+
+@item
+The @code{fullscreen} frame parameter is always @code{maximized} for
+top-level frames.
+@end itemize
+
+@node Android Fonts
+@section Font backends and selection under Android
+@cindex fonts, android
+
+ Emacs supports two font backends under Android: they are respectively
+named @code{sfnt-android} and @code{android}.
+
+Upon startup, Emacs enumerates all the TrueType format fonts in the
+directory @file{/system/fonts}; this is where the Android system
+places fonts. Emacs assumes there will always be a font named ``Droid
+Sans Mono'', and then defaults to using this font. These fonts are
+then rendered by the @code{sfnt-android} font driver.
+
+When running on Android, Emacs currently lacks support for TrueType
+Container and OpenType fonts. This means that only a subset of the
+fonts installed on the system are currently available to Emacs. If
+you are interested in raising this limitation, please contact
+@email{emacs-devel@@gnu.org}.
+
+If the @code{sfnt-android} font driver fails to find any fonts at all,
+Emacs falls back to the @code{android} font driver. This is a very
+lousy font driver, because of limitations and inaccuracies in the font
+metrics provided by the Android platform. In that case, Emacs uses
+the ``Monospace'' typeface configured on your system; this should
+always be Droid Sans Mono.
raised the finger from the touchscreen.
@end table
+If a touchpoint is pressed against the menu bar, then Emacs will not
+generate any corresponding @code{touchscreen-begin} or
+@code{touchscreen-end} events; instead, the menu bar may be displayed
+when @code{touchscreen-end} should have been delivered.
+
@node Focus Events
@subsection Focus Events
@cindex focus event
The kind of window system the terminal uses---either @code{graphic}
(any graphics-capable display), @code{x}, @code{pc} (for the MS-DOS
console), @code{w32} (for MS Windows 9X/NT/2K/XP), @code{haiku} (for
-Haiku), @code{pgtk} (for pure GTK), or @code{tty} (a non-graphics-capable
-display). @xref{Window Systems, window-system}.
+Haiku), @code{pgtk} (for pure GTK), @code{android} (for Android), or
+@code{tty} (a non-graphics-capable display). @xref{Window Systems,
+window-system}.
@item class
What kinds of colors the terminal supports---either @code{color},
Emacs is displaying the frame using the Application Kit on Haiku.
@item pgtk
Emacs is displaying the frame using pure GTK facilities.
+@item android
+Emacs is displaying the frame on Android.
@item nil
Emacs is displaying the frame on a character-based terminal.
@end table
indicate that position for the various builds:
@itemize @w{}
-@item (1) non-toolkit, Haiku, and terminal frames
+@item (1) non-toolkit, Android, Haiku, and terminal frames
@item (2) Lucid, Motif, and MS-Windows frames
HarfBuzz text shaping) (@pxref{Windows Fonts,,, emacs, The GNU Emacs
Manual}). The @code{harfbuzz} driver is similarly recommended. On
Haiku, there can be several font drivers (@pxref{Haiku Fonts,,, emacs,
+The GNU Emacs Manual}), as on Android (@pxref{Android Fonts,,, emacs,
The GNU Emacs Manual}).
On other systems, there is only one available font backend, so it does
@item nacl
Google Native Client (@acronym{NaCl}) sandboxing system.
+@item android
+The Open Handset Alliance's Android operating system.
+
@item ms-dos
Microsoft's DOS@. Emacs compiled with DJGPP for MS-DOS binds
@code{system-type} to @code{ms-dos} even when you run it on MS-Windows.
pointerIndex = event.getActionIndex ();
pointerID = event.getPointerId (pointerIndex);
pointerMap.put (pointerID,
- new Coordinate ((int) event.getX (pointerID),
- (int) event.getY (pointerID)));
+ new Coordinate ((int) event.getX (pointerIndex),
+ (int) event.getY (pointerIndex)));
break;
case MotionEvent.ACTION_POINTER_UP:
(if (featurep 'dynamic-setting)
(load "dynamic-setting"))
+;; touch-screen.el is tiny and is used liberally throughout the button
+;; code etc, so it may as well be preloaded everywhere.
+(load "touch-screen")
+
(if (featurep 'x)
(progn
(load "x-dnd")
(set-window-start nil (pixel-point-at-unseen-line) t)
(set-window-vscroll nil vscroll t))
+;;;###autoload
(defun pixel-scroll-precision-scroll-down-page (delta)
"Scroll the current window down by DELTA pixels.
Note that this function doesn't work if DELTA is larger than
(setq delta (- delta max-height)))
(pixel-scroll-precision-scroll-down-page delta)))
+;;;###autoload
(defun pixel-scroll-precision-scroll-up-page (delta)
"Scroll the current window up by DELTA pixels.
Note that this function doesn't work if DELTA is larger than
(require 'mouse)
(require 'fontset)
(require 'dnd)
+(require 'touch-screen)
(add-to-list 'display-format-alist '(".*" . android))
--- /dev/null
+;;; touch-screen.el --- touch screen support for X and Android -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+;; Package: emacs
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file provides code to recognize simple touch screen gestures.
+;; It is used on X and Android, where the platform cannot recognize
+;; them for us.
+
+;;; Code:
+
+(defvar touch-screen-current-tool nil
+ "The touch point currently being tracked, or nil.
+If non-nil, this is a list of five elements: the ID of the touch
+point being tracked, the window where the touch began, a cons
+containing the last known position of the touch point, relative
+to that window, a field used to store data while tracking the
+touch point, and the initial position of the touchpoint. See
+`touch-screen-handle-point-update' for the meanings of the fourth
+element.")
+
+(defvar touch-screen-current-timer nil
+ "Timer used to track long-presses.
+This is always cleared upon any significant state change.")
+
+(defcustom touch-screen-delay 0.7
+ "Delay in seconds before Emacs considers a touch to be a long-press."
+ :type 'number
+ :group 'mouse
+ :version "30.1")
+
+(defun touch-screen-relative-xy (posn window)
+ "Return the coordinates of POSN, a mouse position list.
+However, return the coordinates relative to WINDOW.
+
+If (posn-window posn) is the same as window, simply return the
+coordinates in POSN. Otherwise, convert them to the frame, and
+then back again."
+ (if (eq (posn-window posn) window)
+ (posn-x-y posn)
+ (let ((xy (posn-x-y posn))
+ (edges (window-inside-pixel-edges window)))
+ ;; Make the X and Y positions frame relative.
+ (when (windowp (posn-window posn))
+ (let ((edges (window-inside-pixel-edges
+ (posn-window posn))))
+ (setq xy (cons (+ (car xy) (car edges))
+ (+ (cdr xy) (cadr edges))))))
+ ;; Make the X and Y positions window relative again.
+ (cons (- (car xy) (car edges))
+ (- (cdr xy) (cadr edges))))))
+
+(defun touch-screen-handle-scroll (dx dy)
+ "Scroll the display assuming that a touch point has moved by DX and DY."
+ (ignore dx)
+ ;; This only looks good with precision pixel scrolling.
+ (if (> dy 0)
+ (pixel-scroll-precision-scroll-down-page dy)
+ (pixel-scroll-precision-scroll-up-page (- dy))))
+
+(defun touch-screen-handle-timeout (arg)
+ "Start the touch screen timeout or handle it depending on ARG.
+When ARG is nil, start the `touch-screen-current-timer' to go off
+in `touch-screen-delay' seconds, and call this function with ARG
+t.
+
+When ARG is t, beep. Then, set the fourth element of
+touch-screen-current-tool to `held', and the mark to the last
+known position of the tool."
+ (if (not arg)
+ ;; Cancel the touch screen long-press timer, if it is still
+ ;; there by any chance.
+ (progn
+ (when touch-screen-current-timer
+ (cancel-timer touch-screen-current-timer))
+ (setq touch-screen-current-timer
+ (run-at-time touch-screen-delay nil
+ #'touch-screen-handle-timeout
+ t)))
+ ;; Beep.
+ (beep)
+ ;; Set touch-screen-current-timer to nil.
+ (setq touch-screen-current-timer nil)
+ (when touch-screen-current-tool
+ ;; Set the state to `held'.
+ (setcar (nthcdr 3 touch-screen-current-tool) 'held)
+ ;; Go to the initial position of the touchpoint and activate the
+ ;; mark.
+ (with-selected-window (cadr touch-screen-current-tool)
+ (set-mark (posn-point (nth 4 touch-screen-current-tool)))
+ (goto-char (mark))
+ (activate-mark)))))
+
+(defun touch-screen-handle-point-update (point)
+ "Notice that the touch point POINT has changed position.
+POINT must be the touch point currently being tracked as
+`touch-screen-current-tool'.
+
+If the fourth element of `touch-screen-current-tool' is nil, then
+the touch has just begun. Determine how much POINT has moved.
+If POINT has moved upwards or downwards by a significant amount,
+then set the fourth element to `scroll'. Then, call
+`touch-screen-handle-scroll' to scroll the display by that
+amount.
+
+If the fourth element of `touch-screen-current-tool' is `scroll',
+then scroll the display by how much POINT has moved in the Y
+axis.
+
+If the fourth element of `touch-screen-current-tool' is `held',
+then the touch has been held down for some time. If motion
+happens, cancel `touch-screen-current-timer', and set the field
+to `drag'. Then, activate the mark and start dragging.
+
+If the fourth element of `touch-screen-current-tool' is `drag',
+then move point to the position of POINT.
+
+Set `touch-screen-current-tool' to nil should any error occur."
+ (let ((window (nth 1 touch-screen-current-tool))
+ (what (nth 3 touch-screen-current-tool)))
+ (cond ((null what)
+ (let* ((posn (cdr point))
+ (last-posn (nth 2 touch-screen-current-tool))
+ ;; Now get the position of X and Y relative to
+ ;; WINDOW.
+ (relative-xy
+ (touch-screen-relative-xy posn window))
+ (diff-x (- (car last-posn) (car relative-xy)))
+ (diff-y (- (cdr last-posn) (cdr relative-xy))))
+ ;; Decide whether or not to start scrolling.
+ (when (or (> diff-y 10) (> diff-x 10)
+ (< diff-y -10) (< diff-x -10))
+ (setcar (nthcdr 3 touch-screen-current-tool)
+ 'scroll)
+ (setcar (nthcdr 2 touch-screen-current-tool)
+ relative-xy)
+ (with-selected-window window
+ (touch-screen-handle-scroll diff-x diff-y))
+ ;; Cancel the touch screen long-press timer, if it is
+ ;; still there by any chance.
+ (when touch-screen-current-timer
+ (cancel-timer touch-screen-current-timer)
+ (setq touch-screen-current-timer nil)))))
+ ((eq what 'scroll)
+ ;; Cancel the touch screen long-press timer, if it is still
+ ;; there by any chance.
+ (when touch-screen-current-timer
+ (cancel-timer touch-screen-current-timer)
+ (setq touch-screen-current-timer nil))
+ (let* ((posn (cdr point))
+ (last-posn (nth 2 touch-screen-current-tool))
+ ;; Now get the position of X and Y relative to
+ ;; WINDOW.
+ (relative-xy
+ (touch-screen-relative-xy posn window))
+ (diff-x (- (car last-posn) (car relative-xy)))
+ (diff-y (- (cdr last-posn) (cdr relative-xy))))
+ (setcar (nthcdr 3 touch-screen-current-tool)
+ 'scroll)
+ (setcar (nthcdr 2 touch-screen-current-tool)
+ relative-xy)
+ (unless (and (zerop diff-x) (zerop diff-y))
+ (with-selected-window window
+ (touch-screen-handle-scroll diff-x diff-y)))))
+ ((eq what 'held)
+ (let* ((posn (cdr point))
+ (relative-xy
+ (touch-screen-relative-xy posn window)))
+ (when touch-screen-current-timer
+ (cancel-timer touch-screen-current-timer)
+ (setq touch-screen-current-timer nil))
+ ;; Now start dragging.
+ (setcar (nthcdr 3 touch-screen-current-tool)
+ 'drag)
+ (setcar (nthcdr 2 touch-screen-current-tool)
+ relative-xy)
+ (with-selected-window window
+ ;; Activate the mark. It should have been set by the
+ ;; time `touch-screen-timeout' was called.
+ (activate-mark)
+
+ ;; Figure out what character to go to. If this posn is
+ ;; in the window, go to (posn-point posn). If not,
+ ;; then go to the line before either window start or
+ ;; window end.
+ (if (and (eq (posn-window posn) window)
+ (posn-point posn))
+ (goto-char (posn-point posn))
+ (let ((relative-xy
+ (touch-screen-relative-xy posn window)))
+ (let ((scroll-conservatively 101))
+ (cond
+ ((< (cdr relative-xy) 0)
+ (ignore-errors
+ (goto-char (1- (window-start))))
+ (redisplay))
+ ((> (cdr relative-xy)
+ (let ((edges (window-inside-pixel-edges)))
+ (- (nth 3 edges) (cadr edges))))
+ (ignore-errors
+ (goto-char (1+ (window-end nil t))))
+ (redisplay)))))))))
+ ((eq what 'drag)
+ (let* ((posn (cdr point)))
+ ;; Keep dragging.
+ (with-selected-window window
+ ;; Figure out what character to go to. If this posn is
+ ;; in the window, go to (posn-point posn). If not,
+ ;; then go to the line before either window start or
+ ;; window end.
+ (if (and (eq (posn-window posn) window)
+ (posn-point posn))
+ (goto-char (posn-point posn))
+ (let ((relative-xy
+ (touch-screen-relative-xy posn window)))
+ (let ((scroll-conservatively 101))
+ (cond
+ ((< (cdr relative-xy) 0)
+ (ignore-errors
+ (goto-char (1- (window-start))))
+ (redisplay))
+ ((> (cdr relative-xy)
+ (let ((edges (window-inside-pixel-edges)))
+ (- (nth 3 edges) (cadr edges))))
+ (ignore-errors
+ (goto-char (1+ (window-end nil t))))
+ (redisplay))))))))))))
+
+(defun touch-screen-handle-point-up (point)
+ "Notice that POINT has been removed from the screen.
+POINT should be the point currently tracked as
+`touch-screen-current-tool'.
+
+If the fourth argument of `touch-screen-current-tool' is nil,
+move point to the position of POINT, selecting the window under
+POINT as well; if there is a button at POINT, then activate the
+button there. Otherwise, deactivate the mark. Then, display the
+on-screen keyboard."
+ (let ((what (nth 3 touch-screen-current-tool)))
+ (cond ((null what)
+ (when (windowp (posn-window (cdr point)))
+ ;; Select the window that was tapped.
+ (select-window (posn-window (cdr point)))
+ (let ((button (button-at (posn-point (cdr point)))))
+ (when button
+ (button-activate button t))
+ (goto-char (posn-point (cdr point)))
+ (deactivate-mark)))))))
+
+(defun touch-screen-handle-touch (event)
+ "Handle a single touch EVENT, and perform associated actions.
+EVENT can either be a touchscreen-begin, touchscreen-update or
+touchscreen-end event."
+ (interactive "e")
+ (cond
+ ((eq (car event) 'touchscreen-begin)
+ ;; A tool was just pressed against the screen. Figure out the
+ ;; window where it is and make it the tool being tracked on the
+ ;; window.
+ (let ((touchpoint (caadr event))
+ (position (cdadr event)))
+ ;; Cancel the touch screen timer, if it is still there by any
+ ;; chance.
+ (when touch-screen-current-timer
+ (cancel-timer touch-screen-current-timer)
+ (setq touch-screen-current-timer nil))
+ ;; Replace any previously ongoing gesture. If POSITION has no
+ ;; window or position, make it nil instead.
+ (setq touch-screen-current-tool (and (windowp (posn-window position))
+ (posn-point position)
+ (list touchpoint
+ (posn-window position)
+ (posn-x-y position)
+ nil position)))
+ ;; Start the long-press timer.
+ (touch-screen-handle-timeout nil)))
+ ((eq (car event) 'touchscreen-update)
+ ;; The positions of tools currently pressed against the screen
+ ;; have changed. If there is a tool being tracked as part of a
+ ;; gesture, look it up in the list of tools.
+ (let ((new-point (assq (car touch-screen-current-tool)
+ (cadr event))))
+ (when new-point
+ (touch-screen-handle-point-update new-point))))
+ ((eq (car event) 'touchscreen-end)
+ ;; A tool has been removed from the screen. If it is the tool
+ ;; currently being tracked, clear `touch-screen-current-tool'.
+ (when (eq (caadr event) (car touch-screen-current-tool))
+ ;; Cancel the touch screen long-press timer, if it is still there
+ ;; by any chance.
+ (when touch-screen-current-timer
+ (cancel-timer touch-screen-current-timer)
+ (setq touch-screen-current-timer nil))
+ (touch-screen-handle-point-up (cadr event))
+ (setq touch-screen-current-tool nil)))))
+
+(define-key global-map [touchscreen-begin] #'touch-screen-handle-touch)
+(define-key global-map [touchscreen-update] #'touch-screen-handle-touch)
+(define-key global-map [touchscreen-end] #'touch-screen-handle-touch)
+
+(provide 'touch-screen)
+
+;;; touch-screen ends here
#include <signal.h>
#include <semaphore.h>
#include <dlfcn.h>
+#include <errno.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/param.h>
#include <assert.h>
char *line;
size_t n;
- fd = (int) data;
+ fd = (int) (intptr_t) data;
file = fdopen (fd, "r");
if (!file)
close (pipefd[1]);
if (pthread_create (&thread, NULL, android_run_debug_thread,
- (void *) pipefd[0]))
+ (void *) (intptr_t) pipefd[0]))
emacs_abort ();
/* Now set the path to the site load directory. */
{
char *byte, *word;
unsigned int r, g, b;
+ unsigned int pixel_int;
/* Ignore out-of-bounds accesses. */
b = pixel & 0x000000ff;
pixel = (r >> 16) | g | (b << 16) | 0xff000000;
- memcpy (word, &pixel, sizeof pixel);
+ pixel_int = pixel;
+ memcpy (word, &pixel_int, sizeof pixel_int);
break;
}
}
}
}
+\f
+
+/* Native image transforms. */
+
+/* Transform the coordinates X and Y by the specified affine
+ transformation MATRIX. Place the result in *XOUT and *YOUT. */
+
+static void
+android_transform_coordinates (int x, int y,
+ struct android_transform *transform,
+ float *xout, float *yout)
+{
+ /* Apply the specified affine transformation.
+ A transform looks like:
+
+ M1 M2 M3 X
+ M4 M5 M6 * Y
+
+ =
+
+ M1*X + M2*Y + M3*1 = X1
+ M4*X + M5*Y + M6*1 = Y1
+
+ (In most transforms, there is another row at the bottom for
+ mathematical reasons. Since Z1 is always 1.0, the row is simply
+ implied to be 0 0 1, because 0 * x + 0 * y + 1 * 1 = 1.0. See
+ the definition of matrix3x3 in image.c for some more explanations
+ about this.) */
+
+ *xout = transform->m1 * x + transform->m2 * y + transform->m3;
+ *yout = transform->m4 * x + transform->m5 * y + transform->m6;
+}
+
+/* Return the interpolation of the four pixels TL, TR, BL, and BR,
+ according to the weights DISTX and DISTY. */
+
+static unsigned int
+android_four_corners_bilinear (unsigned int tl, unsigned int tr,
+ unsigned int bl, unsigned int br,
+ int distx, int disty)
+{
+ int distxy, distxiy, distixy, distixiy;
+ uint32_t f, r;
+
+ distxy = distx * disty;
+ distxiy = (distx << 8) - distxy;
+ distixy = (disty << 8) - distxy;
+ distixiy = (256 * 256 - (disty << 8)
+ - (distx << 8) + distxy);
+
+ /* Red */
+ r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
+ + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
+
+ /* Green */
+ f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
+ + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
+ r |= f & 0xff000000;
+
+ /* Now do the upper two components. */
+ tl >>= 16;
+ tr >>= 16;
+ bl >>= 16;
+ br >>= 16;
+ r >>= 16;
+
+ /* Blue */
+ f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
+ + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
+ r |= f & 0x00ff0000;
+
+ /* Alpha */
+ f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
+ + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
+ r |= f & 0xff000000;
+
+ return r;
+}
+
+/* Return the interpolation of the four pixels closest to at X, Y in
+ IMAGE, according to weights in both axes computed from X and Y.
+ IMAGE must be depth 24, or the behavior is undefined. */
+
+static unsigned int
+android_fetch_pixel_bilinear (struct android_image *image,
+ float x, float y)
+{
+ int x1, y1, x2, y2;
+ float distx, disty;
+ unsigned int top_left, top_right;
+ unsigned int bottom_left, bottom_right;
+ char *word;
+
+ /* Compute the four closest corners to X and Y. */
+ x1 = (int) x;
+ x2 = x1 + 1;
+ y1 = (int) y;
+ y2 = y1 + 1;
+
+ /* Make sure all four corners are within range. */
+ x1 = MAX (0, MIN (image->width - 1, x1));
+ y1 = MAX (0, MIN (image->height - 1, y1));
+ x2 = MAX (0, MIN (image->width - 1, x2));
+ y2 = MAX (0, MIN (image->height - 1, y2));
+
+ /* Compute the X and Y biases. These are numbers between 0f and
+ 1f. */
+ distx = x - x1;
+ disty = y - y1;
+
+ /* Fetch the four closest pixels. */
+ word = image->data + y1 * image->bytes_per_line + x1 * 4;
+ memcpy (&top_left, word, sizeof top_left);
+ word = image->data + y1 * image->bytes_per_line + x2 * 4;
+ memcpy (&top_right, word, sizeof top_right);
+ word = image->data + y2 * image->bytes_per_line + x1 * 4;
+ memcpy (&bottom_left, word, sizeof bottom_left);
+ word = image->data + y2 * image->bytes_per_line + x2 * 4;
+ memcpy (&bottom_right, word, sizeof bottom_right);
+
+ /* Do the interpolation. */
+ return android_four_corners_bilinear (top_left, top_right, bottom_left,
+ bottom_right, distx * 256,
+ disty * 256);
+}
+
+/* Transform the depth 24 image IMAGE by the 3x2 affine transformation
+ matrix MATRIX utilizing a bilinear filter. Place the result in
+ OUT. The matrix maps from the coordinate space of OUT to
+ IMAGE. */
+
+void
+android_project_image_bilinear (struct android_image *image,
+ struct android_image *out,
+ struct android_transform *transform)
+{
+ int x, y;
+ unsigned int pixel;
+ float xout, yout;
+ char *word;
+
+ /* Loop through each pixel in OUT. Transform it by TRANSFORM, then
+ interpolate it to IMAGE, and place the result back in OUT. */
+
+ for (y = 0; y < out->height; ++y)
+ {
+ for (x = 0; x < out->width; ++x)
+ {
+ /* Transform the coordinates by TRANSFORM. */
+ android_transform_coordinates (x, y, transform,
+ &xout, &yout);
+
+ /* Interpolate back to IMAGE. */
+ pixel = android_fetch_pixel_bilinear (image, xout, yout);
+
+ /* Put the pixel back in OUT. */
+ word = out->data + y * out->bytes_per_line + x * 4;
+ memcpy (word, &pixel, sizeof pixel);
+ }
+ }
+}
+
+/* Return the interpolation of X, Y to IMAGE, a depth 24 image. */
+
+static unsigned int
+android_fetch_pixel_nearest_24 (struct android_image *image, float x,
+ float y)
+{
+ int x1, y1;
+ char *word;
+ unsigned int pixel;
+
+ x1 = MAX (0, MIN (image->width - 1, (int) roundf (x)));
+ y1 = MAX (0, MIN (image->height - 1, (int) roundf (y)));
+
+ word = image->data + y1 * image->bytes_per_line + x1 * 4;
+ memcpy (&pixel, word, sizeof pixel);
+
+ return pixel;
+}
+
+/* Return the interpolation of X, Y to IMAGE, a depth 1 image. */
+
+static unsigned int
+android_fetch_pixel_nearest_1 (struct android_image *image, float x,
+ float y)
+{
+ int x1, y1;
+ char *byte;
+
+ x1 = MAX (0, MIN (image->width - 1, (int) roundf (x)));
+ y1 = MAX (0, MIN (image->height - 1, (int) roundf (y)));
+
+ byte = image->data + y1 * image->bytes_per_line;
+ return (byte[x1 / 8] & (1 << x1 % 8)) ? 1 : 0;
+}
+
+/* Transform the depth 24 or 1 image IMAGE by the 3x2 affine
+ transformation matrix MATRIX. Place the result in OUT. The matrix
+ maps from the coordinate space of OUT to IMAGE. Use a
+ nearest-neighbor filter. */
+
+void
+android_project_image_nearest (struct android_image *image,
+ struct android_image *out,
+ struct android_transform *transform)
+{
+ int x, y;
+ unsigned int pixel;
+ float xout, yout;
+ char *word, *byte;
+
+ if (image->depth == 1)
+ {
+ for (y = 0; y < out->height; ++y)
+ {
+ for (x = 0; x < out->width; ++x)
+ {
+ /* Transform the coordinates by TRANSFORM. */
+ android_transform_coordinates (x, y, transform,
+ &xout, &yout);
+
+ /* Interpolate back to IMAGE. */
+ pixel = android_fetch_pixel_nearest_1 (image, xout, yout);
+
+ /* Put the pixel back in OUT. */
+ byte = out->data + y * out->bytes_per_line + x / 8;
+
+ if (pixel)
+ *byte |= (1 << x % 8);
+ else
+ *byte &= ~(1 << x % 8);
+ }
+ }
+
+ return;
+ }
+
+ for (y = 0; y < out->height; ++y)
+ {
+ for (x = 0; x < out->width; ++x)
+ {
+ /* Transform the coordinates by TRANSFORM. */
+ android_transform_coordinates (x, y, transform,
+ &xout, &yout);
+
+ /* Interpolate back to IMAGE. */
+ pixel = android_fetch_pixel_nearest_24 (image, xout, yout);
+
+ /* Put the pixel back in OUT. */
+ word = out->data + y * out->bytes_per_line + x * 4;
+ memcpy (word, &pixel, sizeof pixel);
+ }
+ }
+}
+
#else /* ANDROID_STUBIFY */
/* X emulation functions for Android. */
emacs_abort ();
}
+void
+android_project_image_bilinear (struct android_image *image,
+ struct android_image *out,
+ struct android_transform *transform)
+{
+ emacs_abort ();
+}
+
+void
+android_project_image_nearest (struct android_image *image,
+ struct android_image *out,
+ struct android_transform *transform)
+{
+ emacs_abort ();
+}
+
#endif
enum android_image_format);
extern void android_put_image (android_pixmap, struct android_image *);
+
+/* Native image transforms. */
+
+/* 3x2 matrix describing a projective transform. See
+ android_transform_coordinates for details. */
+
+struct android_transform
+{
+ float m1, m2, m3;
+ float m4, m5, m6;
+};
+
+extern void android_project_image_bilinear (struct android_image *,
+ struct android_image *,
+ struct android_transform *);
+extern void android_project_image_nearest (struct android_image *,
+ struct android_image *,
+ struct android_transform *);
+
\f
/* X emulation stuff also needed while building stubs. */
|| event->y < r->y || event->y >= r->y + r->height)
{
frame->mouse_moved = true;
- /* TODO
- dpyinfo->last_mouse_scroll_bar = NULL; */
note_mouse_highlight (frame, event->x, event->y);
/* Remember which glyph we're now on. */
remember_mouse_glyph (frame, event->x, event->y, r);
s->background_filled_p = true;
}
+static void
+android_get_scale_factor (int *scale_x, int *scale_y)
+{
+ /* This is 96 everywhere else, but 160 on Android. */
+ const int base_res = 160;
+ struct android_display_info *dpyinfo;
+
+ dpyinfo = x_display_list;
+ *scale_x = *scale_y = 1;
+
+ if (dpyinfo)
+ {
+ if (dpyinfo->resx > base_res)
+ *scale_x = floor (dpyinfo->resx / base_res);
+ if (dpyinfo->resy > base_res)
+ *scale_y = floor (dpyinfo->resy / base_res);
+ }
+}
+
static void
android_draw_underwave (struct glyph_string *s, int decoration_width)
{
- int wave_height = 3, wave_length = 2;
+ int scale_x, scale_y;
+
+ android_get_scale_factor (&scale_x, &scale_y);
+
+ int wave_height = 3 * scale_y, wave_length = 2 * scale_x;
+
int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
bool odd;
struct android_rectangle wave_clip, string_clip, final_clip;
#ifdef HAVE_WINDOW_SYSTEM
-# if (defined USE_CAIRO || defined HAVE_XRENDER \
- || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU)
+# if (defined USE_CAIRO || defined HAVE_XRENDER \
+ || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU \
+ || defined HAVE_ANDROID)
# define HAVE_NATIVE_TRANSFORMS
# endif
finally move the origin back to the top left of the image, which
may now be a different corner.
- Note that different GUI backends (X, Cairo, w32, NS, Haiku) want
- the transform matrix defined as transform from the original image
- to the transformed image, while others want the matrix to describe
- the transform of the space, which boils down to inverting the
- matrix.
+ Note that different GUI backends (X, Cairo, w32, NS, Haiku,
+ Android) want the transform matrix defined as transform from the
+ original image to the transformed image, while others want the
+ matrix to describe the transform of the space, which boils down to
+ inverting the matrix.
It's possible to pre-calculate the matrix multiplications and just
generate one transform matrix that will do everything we need in a
*rotation = XFIXNUM (reduced_angle);
}
+#ifdef HAVE_ANDROID
+
+static void
+matrix_identity (matrix3x3 matrix)
+{
+ memset (matrix, 0, sizeof (matrix3x3));
+
+ matrix[0][0] = 1.0;
+ matrix[1][1] = 1.0;
+ matrix[2][2] = 1.0;
+}
+
+/* Translate the matrix TRANSFORM to X, Y, and then perform clockwise
+ rotation by the given angle THETA in radians and translate back.
+ As the transform is being performed in a coordinate system where Y
+ grows downwards, the given angle describes a clockwise
+ rotation. */
+
+static void
+matrix_rotate (matrix3x3 transform, double theta, double x, double y)
+{
+ matrix3x3 temp, copy;
+
+ /* 1. Translate the matrix so X and Y are in the center. */
+
+ matrix_identity (temp);
+ memcpy (copy, transform, sizeof copy);
+
+ temp[0][2] = x;
+ temp[1][2] = y;
+
+ matrix3x3_mult (copy, temp, transform);
+ matrix_identity (temp);
+ memcpy (copy, transform, sizeof copy);
+
+ /* 2. Rotate the matrix counter-clockwise, assuming a coordinate
+ system where Y grows downwards. */
+
+ temp[0][0] = cos (theta);
+ temp[0][1] = -sin (theta);
+ temp[1][0] = sinf (theta);
+ temp[1][1] = cosf (theta);
+
+ matrix3x3_mult (copy, temp, transform);
+ matrix_identity (temp);
+ memcpy (copy, transform, sizeof copy);
+
+ /* 3. Translate back. */
+
+ temp[0][2] = -x;
+ temp[1][2] = -y;
+
+ matrix3x3_mult (copy, temp, transform);
+}
+
+/* Scale the matrix TRANSFORM by -1, and then apply a TX of width, in
+ effect flipping the image horizontally. */
+
+static void
+matrix_mirror_horizontal (matrix3x3 transform, double width)
+{
+ matrix3x3 temp, copy;
+
+ matrix_identity (temp);
+ memcpy (copy, transform, sizeof copy);
+
+ temp[0][0] = -1.0f;
+ temp[0][2] = width;
+
+ matrix3x3_mult (copy, temp, transform);
+}
+
+static void
+matrix_translate (matrix3x3 transform, float tx, float ty)
+{
+ matrix3x3 temp, copy;
+
+ matrix_identity (temp);
+ memcpy (copy, transform, sizeof copy);
+
+ /* Set the tx and ty. */
+ temp[0][2] = tx;
+ temp[1][2] = ty;
+
+ /* Multiply it with the transform. */
+ matrix3x3_mult (copy, temp, transform);
+}
+
+#endif
+
static void
image_set_transform (struct frame *f, struct image *img)
{
memcpy (&img->transform, identity, sizeof identity);
#endif
+#if defined HAVE_ANDROID
+ matrix3x3 identity = {
+ { 1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, 0, 1 },
+ };
+#endif
+
# if (defined HAVE_IMAGEMAGICK \
&& !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE)
/* ImageMagick images already have the correct transform. */
/* Determine flipping. */
flip = !NILP (image_spec_value (img->spec, QCflip, NULL));
-# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU
+# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU \
+ || defined HAVE_ANDROID
/* We want scale up operations to use a nearest neighbor filter to
show real pixels instead of munging them, but scale down
operations to use a blended filter, to avoid aliasing and the like.
matrix3x3 matrix
= {
-# if defined USE_CAIRO || defined HAVE_XRENDER
+# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_ANDROID
[0][0] = (!IEEE_FLOATING_POINT && width == 0 ? DBL_MAX
: img->width / (double) width),
[1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX
/* Haiku needs this, since the transformation is done on the basis
of the view, and not the image. */
-#ifdef HAVE_HAIKU
+#if defined HAVE_HAIKU
int extra_tx, extra_ty;
extra_tx = 0;
rotate_flag = 0;
else
{
-# if (defined USE_CAIRO || defined HAVE_XRENDER \
- || defined HAVE_NTGUI || defined HAVE_NS \
+#ifndef HAVE_ANDROID
+# if (defined USE_CAIRO || defined HAVE_XRENDER \
+ || defined HAVE_NTGUI || defined HAVE_NS \
|| defined HAVE_HAIKU)
int cos_r, sin_r;
if (rotation == 0)
sin_r = 1;
rotate_flag = 1;
-#ifdef HAVE_HAIKU
+#if defined HAVE_HAIKU
if (!flip)
extra_ty = height;
extra_tx = 0;
if (0 < rotate_flag)
{
-# if defined USE_CAIRO || defined HAVE_XRENDER
+# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_ANDROID
/* 1. Translate so (0, 0) is in the center of the image. */
matrix3x3 t
= { [0][0] = 1,
img->height = height;
}
# endif
+#else
+ /* Calculate the inverse transform from the destination to the
+ source. The matrix is currently identity with scale
+ applied.
+
+ This code makes more sense to me than what lies above. But
+ I'm not touching what works. */
+
+ if (rotation != 0 && rotation != 90
+ && rotation != 180 && rotation != 270)
+ {
+ rotate_flag = 0;
+ goto bail;
+ }
+
+ rotate_flag = 1;
+
+ switch ((int) rotation + (flip ? 1 : 0))
+ {
+ case 0:
+ break;
+
+ case 90:
+ /* Rotate the image 90 degrees clockwise. IOW, rotate the
+ destination by 90 degrees counterclockwise, which is 270
+ degrees clockwise. */
+ matrix_rotate (matrix, M_PI * 1.5, 0, 0);
+ matrix_translate (matrix, -height, 0);
+ break;
+
+ case 180:
+ /* Apply clockwise 180 degree rotation around the
+ center. */
+ matrix_rotate (matrix, M_PI, width / 2.0, height / 2.0);
+ break;
+
+ case 270:
+ /* Apply 270 degree counterclockwise rotation to the
+ destination, which is 90 degrees clockwise. */
+ matrix_rotate (matrix, M_PI * 0.5, 0, 0);
+ matrix_translate (matrix, 0, -width);
+ break;
+
+ case 1:
+ /* Flipped. Apply horizontal flip. */
+ matrix_mirror_horizontal (matrix, width);
+ break;
+
+ case 91:
+ /* Apply a flip but otherwise treat this the same as 90. */
+ matrix_rotate (matrix, M_PI * 1.5, 0, 0);
+ matrix_translate (matrix, -height, 0);
+ matrix_mirror_horizontal (matrix, height);
+ break;
+
+ case 181:
+ /* Flipped 180 degrees. Apply a flip and treat this the
+ same as 180. */
+ matrix_rotate (matrix, M_PI, width / 2.0, height / 2.0);
+ matrix_mirror_horizontal (matrix, width);
+ break;
+
+ case 271:
+ /* Flipped 270 degrees. Apply a flip and treat this the
+ same as 270. */
+ matrix_rotate (matrix, M_PI * 0.5, 0, 0);
+ matrix_translate (matrix, 0, -width);
+ matrix_mirror_horizontal (matrix, height);
+ break;
+ }
+
+ /* Now set img->width and img->height. Flip them if the
+ rotation being applied requires so. */
+
+ if (rotation != 270 && rotation != 90)
+ {
+ img->width = width;
+ img->height = height;
+ }
+ else
+ {
+ img->height = width;
+ img->width = height;
+ }
+ bail:
+ ;
+#endif
}
if (rotate_flag < 0)
img->transform[0][2] = extra_tx;
img->transform[1][2] = extra_ty;
}
+# elif defined HAVE_ANDROID
+ /* Create a new image of the right size, then turn it into a pixmap
+ and set that as img->pixmap. Destroy img->mask for now (this is
+ not right.) */
+
+ struct android_image *transformed_image, *image;
+ struct android_transform transform;
+
+ /* If there is no transform, simply return. */
+ if (!memcmp (&matrix, &identity, sizeof matrix))
+ return;
+
+ /* First, get the source image. */
+ image = image_get_x_image (f, img, false);
+
+ /* Make the transformed image. */
+ transformed_image = android_create_image (image->depth,
+ ANDROID_Z_PIXMAP,
+ NULL, img->width,
+ img->height);
+
+ /* Allocate memory for that image. */
+ transformed_image->data
+ = xmalloc (transformed_image->bytes_per_line
+ * transformed_image->height);
+
+ /* Do the transform. */
+ transform.m1 = matrix[0][0];
+ transform.m2 = matrix[0][1];
+ transform.m3 = matrix[0][2];
+ transform.m4 = matrix[1][0];
+ transform.m5 = matrix[1][1];
+ transform.m6 = matrix[1][2];
+
+ if (image->depth == 24 && smoothing)
+ android_project_image_bilinear (image, transformed_image,
+ &transform);
+ else
+ android_project_image_nearest (image, transformed_image,
+ &transform);
+
+ image_unget_x_image (img, false, image);
+
+ /* Now replace the image. */
+
+ if (img->ximg)
+ image_destroy_x_image (img->ximg);
+
+ img->ximg = transformed_image;
+
+#ifndef ANDROID_STUBIFY
+ /* Then replace the pixmap. */
+ android_free_pixmap (img->pixmap);
+
+ /* In case android_create_pixmap signals. */
+ img->pixmap = ANDROID_NONE;
+ img->pixmap = android_create_pixmap (img->width, img->height,
+ transformed_image->depth);
+ android_put_image (img->pixmap, transformed_image);
+#else
+ emacs_abort ();
+#endif
+
+ /* Now, transform the mask. The mask should be depth 1, and is
+ always transformed using a nearest neighbor filter. */
+
+ if (img->mask_img || img->mask)
+ {
+ image = image_get_x_image (f, img, true);
+ transformed_image = android_create_image (1, ANDROID_Z_PIXMAP,
+ NULL, img->width,
+ img->height);
+ transformed_image->data
+ = xmalloc (transformed_image->bytes_per_line
+ * transformed_image->height);
+ android_project_image_nearest (image, transformed_image,
+ &transform);
+ image_unget_x_image (img, false, image);
+
+ /* Now replace the image. */
+
+ if (img->mask_img)
+ image_destroy_x_image (img->mask_img);
+
+ img->mask_img = transformed_image;
+
+#ifndef ANDROID_STUBIFY
+ if (img->mask)
+ android_free_pixmap (img->mask);
+
+ img->mask = ANDROID_NONE;
+ img->mask = android_create_pixmap (img->width, img->height, 1);
+ android_put_image (img->mask, transformed_image);
+#endif
+ }
+
+ /* Done! */
#endif
}
{
#ifdef HAVE_NATIVE_TRANSFORMS
# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
- || defined (HAVE_HAIKU)
+ || defined (HAVE_HAIKU) | defined HAVE_ANDROID
return list2 (Qscale, Qrotate90);
# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
if (FRAME_DISPLAY_INFO (f)->xrender_supported_p)
static Lisp_Object virtual_core_pointer_name;
static Lisp_Object virtual_core_keyboard_name;
+/* If not nil, ID of the last TOUCHSCREEN_END_EVENT to land on the
+ menu bar. */
+static Lisp_Object menu_bar_touch_id;
+
\f
/* Global variable declarations. */
{
Lisp_Object x, y, id, position;
struct frame *f = XFRAME (event->frame_or_window);
+#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR
+ int column, row, dummy;
+#endif
id = event->arg;
x = event->x;
y = event->y;
+#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR
+ if (event->kind == TOUCHSCREEN_BEGIN_EVENT
+ && coords_in_menu_bar_window (f, XFIXNUM (x), XFIXNUM (y)))
+ {
+ /* If the tap began in the menu bar window, then save the
+ id. */
+ menu_bar_touch_id = id;
+ return Qnil;
+ }
+ else if (event->kind == TOUCHSCREEN_END_EVENT
+ && EQ (menu_bar_touch_id, id))
+ {
+ /* This touch should activate the menu bar. Generate the
+ menu bar event. */
+ menu_bar_touch_id = Qnil;
+
+ if (f->menu_bar_window)
+ {
+ x_y_to_hpos_vpos (XWINDOW (f->menu_bar_window), XFIXNUM (x),
+ XFIXNUM (y), &column, &row, NULL, NULL,
+ &dummy);
+
+ if (row >= 0 && row < FRAME_MENU_BAR_LINES (f))
+ {
+ Lisp_Object items, item;
+
+ /* Find the menu bar item under `column'. */
+ item = Qnil;
+ items = FRAME_MENU_BAR_ITEMS (f);
+ for (i = 0; i < ASIZE (items); i += 4)
+ {
+ Lisp_Object pos, string;
+ string = AREF (items, i + 1);
+ pos = AREF (items, i + 3);
+ if (NILP (string))
+ break;
+ if (column >= XFIXNUM (pos)
+ && column < XFIXNUM (pos) + SCHARS (string))
+ {
+ item = AREF (items, i);
+ break;
+ }
+ }
+
+ /* ELisp manual 2.4b says (x y) are window
+ relative but code says they are
+ frame-relative. */
+ position = list4 (event->frame_or_window,
+ Qmenu_bar,
+ Fcons (event->x, event->y),
+ INT_TO_INTEGER (event->timestamp));
+
+ return list2 (item, position);
+ }
+ }
+
+ return Qnil;
+ }
+#endif
+
position = make_lispy_position (f, x, y, event->timestamp);
return list2 (((event->kind
virtual_core_keyboard_name = Qnil;
staticpro (&virtual_core_keyboard_name);
+ menu_bar_touch_id = Qnil;
+ staticpro (&menu_bar_touch_id);
+
defsubr (&Scurrent_idle_time);
defsubr (&Sevent_symbol_parse_modifiers);
defsubr (&Sevent_convert_list);
that now overlap with Y, keeping them sorted by X. Poly those
edges through SPAN_FUNC. Then, move upwards by SFNT_POLY_STEP,
remove edges that no longer apply, and interpolate the remaining
- edge's X coordinates. Repeat until all the edges have been polyed.
+ edges' X coordinates. Repeat until all the edges have been polyed.
Or alternatively, think of this as such: each edge is actually a
vector from its bottom position towards its top most position.
return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff;
}
-/* Blend two pixels SRC and DST without utilizing any control flow.
- SRC must be in premultiplied ARGB8888 format, and DST must be in
- premultiplied ABGR8888 format. Value is in premultiplied ABGR8888
- format. */
-
-static unsigned int
-sfntfont_android_blend (unsigned int src, unsigned int dst)
-{
- unsigned int a, br_part, ag_part, src_rb, both;
-
- a = (src >> 24);
- br_part = sfntfont_android_mul8x2 (255 - a, dst);
- ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
-
- both = ag_part | br_part;
-
- /* Swizzle src. */
- src_rb = src & 0x00ff00ff;
- src = src & ~0x00ff00ff;
- src |= (src_rb >> 16 | src_rb << 16);
-
- /* This addition need not be saturating because both has already
- been multiplied by 255 - a. */
- return both + src;
-}
-
#define U255TO256(x) ((unsigned short) (x) + ((x) >> 7))
/* Blend two pixels SRC and DST without utilizing any control flow.
- Both SRC and DST are expected to be in premultiplied ARGB8888
+ Both SRC and DST are expected to be in premultiplied ABGB8888
format. Value is returned in premultiplied ARGB8888 format. */
static unsigned int
-sfntfont_android_blendrgb (unsigned int src, unsigned int dst)
+sfntfont_android_blend (unsigned int src, unsigned int dst)
{
- unsigned int a, rb_part, ag_part, both;
+ unsigned int a, br_part, ag_part, both;
a = (src >> 24);
- rb_part = sfntfont_android_mul8x2 (255 - a, dst);
+ br_part = sfntfont_android_mul8x2 (255 - a, dst);
ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
- both = ag_part | rb_part;
+ both = ag_part | br_part;
/* This addition need not be saturating because both has already
been multiplied by 255 - a. */
jobject bitmap;
int left, top, temp_y;
unsigned int prod, raster_y;
+ unsigned long foreground, back_pixel, rb;
if (!s->gc->num_clip_rects)
/* Clip region is empty. */
/* Nothing to draw. */
return;
+ /* Swizzle the foreground and background in s->gc into BGR, then add
+ an alpha channel. */
+ foreground = s->gc->foreground;
+ back_pixel = s->gc->background;
+ rb = foreground & 0x00ff00ff;
+ foreground &= ~0x00ff00ff;
+ foreground |= rb >> 16 | rb << 16 | 0xff000000;
+ rb = back_pixel & 0x00ff00ff;
+ back_pixel &= ~0x00ff00ff;
+ back_pixel |= rb >> 16 | rb << 16 | 0xff000000;
+
USE_SAFE_ALLOCA;
prepare_face_for_display (s->f, s->face);
+ stride * temp_y);
for (x = background.x; x < background.x + background.width; ++x)
- row[x] = s->gc->background | 0xff000000;
+ row[x] = back_pixel;
}
}
{
prod
= sfntfont_android_scale32 (U255TO256 (raster_row[x]),
- (s->gc->foreground
- | 0xff000000));
+ foreground);
row[left + x]
- = sfntfont_android_blendrgb (prod, row[left + x]);
+ = sfntfont_android_blend (prod, row[left + x]);
}
}
}
/* Emacs missing charsets? */
return false;
- font_character = ENCODE_CHAR (charset, XFIXNUM (character));
+ font_character = ENCODE_CHAR (charset, (int) XFIXNUM (character));
if (font_character == CHARSET_INVALID_CODE (charset))
return false;