mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
Update Android port
* doc/emacs/android.texi (Android, Android Environment): Improve
documentation.
* doc/lispref/commands.texi (Touchscreen Events): Document
changes to touchscreen support.
* doc/lispref/display.texi (Defining Faces, Window Systems):
* doc/lispref/frames.texi (Frame Layout, Font and Color
Parameters):
* doc/lispref/os.texi (System Environment): Document Android in
various places.
* java/org/gnu/emacs/EmacsWindow.java (figureChange): Fix crash.
* lisp/loadup.el: ("touch-screen"): Load touch-screen.el.
* lisp/pixel-scroll.el: Autoload two functions.
* lisp/term/android-win.el: Add require 'touch-screen.
* lisp/touch-screen.el (touch-screen-current-tool)
(touch-screen-current-timer, touch-screen-delay)
(touch-screen-relative-xy, touch-screen-handle-scroll)
(touch-screen-handle-timeout, touch-screen-handle-point-update)
(touch-screen-handle-point-up, touch-screen-handle-touch)
(global-map, touch-screen): New file.
* src/android.c (android_run_debug_thread): Fix build on 64 bit
systems.
(JNICALL, android_put_pixel): Likewise.
(android_transform_coordinates, android_four_corners_bilinear)
(android_fetch_pixel_bilinear, android_project_image_bilinear)
(android_fetch_pixel_nearest_24, android_fetch_pixel_nearest_1)
(android_project_image_nearest): New functions.
* src/androidgui.h (struct android_transform): New structure.
* src/androidterm.c (android_note_mouse_movement): Remove
obsolete TODO.
(android_get_scale_factor): New function.
(android_draw_underwave): Scale underwave correctly.
* src/dispextern.h: Support native image transforms on Android.
* src/image.c (matrix_identity, matrix_rotate)
(matrix_mirror_horizontal, matrix_translate): New functions.
(image_set_transform): Implement native image transforms on
Android.
(Fimage_transforms_p): Implement on Android.
* src/keyboard.c (make_lispy_event, syms_of_keyboard): Handle
touch screen- menu bar events.
* src/sfnt.c: Fix typo in comment.
* src/sfntfont-android.c (sfntfont_android_blend, U255TO256)
(sfntfont_android_put_glyphs): Avoid redundant swizzling.
* src/sfntfont.c (sfntfont_lookup_char): Fix build on 64 bit
systems.
This commit is contained in:
parent
da9ae10636
commit
ad59d8986a
19 changed files with 1115 additions and 65 deletions
|
|
@ -14,6 +14,7 @@ an Android device running Android 2.2 or later.
|
||||||
* Android Startup:: Starting up Emacs on Android.
|
* Android Startup:: Starting up Emacs on Android.
|
||||||
* Android File System:: The Android file system.
|
* Android File System:: The Android file system.
|
||||||
* Android Environment:: Running Emacs under Android.
|
* Android Environment:: Running Emacs under Android.
|
||||||
|
* Android Fonts:: Font selection under Android.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node What is Android?
|
@node What is Android?
|
||||||
|
|
@ -293,5 +294,56 @@ This strategy works as long as one window is in the foreground.
|
||||||
Otherwise, Emacs can only run in the background for a limited amount
|
Otherwise, Emacs can only run in the background for a limited amount
|
||||||
of time before the process is killed completely.
|
of time before the process is killed completely.
|
||||||
|
|
||||||
@c TODO: write more documentation here about what is supported and
|
@cindex windowing limitations, android
|
||||||
@c what is not, and fonts.
|
@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.
|
||||||
|
|
|
||||||
|
|
@ -2018,6 +2018,11 @@ display, because another program took the grab, or because the user
|
||||||
raised the finger from the touchscreen.
|
raised the finger from the touchscreen.
|
||||||
@end table
|
@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
|
@node Focus Events
|
||||||
@subsection Focus Events
|
@subsection Focus Events
|
||||||
@cindex focus event
|
@cindex focus event
|
||||||
|
|
|
||||||
|
|
@ -2846,8 +2846,9 @@ apply to. Here are the possible values of @var{characteristic}:
|
||||||
The kind of window system the terminal uses---either @code{graphic}
|
The kind of window system the terminal uses---either @code{graphic}
|
||||||
(any graphics-capable display), @code{x}, @code{pc} (for the MS-DOS
|
(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
|
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
|
Haiku), @code{pgtk} (for pure GTK), @code{android} (for Android), or
|
||||||
display). @xref{Window Systems, window-system}.
|
@code{tty} (a non-graphics-capable display). @xref{Window Systems,
|
||||||
|
window-system}.
|
||||||
|
|
||||||
@item class
|
@item class
|
||||||
What kinds of colors the terminal supports---either @code{color},
|
What kinds of colors the terminal supports---either @code{color},
|
||||||
|
|
@ -8734,6 +8735,8 @@ Emacs is displaying the frame using MS-DOS direct screen writes.
|
||||||
Emacs is displaying the frame using the Application Kit on Haiku.
|
Emacs is displaying the frame using the Application Kit on Haiku.
|
||||||
@item pgtk
|
@item pgtk
|
||||||
Emacs is displaying the frame using pure GTK facilities.
|
Emacs is displaying the frame using pure GTK facilities.
|
||||||
|
@item android
|
||||||
|
Emacs is displaying the frame on Android.
|
||||||
@item nil
|
@item nil
|
||||||
Emacs is displaying the frame on a character-based terminal.
|
Emacs is displaying the frame on a character-based terminal.
|
||||||
@end table
|
@end table
|
||||||
|
|
|
||||||
|
|
@ -695,7 +695,7 @@ The position of the top left corner of the native frame specifies the
|
||||||
indicate that position for the various builds:
|
indicate that position for the various builds:
|
||||||
|
|
||||||
@itemize @w{}
|
@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
|
@item (2) Lucid, Motif, and MS-Windows frames
|
||||||
|
|
||||||
|
|
@ -2389,6 +2389,7 @@ engine), and @code{harfbuzz} (font driver for OTF and TTF fonts with
|
||||||
HarfBuzz text shaping) (@pxref{Windows Fonts,,, emacs, The GNU Emacs
|
HarfBuzz text shaping) (@pxref{Windows Fonts,,, emacs, The GNU Emacs
|
||||||
Manual}). The @code{harfbuzz} driver is similarly recommended. On
|
Manual}). The @code{harfbuzz} driver is similarly recommended. On
|
||||||
Haiku, there can be several font drivers (@pxref{Haiku Fonts,,, emacs,
|
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}).
|
The GNU Emacs Manual}).
|
||||||
|
|
||||||
On other systems, there is only one available font backend, so it does
|
On other systems, there is only one available font backend, so it does
|
||||||
|
|
|
||||||
|
|
@ -970,6 +970,9 @@ Hewlett-Packard HPUX operating system.
|
||||||
@item nacl
|
@item nacl
|
||||||
Google Native Client (@acronym{NaCl}) sandboxing system.
|
Google Native Client (@acronym{NaCl}) sandboxing system.
|
||||||
|
|
||||||
|
@item android
|
||||||
|
The Open Handset Alliance's Android operating system.
|
||||||
|
|
||||||
@item ms-dos
|
@item ms-dos
|
||||||
Microsoft's DOS@. Emacs compiled with DJGPP for MS-DOS binds
|
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.
|
@code{system-type} to @code{ms-dos} even when you run it on MS-Windows.
|
||||||
|
|
|
||||||
|
|
@ -637,8 +637,8 @@ public class EmacsWindow extends EmacsHandleObject
|
||||||
pointerIndex = event.getActionIndex ();
|
pointerIndex = event.getActionIndex ();
|
||||||
pointerID = event.getPointerId (pointerIndex);
|
pointerID = event.getPointerId (pointerIndex);
|
||||||
pointerMap.put (pointerID,
|
pointerMap.put (pointerID,
|
||||||
new Coordinate ((int) event.getX (pointerID),
|
new Coordinate ((int) event.getX (pointerIndex),
|
||||||
(int) event.getY (pointerID)));
|
(int) event.getY (pointerIndex)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_POINTER_UP:
|
case MotionEvent.ACTION_POINTER_UP:
|
||||||
|
|
|
||||||
|
|
@ -295,6 +295,10 @@
|
||||||
(if (featurep 'dynamic-setting)
|
(if (featurep 'dynamic-setting)
|
||||||
(load "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)
|
(if (featurep 'x)
|
||||||
(progn
|
(progn
|
||||||
(load "x-dnd")
|
(load "x-dnd")
|
||||||
|
|
|
||||||
|
|
@ -500,6 +500,7 @@ Otherwise, redisplay will reset the window's vscroll."
|
||||||
(set-window-start nil (pixel-point-at-unseen-line) t)
|
(set-window-start nil (pixel-point-at-unseen-line) t)
|
||||||
(set-window-vscroll nil vscroll t))
|
(set-window-vscroll nil vscroll t))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
(defun pixel-scroll-precision-scroll-down-page (delta)
|
(defun pixel-scroll-precision-scroll-down-page (delta)
|
||||||
"Scroll the current window down by DELTA pixels.
|
"Scroll the current window down by DELTA pixels.
|
||||||
Note that this function doesn't work if DELTA is larger than
|
Note that this function doesn't work if DELTA is larger than
|
||||||
|
|
@ -556,6 +557,7 @@ the height of the current window."
|
||||||
(setq delta (- delta max-height)))
|
(setq delta (- delta max-height)))
|
||||||
(pixel-scroll-precision-scroll-down-page delta)))
|
(pixel-scroll-precision-scroll-down-page delta)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
(defun pixel-scroll-precision-scroll-up-page (delta)
|
(defun pixel-scroll-precision-scroll-up-page (delta)
|
||||||
"Scroll the current window up by DELTA pixels.
|
"Scroll the current window up by DELTA pixels.
|
||||||
Note that this function doesn't work if DELTA is larger than
|
Note that this function doesn't work if DELTA is larger than
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
(require 'mouse)
|
(require 'mouse)
|
||||||
(require 'fontset)
|
(require 'fontset)
|
||||||
(require 'dnd)
|
(require 'dnd)
|
||||||
|
(require 'touch-screen)
|
||||||
|
|
||||||
(add-to-list 'display-format-alist '(".*" . android))
|
(add-to-list 'display-format-alist '(".*" . android))
|
||||||
|
|
||||||
|
|
|
||||||
322
lisp/touch-screen.el
Normal file
322
lisp/touch-screen.el
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
;;; 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
|
||||||
282
src/android.c
282
src/android.c
|
|
@ -25,9 +25,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
@ -513,7 +515,7 @@ android_run_debug_thread (void *data)
|
||||||
char *line;
|
char *line;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
fd = (int) data;
|
fd = (int) (intptr_t) data;
|
||||||
file = fdopen (fd, "r");
|
file = fdopen (fd, "r");
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
|
|
@ -958,7 +960,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
|
||||||
close (pipefd[1]);
|
close (pipefd[1]);
|
||||||
|
|
||||||
if (pthread_create (&thread, NULL, android_run_debug_thread,
|
if (pthread_create (&thread, NULL, android_run_debug_thread,
|
||||||
(void *) pipefd[0]))
|
(void *) (intptr_t) pipefd[0]))
|
||||||
emacs_abort ();
|
emacs_abort ();
|
||||||
|
|
||||||
/* Now set the path to the site load directory. */
|
/* Now set the path to the site load directory. */
|
||||||
|
|
@ -2829,6 +2831,7 @@ android_put_pixel (struct android_image *ximg, int x, int y,
|
||||||
{
|
{
|
||||||
char *byte, *word;
|
char *byte, *word;
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
|
unsigned int pixel_int;
|
||||||
|
|
||||||
/* Ignore out-of-bounds accesses. */
|
/* Ignore out-of-bounds accesses. */
|
||||||
|
|
||||||
|
|
@ -2859,7 +2862,8 @@ android_put_pixel (struct android_image *ximg, int x, int y,
|
||||||
b = pixel & 0x000000ff;
|
b = pixel & 0x000000ff;
|
||||||
pixel = (r >> 16) | g | (b << 16) | 0xff000000;
|
pixel = (r >> 16) | g | (b << 16) | 0xff000000;
|
||||||
|
|
||||||
memcpy (word, &pixel, sizeof pixel);
|
pixel_int = pixel;
|
||||||
|
memcpy (word, &pixel_int, sizeof pixel_int);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3734,6 +3738,262 @@ android_exception_check (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 */
|
#else /* ANDROID_STUBIFY */
|
||||||
|
|
||||||
/* X emulation functions for Android. */
|
/* X emulation functions for Android. */
|
||||||
|
|
@ -3793,4 +4053,20 @@ android_put_image (android_pixmap pixmap,
|
||||||
emacs_abort ();
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -542,6 +542,25 @@ extern struct android_image *android_get_image (android_drawable,
|
||||||
enum android_image_format);
|
enum android_image_format);
|
||||||
extern void android_put_image (android_pixmap, struct android_image *);
|
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 *);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* X emulation stuff also needed while building stubs. */
|
/* X emulation stuff also needed while building stubs. */
|
||||||
|
|
|
||||||
|
|
@ -417,8 +417,6 @@ android_note_mouse_movement (struct frame *frame,
|
||||||
|| event->y < r->y || event->y >= r->y + r->height)
|
|| event->y < r->y || event->y >= r->y + r->height)
|
||||||
{
|
{
|
||||||
frame->mouse_moved = true;
|
frame->mouse_moved = true;
|
||||||
/* TODO
|
|
||||||
dpyinfo->last_mouse_scroll_bar = NULL; */
|
|
||||||
note_mouse_highlight (frame, event->x, event->y);
|
note_mouse_highlight (frame, event->x, event->y);
|
||||||
/* Remember which glyph we're now on. */
|
/* Remember which glyph we're now on. */
|
||||||
remember_mouse_glyph (frame, event->x, event->y, r);
|
remember_mouse_glyph (frame, event->x, event->y, r);
|
||||||
|
|
@ -2959,10 +2957,34 @@ android_draw_stretch_glyph_string (struct glyph_string *s)
|
||||||
s->background_filled_p = true;
|
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
|
static void
|
||||||
android_draw_underwave (struct glyph_string *s, int decoration_width)
|
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;
|
int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
|
||||||
bool odd;
|
bool odd;
|
||||||
struct android_rectangle wave_clip, string_clip, final_clip;
|
struct android_rectangle wave_clip, string_clip, final_clip;
|
||||||
|
|
|
||||||
|
|
@ -3099,7 +3099,8 @@ struct redisplay_interface
|
||||||
#ifdef HAVE_WINDOW_SYSTEM
|
#ifdef HAVE_WINDOW_SYSTEM
|
||||||
|
|
||||||
# if (defined USE_CAIRO || defined HAVE_XRENDER \
|
# if (defined USE_CAIRO || defined HAVE_XRENDER \
|
||||||
|| defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU)
|
|| defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU \
|
||||||
|
|| defined HAVE_ANDROID)
|
||||||
# define HAVE_NATIVE_TRANSFORMS
|
# define HAVE_NATIVE_TRANSFORMS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
|
|
||||||
306
src/image.c
306
src/image.c
|
|
@ -2631,11 +2631,11 @@ compute_image_size (double width, double height,
|
||||||
finally move the origin back to the top left of the image, which
|
finally move the origin back to the top left of the image, which
|
||||||
may now be a different corner.
|
may now be a different corner.
|
||||||
|
|
||||||
Note that different GUI backends (X, Cairo, w32, NS, Haiku) want
|
Note that different GUI backends (X, Cairo, w32, NS, Haiku,
|
||||||
the transform matrix defined as transform from the original image
|
Android) want the transform matrix defined as transform from the
|
||||||
to the transformed image, while others want the matrix to describe
|
original image to the transformed image, while others want the
|
||||||
the transform of the space, which boils down to inverting the
|
matrix to describe the transform of the space, which boils down to
|
||||||
matrix.
|
inverting the matrix.
|
||||||
|
|
||||||
It's possible to pre-calculate the matrix multiplications and just
|
It's possible to pre-calculate the matrix multiplications and just
|
||||||
generate one transform matrix that will do everything we need in a
|
generate one transform matrix that will do everything we need in a
|
||||||
|
|
@ -2677,6 +2677,96 @@ compute_image_rotation (struct image *img, double *rotation)
|
||||||
*rotation = XFIXNUM (reduced_angle);
|
*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
|
static void
|
||||||
image_set_transform (struct frame *f, struct image *img)
|
image_set_transform (struct frame *f, struct image *img)
|
||||||
{
|
{
|
||||||
|
|
@ -2696,6 +2786,14 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
memcpy (&img->transform, identity, sizeof identity);
|
memcpy (&img->transform, identity, sizeof identity);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined HAVE_ANDROID
|
||||||
|
matrix3x3 identity = {
|
||||||
|
{ 1, 0, 0 },
|
||||||
|
{ 0, 1, 0 },
|
||||||
|
{ 0, 0, 1 },
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
# if (defined HAVE_IMAGEMAGICK \
|
# if (defined HAVE_IMAGEMAGICK \
|
||||||
&& !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE)
|
&& !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE)
|
||||||
/* ImageMagick images already have the correct transform. */
|
/* ImageMagick images already have the correct transform. */
|
||||||
|
|
@ -2733,7 +2831,8 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
/* Determine flipping. */
|
/* Determine flipping. */
|
||||||
flip = !NILP (image_spec_value (img->spec, QCflip, NULL));
|
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
|
/* We want scale up operations to use a nearest neighbor filter to
|
||||||
show real pixels instead of munging them, but scale down
|
show real pixels instead of munging them, but scale down
|
||||||
operations to use a blended filter, to avoid aliasing and the like.
|
operations to use a blended filter, to avoid aliasing and the like.
|
||||||
|
|
@ -2755,7 +2854,7 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
|
|
||||||
matrix3x3 matrix
|
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
|
[0][0] = (!IEEE_FLOATING_POINT && width == 0 ? DBL_MAX
|
||||||
: img->width / (double) width),
|
: img->width / (double) width),
|
||||||
[1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX
|
[1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX
|
||||||
|
|
@ -2778,7 +2877,7 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
|
|
||||||
/* Haiku needs this, since the transformation is done on the basis
|
/* Haiku needs this, since the transformation is done on the basis
|
||||||
of the view, and not the image. */
|
of the view, and not the image. */
|
||||||
#ifdef HAVE_HAIKU
|
#if defined HAVE_HAIKU
|
||||||
int extra_tx, extra_ty;
|
int extra_tx, extra_ty;
|
||||||
|
|
||||||
extra_tx = 0;
|
extra_tx = 0;
|
||||||
|
|
@ -2789,6 +2888,7 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
rotate_flag = 0;
|
rotate_flag = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifndef HAVE_ANDROID
|
||||||
# if (defined USE_CAIRO || defined HAVE_XRENDER \
|
# if (defined USE_CAIRO || defined HAVE_XRENDER \
|
||||||
|| defined HAVE_NTGUI || defined HAVE_NS \
|
|| defined HAVE_NTGUI || defined HAVE_NS \
|
||||||
|| defined HAVE_HAIKU)
|
|| defined HAVE_HAIKU)
|
||||||
|
|
@ -2817,7 +2917,7 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
sin_r = 1;
|
sin_r = 1;
|
||||||
rotate_flag = 1;
|
rotate_flag = 1;
|
||||||
|
|
||||||
#ifdef HAVE_HAIKU
|
#if defined HAVE_HAIKU
|
||||||
if (!flip)
|
if (!flip)
|
||||||
extra_ty = height;
|
extra_ty = height;
|
||||||
extra_tx = 0;
|
extra_tx = 0;
|
||||||
|
|
@ -2853,7 +2953,7 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
|
|
||||||
if (0 < rotate_flag)
|
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. */
|
/* 1. Translate so (0, 0) is in the center of the image. */
|
||||||
matrix3x3 t
|
matrix3x3 t
|
||||||
= { [0][0] = 1,
|
= { [0][0] = 1,
|
||||||
|
|
@ -2904,6 +3004,93 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
img->height = height;
|
img->height = height;
|
||||||
}
|
}
|
||||||
# endif
|
# 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)
|
if (rotate_flag < 0)
|
||||||
|
|
@ -2968,6 +3155,103 @@ image_set_transform (struct frame *f, struct image *img)
|
||||||
img->transform[0][2] = extra_tx;
|
img->transform[0][2] = extra_tx;
|
||||||
img->transform[1][2] = extra_ty;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -12087,7 +12371,7 @@ The list of capabilities can include one or more of the following:
|
||||||
{
|
{
|
||||||
#ifdef HAVE_NATIVE_TRANSFORMS
|
#ifdef HAVE_NATIVE_TRANSFORMS
|
||||||
# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
|
# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
|
||||||
|| defined (HAVE_HAIKU)
|
|| defined (HAVE_HAIKU) | defined HAVE_ANDROID
|
||||||
return list2 (Qscale, Qrotate90);
|
return list2 (Qscale, Qrotate90);
|
||||||
# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
|
# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
|
||||||
if (FRAME_DISPLAY_INFO (f)->xrender_supported_p)
|
if (FRAME_DISPLAY_INFO (f)->xrender_supported_p)
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,10 @@ static struct timespec timer_last_idleness_start_time;
|
||||||
static Lisp_Object virtual_core_pointer_name;
|
static Lisp_Object virtual_core_pointer_name;
|
||||||
static Lisp_Object virtual_core_keyboard_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;
|
||||||
|
|
||||||
|
|
||||||
/* Global variable declarations. */
|
/* Global variable declarations. */
|
||||||
|
|
||||||
|
|
@ -6445,11 +6449,74 @@ make_lispy_event (struct input_event *event)
|
||||||
{
|
{
|
||||||
Lisp_Object x, y, id, position;
|
Lisp_Object x, y, id, position;
|
||||||
struct frame *f = XFRAME (event->frame_or_window);
|
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;
|
id = event->arg;
|
||||||
x = event->x;
|
x = event->x;
|
||||||
y = event->y;
|
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);
|
position = make_lispy_position (f, x, y, event->timestamp);
|
||||||
|
|
||||||
return list2 (((event->kind
|
return list2 (((event->kind
|
||||||
|
|
@ -12462,6 +12529,9 @@ syms_of_keyboard (void)
|
||||||
virtual_core_keyboard_name = Qnil;
|
virtual_core_keyboard_name = Qnil;
|
||||||
staticpro (&virtual_core_keyboard_name);
|
staticpro (&virtual_core_keyboard_name);
|
||||||
|
|
||||||
|
menu_bar_touch_id = Qnil;
|
||||||
|
staticpro (&menu_bar_touch_id);
|
||||||
|
|
||||||
defsubr (&Scurrent_idle_time);
|
defsubr (&Scurrent_idle_time);
|
||||||
defsubr (&Sevent_symbol_parse_modifiers);
|
defsubr (&Sevent_symbol_parse_modifiers);
|
||||||
defsubr (&Sevent_convert_list);
|
defsubr (&Sevent_convert_list);
|
||||||
|
|
|
||||||
|
|
@ -3436,7 +3436,7 @@ sfnt_compare_edges (const void *a, const void *b)
|
||||||
that now overlap with Y, keeping them sorted by X. Poly those
|
that now overlap with Y, keeping them sorted by X. Poly those
|
||||||
edges through SPAN_FUNC. Then, move upwards by SFNT_POLY_STEP,
|
edges through SPAN_FUNC. Then, move upwards by SFNT_POLY_STEP,
|
||||||
remove edges that no longer apply, and interpolate the remaining
|
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
|
Or alternatively, think of this as such: each edge is actually a
|
||||||
vector from its bottom position towards its top most position.
|
vector from its bottom position towards its top most position.
|
||||||
|
|
|
||||||
|
|
@ -73,15 +73,16 @@ sfntfont_android_mul8x2 (unsigned int a8, unsigned int b32)
|
||||||
return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff;
|
return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define U255TO256(x) ((unsigned short) (x) + ((x) >> 7))
|
||||||
|
|
||||||
/* Blend two pixels SRC and DST without utilizing any control flow.
|
/* Blend two pixels SRC and DST without utilizing any control flow.
|
||||||
SRC must be in premultiplied ARGB8888 format, and DST must be in
|
Both SRC and DST are expected to be in premultiplied ABGB8888
|
||||||
premultiplied ABGR8888 format. Value is in premultiplied ABGR8888
|
format. Value is returned in premultiplied ARGB8888 format. */
|
||||||
format. */
|
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
sfntfont_android_blend (unsigned int src, unsigned int dst)
|
sfntfont_android_blend (unsigned int src, unsigned int dst)
|
||||||
{
|
{
|
||||||
unsigned int a, br_part, ag_part, src_rb, both;
|
unsigned int a, br_part, ag_part, both;
|
||||||
|
|
||||||
a = (src >> 24);
|
a = (src >> 24);
|
||||||
br_part = sfntfont_android_mul8x2 (255 - a, dst);
|
br_part = sfntfont_android_mul8x2 (255 - a, dst);
|
||||||
|
|
@ -89,33 +90,6 @@ sfntfont_android_blend (unsigned int src, unsigned int dst)
|
||||||
|
|
||||||
both = ag_part | br_part;
|
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
|
|
||||||
format. Value is returned in premultiplied ARGB8888 format. */
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
sfntfont_android_blendrgb (unsigned int src, unsigned int dst)
|
|
||||||
{
|
|
||||||
unsigned int a, rb_part, ag_part, both;
|
|
||||||
|
|
||||||
a = (src >> 24);
|
|
||||||
rb_part = sfntfont_android_mul8x2 (255 - a, dst);
|
|
||||||
ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
|
|
||||||
|
|
||||||
both = ag_part | rb_part;
|
|
||||||
|
|
||||||
/* This addition need not be saturating because both has already
|
/* This addition need not be saturating because both has already
|
||||||
been multiplied by 255 - a. */
|
been multiplied by 255 - a. */
|
||||||
return both + src;
|
return both + src;
|
||||||
|
|
@ -210,6 +184,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
|
||||||
jobject bitmap;
|
jobject bitmap;
|
||||||
int left, top, temp_y;
|
int left, top, temp_y;
|
||||||
unsigned int prod, raster_y;
|
unsigned int prod, raster_y;
|
||||||
|
unsigned long foreground, back_pixel, rb;
|
||||||
|
|
||||||
if (!s->gc->num_clip_rects)
|
if (!s->gc->num_clip_rects)
|
||||||
/* Clip region is empty. */
|
/* Clip region is empty. */
|
||||||
|
|
@ -219,6 +194,17 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
|
||||||
/* Nothing to draw. */
|
/* Nothing to draw. */
|
||||||
return;
|
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;
|
USE_SAFE_ALLOCA;
|
||||||
|
|
||||||
prepare_face_for_display (s->f, s->face);
|
prepare_face_for_display (s->f, s->face);
|
||||||
|
|
@ -294,7 +280,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
|
||||||
+ stride * temp_y);
|
+ stride * temp_y);
|
||||||
|
|
||||||
for (x = background.x; x < background.x + background.width; ++x)
|
for (x = background.x; x < background.x + background.width; ++x)
|
||||||
row[x] = s->gc->background | 0xff000000;
|
row[x] = back_pixel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,10 +313,9 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
|
||||||
{
|
{
|
||||||
prod
|
prod
|
||||||
= sfntfont_android_scale32 (U255TO256 (raster_row[x]),
|
= sfntfont_android_scale32 (U255TO256 (raster_row[x]),
|
||||||
(s->gc->foreground
|
foreground);
|
||||||
| 0xff000000));
|
|
||||||
row[left + x]
|
row[left + x]
|
||||||
= sfntfont_android_blendrgb (prod, row[left + x]);
|
= sfntfont_android_blend (prod, row[left + x]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -860,7 +860,7 @@ sfntfont_lookup_char (struct sfnt_font_desc *desc, Lisp_Object character,
|
||||||
/* Emacs missing charsets? */
|
/* Emacs missing charsets? */
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
font_character = ENCODE_CHAR (charset, XFIXNUM (character));
|
font_character = ENCODE_CHAR (charset, (int) XFIXNUM (character));
|
||||||
|
|
||||||
if (font_character == CHARSET_INVALID_CODE (charset))
|
if (font_character == CHARSET_INVALID_CODE (charset))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue