* configure.ac (ANDROID_MIN_SDK): New variable. (DX): Remove and replace with D8. (XCONFIGURE): Check for the minimum version of Android the cross compiler compiles for. Generate java/AndroidManifest.xml from java/AndroidManifest.xml.in. Allow using Zlib on Android. * java/AndroidManifest.xml.in: New file. Use the minimum SDK detected by configure. * java/Makefile.in (top_srcdir, version): New variables. (DX, D8): Replace with D8. (ANDROID_MIN_SDK, APK_NAME): New variables. (.PHONY): (.PRECIOUS): (classes.dex): (emacs.apk): Generate $(APK_NAME) instead of `emacs.apk'. * java/debug.sh: New option --attach-existing. Attach to an existing Emacs instance when specified. * java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): New field `isPaused'. (invalidateFocus1): Fix infinite recursion. (detachWindow): Deiconify window. (attachWindow): Iconify the window if the activity is paused. (onCreate): Use the ``no title bar'' theme. (onPause, onResume): New functions. * java/org/gnu/emacs/EmacsNative.java (sendTouchUp, sendTouchDown) (sendTouchMove, sendWheel, sendIconified, sendDeiconified): New functions. * java/org/gnu/emacs/EmacsSdk7FontDriver.java (Sdk7Typeface): (list): Remove logging for code that is mostly going to be unused. * java/org/gnu/emacs/EmacsService.java (ringBell, queryTree) (getScreenWidth, getScreenHeight, detectMouse): New functions. * java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView) (surfaceChanged, surfaceCreated, surfaceDestroyed): Add extra debug logging. Avoid deadlock in surfaceCreated. * java/org/gnu/emacs/EmacsView.java (EmacsView): Try very hard to make the SurfaceView respect Z order. It didn't work. (handleDirtyBitmap): Copy over the contents from the old bitmap. (explicitlyDirtyBitmap): New function. (onLayout): Don't dirty bitmap if unnecessary. (damageRect, swapBuffers): Don't synchronize so hard. (onTouchEvent): Call window.onTouchEvent instead. (moveChildToBack, raise, lower): New functions. * java/org/gnu/emacs/EmacsWindow.java (Coordinate): New subclass. (pointerMap, isMapped, isIconified, dontFocusOnMap) (dontAcceptFocus): New fields. (EmacsWindow): Don't immediately register unmapped window. (viewLayout): Send configure event outside the lock. (requestViewLayout): Explicitly dirty the bitmap. (mapWindow): Register the window now. Respect dontFocusOnMap. (unmapWindow): Unregister the window now. (figureChange, onTouchEvent): New functions. (onSomeKindOfMotionEvent): Handle scroll wheel events. (reparentTo, makeInputFocus, raise, lower, getWindowGeometry) (noticeIconified, noticeDeiconified, setDontAcceptFocus) (setDontFocusOnMap, getDontFocusOnMap): New functions. * java/org/gnu/emacs/EmacsWindowAttachmentManager.java (registerWindow, detachWindow): Synchronize. (noticeIconified, noticeDeiconified): New functions. (copyWindows): New function. * lisp/frame.el (frame-geometry, frame-edges) (mouse-absolute-pixel-position, set-mouse-absolute-pixel-position) (frame-list-z-order, frame-restack, display-mouse-p) (display-monitor-attributes-list): Implement on Android. * lisp/mwheel.el (mouse-wheel-down-event): (mouse-wheel-up-event): (mouse-wheel-left-event): (mouse-wheel-right-event): Define on Android. * src/android.c (struct android_emacs_service): New methods `ringBell', `queryTree', `getScreenWidth', `getScreenHeight', and `detectMouse'. (struct android_event_queue, android_init_events) (android_next_event, android_write_event): Remove write limit. (android_file_access_p): Handle directories correcty. (android_close): Fix coding style. (android_fclose): New function. (android_init_emacs_service): Initialize new methods. (android_reparent_window): Implement function. (android_bell, android_set_input_focus, android_raise_window) (android_lower_window, android_query_tree, android_get_geometry) (android_get_screen_width, android_get_screen_height) (android_get_mm_width, android_get_mm_height, android_detect_mouse) (android_set_dont_focus_on_map, android_set_dont_accept_focus): New functions. (struct android_dir): New structure. (android_opendir, android_readdir, android_closedir): New functions. (emacs_abort): Implement here on Android and poke debuggerd into generating a tombstone. * src/android.h: Update prototypes. * src/androidfns.c (android_set_parent_frame): New function. (android_default_font_parameter): Use sane font size by default. (Fx_display_pixel_width, Fx_display_pixel_height) (Fx_display_mm_width, Fx_display_mm_height) (Fx_display_monitor_attributes_list): Rename to start with `android-'. Implement. Fiddle with documentation to introduce Android specific nuances. (Fandroid_display_monitor_attributes_list): New function. (Fx_frame_geometry, frame_geometry): New function. (Fandroid_frame_geometry): Implement correctly. (Fx_frame_list_z_order): Rename to start with `android-'. (android_frame_list_z_order, Fandroid_frame_list_z_order): Implement. (Fx_frame_restack): Rename to start with `android-'. (Fandroid_frame_restack): ``Implement''. (Fx_mouse_absolute_pixel_position): Rename to start with `android-'. (Fandroid_mouse_absolute_pixel_position): ``Implement''. (Fx_set_mouse_absolute_pixel_position): Rename to start with `android-'. (Fandroid_set_mouse_absolute_pixel_position): ``Implement''. (Fandroid_detect_mouse): New function. (android_set_menu_bar_lines): Use FRAME_ANDROID_DRAWABLE when clearing area. (android_set_no_focus_on_map, android_set_no_accept_focus): New functions. (android_frame_parm_handlers): Register new frame parameter handlers. (syms_of_androidfns): Update appropriately. * src/androidfont.c (androidfont_draw): Use FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW. * src/androidgui.h (enum android_event_type): New events. (struct android_touch_event, struct android_wheel_event) (struct android_iconify_event): New structures. (union android_event): Add new events. * src/androidterm.c (android_clear_frame): Use FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW. (android_flash, android_ring_bell): Implement bell ringing. (android_toggle_invisible_pointer): Don't TODO function that can't be implemented. (show_back_buffer, android_flush_dirty_back_buffer_on): Check if a buffer flip is required before doing the flip. (android_lower_frame, android_raise_frame): Implement functions. (android_update_tools, android_find_tool): New functions. (handle_one_android_event): Handle new iconification, wheel and touch events. (android_read_socket): Implement pending-autoraise-frames. (android_frame_up_to_date): Implement bell ringing. (android_buffer_flipping_unblocked_hook): Check if a buffer flip is required before doing the flip. (android_focus_frame, android_frame_highlight) (android_frame_unhighlight): New function. (android_frame_rehighlight): Implement functions. (android_iconify_frame): Always display error. (android_set_alpha): Update commentary. (android_free_frame_resources): Free frame touch points. (android_scroll_run, android_flip_and_flush) (android_clear_rectangle, android_draw_fringe_bitmap) (android_draw_glyph_string_background, android_fill_triangle) (android_clear_point, android_draw_relief_rect) (android_draw_box_rect, android_draw_glyph_string_bg_rect) (android_draw_image_foreground, android_draw_stretch_glyph_string) (android_draw_underwave, android_draw_glyph_string_foreground) (android_draw_composite_glyph_string_foreground) (android_draw_glyphless_glyph_string_foreground) (android_draw_glyph_string, android_clear_frame_area) (android_clear_under_internal_border, android_draw_hollow_cursor) (android_draw_bar_cursor, android_draw_vertical_window_border) (android_draw_window_divider): Use FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW for drawing operations. * src/androidterm.h (struct android_touch_point): New structure. (struct android_output): New fields. (FRAME_ANDROID_NEED_BUFFER_FLIP): New macro. * src/dired.c (emacs_readdir, open_directory) (directory_files_internal_unwind, read_dirent) (directory_files_internal, file_name_completion): Add indirection over readdir and opendir. Use android variants on Android. * src/dispnew.c (Fopen_termscript): * src/fileio.c (fclose_unwind): Use emacs_fclose. (Faccess_file): Call android_file_access_p. (file_accessible_directory_p): Append right suffix to Android assets directory. (do_auto_save_unwind): Use emacs_fclose. * src/keyboard.c (lispy_function_keys): Use right function key for page up and page down. (Fopen_dribble_file): Use emacs_fclose. * src/lisp.h: New prototype emacs_fclose. * src/lread.c (close_infile_unwind): Use emacs_fclose. * src/sfnt.c (sfnt_curve_is_flat): Fix area-squared computation. (sfnt_prepare_raster): Compute raster width and height consistently with outline building. (sfnt_build_outline_edges): Use the same offsets used to set offy and offx. (main): Adjust debug code. * src/sfntfont-android.c (sfntfont_android_saturate32): Delete function. (sfntfont_android_blend, sfntfont_android_blendrgb): Remove unnecessary debug code. (sfntfont_android_composite_bitmap): Prevent out of bounds write. (sfntfont_android_put_glyphs): Use FRAME_ANDROID_DRAWABLE. (init_sfntfont_android): Initialize Monospace Serif font to something sensible. * src/sfntfont.c (sfntfont_text_extents): Clear glyph metrics before summing up pcm. (sfntfont_draw): Use s->font instead of s->face->font. * src/sysdep.c (emacs_fclose): Wrap around android_fclose on android. * src/term.c (Fsuspend_tty): (delete_tty): Use emacs_fclose. * src/verbose.mk.in (AM_V_DX): Replace with D8 version.
551 lines
14 KiB
Java
551 lines
14 KiB
Java
/* Font backend for Android terminals. -*- c-file-style: "GNU" -*-
|
|
|
|
Copyright (C) 2023 Free Software Foundation, Inc.
|
|
|
|
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/>. */
|
|
|
|
package org.gnu.emacs;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
|
|
import android.graphics.Paint;
|
|
import android.graphics.Rect;
|
|
import android.graphics.Typeface;
|
|
import android.graphics.Canvas;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.os.Build;
|
|
|
|
public class EmacsSdk7FontDriver extends EmacsFontDriver
|
|
{
|
|
private static final String TOFU_STRING = "\uDB3F\uDFFD";
|
|
private static final String EM_STRING = "m";
|
|
private static final String TAG = "EmacsSdk7FontDriver";
|
|
|
|
protected class Sdk7Typeface
|
|
{
|
|
/* The typeface and paint. */
|
|
public Typeface typeface;
|
|
public Paint typefacePaint;
|
|
public String familyName;
|
|
public int slant, width, weight, spacing;
|
|
|
|
public
|
|
Sdk7Typeface (String fileName, Typeface typeface)
|
|
{
|
|
String style, testString;
|
|
int index, measured, i;
|
|
float[] widths;
|
|
|
|
slant = NORMAL;
|
|
weight = REGULAR;
|
|
width = UNSPECIFIED;
|
|
spacing = PROPORTIONAL;
|
|
|
|
this.typeface = typeface;
|
|
|
|
typefacePaint = new Paint ();
|
|
typefacePaint.setAntiAlias (true);
|
|
typefacePaint.setTypeface (typeface);
|
|
|
|
/* For the calls to measureText below. */
|
|
typefacePaint.setTextSize (10.0f);
|
|
|
|
/* Parse the file name into some useful data. First, strip off
|
|
the extension. */
|
|
fileName = fileName.split ("\\.", 2)[0];
|
|
|
|
/* Next, split the file name by dashes. Everything before the
|
|
last dash is part of the family name. */
|
|
index = fileName.lastIndexOf ("-");
|
|
|
|
if (index > 0)
|
|
{
|
|
style = fileName.substring (index + 1, fileName.length ());
|
|
familyName = fileName.substring (0, index);
|
|
|
|
/* Look for something describing the weight. */
|
|
if (style.contains ("Thin"))
|
|
weight = THIN;
|
|
else if (style.contains ("UltraLight"))
|
|
weight = ULTRA_LIGHT;
|
|
else if (style.contains ("SemiLight"))
|
|
weight = SEMI_LIGHT;
|
|
else if (style.contains ("Light"))
|
|
weight = LIGHT;
|
|
else if (style.contains ("Medium"))
|
|
weight = MEDIUM;
|
|
else if (style.contains ("SemiBold"))
|
|
weight = SEMI_BOLD;
|
|
else if (style.contains ("ExtraBold"))
|
|
weight = EXTRA_BOLD;
|
|
else if (style.contains ("Bold"))
|
|
weight = BOLD;
|
|
else if (style.contains ("Black"))
|
|
weight = BLACK;
|
|
else if (style.contains ("UltraHeavy"))
|
|
weight = ULTRA_HEAVY;
|
|
|
|
/* And the slant. */
|
|
if (style.contains ("ReverseOblique"))
|
|
slant = OBLIQUE;
|
|
else if (style.contains ("ReverseItalic"))
|
|
slant = REVERSE_ITALIC;
|
|
else if (style.contains ("Italic"))
|
|
slant = ITALIC;
|
|
else if (style.contains ("Oblique"))
|
|
slant = OBLIQUE;
|
|
|
|
/* Finally, the width. */
|
|
if (style.contains ("UltraCondensed"))
|
|
width = ULTRA_CONDENSED;
|
|
else if (style.contains ("ExtraCondensed"))
|
|
width = EXTRA_CONDENSED;
|
|
else if (style.contains ("SemiCondensed"))
|
|
width = SEMI_CONDENSED;
|
|
else if (style.contains ("Condensed"))
|
|
width = CONDENSED;
|
|
else if (style.contains ("SemiExpanded"))
|
|
width = SEMI_EXPANDED;
|
|
else if (style.contains ("ExtraExpanded"))
|
|
width = EXTRA_EXPANDED;
|
|
else if (style.contains ("UltraExpanded"))
|
|
width = ULTRA_EXPANDED;
|
|
else if (style.contains ("Expanded"))
|
|
width = EXPANDED;
|
|
|
|
/* Guess the spacing information. */
|
|
testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
widths = new float[testString.length ()];
|
|
|
|
measured = typefacePaint.getTextWidths (testString,
|
|
0, testString.length (),
|
|
widths);
|
|
spacing = MONO;
|
|
for (i = 0; i < measured; ++i)
|
|
{
|
|
if (i != 0 && widths[i - 1] != widths[i])
|
|
/* This isn't a monospace font. */
|
|
spacing = PROPORTIONAL;
|
|
}
|
|
}
|
|
else
|
|
familyName = fileName;
|
|
}
|
|
|
|
@Override
|
|
public String
|
|
toString ()
|
|
{
|
|
return ("Sdk7Typeface ("
|
|
+ String.valueOf (familyName) + ", "
|
|
+ String.valueOf (slant) + ", "
|
|
+ String.valueOf (width) + ", "
|
|
+ String.valueOf (weight) + ", "
|
|
+ String.valueOf (spacing) + ")");
|
|
}
|
|
};
|
|
|
|
protected class Sdk7FontEntity extends FontEntity
|
|
{
|
|
/* The typeface. */
|
|
public Sdk7Typeface typeface;
|
|
|
|
public
|
|
Sdk7FontEntity (Sdk7Typeface typeface)
|
|
{
|
|
float width;
|
|
|
|
foundry = "Google";
|
|
family = typeface.familyName;
|
|
adstyle = null;
|
|
weight = typeface.weight;
|
|
slant = typeface.slant;
|
|
spacing = typeface.spacing;
|
|
width = typeface.width;
|
|
dpi = Math.round (EmacsService.SERVICE.metrics.scaledDensity * 160f);
|
|
|
|
this.typeface = typeface;
|
|
}
|
|
};
|
|
|
|
protected class Sdk7FontObject extends FontObject
|
|
{
|
|
/* The typeface. */
|
|
public Sdk7Typeface typeface;
|
|
|
|
public
|
|
Sdk7FontObject (Sdk7Typeface typeface, int pixelSize)
|
|
{
|
|
float totalWidth;
|
|
String testWidth, testString;
|
|
|
|
this.typeface = typeface;
|
|
this.pixelSize = pixelSize;
|
|
|
|
family = typeface.familyName;
|
|
adstyle = null;
|
|
weight = typeface.weight;
|
|
slant = typeface.slant;
|
|
spacing = typeface.spacing;
|
|
width = typeface.width;
|
|
dpi = Math.round (EmacsService.SERVICE.metrics.scaledDensity * 160f);
|
|
|
|
/* Compute the ascent and descent. */
|
|
typeface.typefacePaint.setTextSize (pixelSize);
|
|
ascent
|
|
= Math.round (-typeface.typefacePaint.ascent ());
|
|
descent
|
|
= Math.round (typeface.typefacePaint.descent ());
|
|
|
|
/* Compute the average width. */
|
|
testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
totalWidth = typeface.typefacePaint.measureText (testString);
|
|
|
|
if (totalWidth > 0)
|
|
avgwidth = Math.round (totalWidth
|
|
/ testString.length ());
|
|
|
|
/* Android doesn't expose the font average width and height
|
|
information, so this will have to do. */
|
|
minWidth = maxWidth = avgwidth;
|
|
|
|
/* This is different from avgwidth in the font spec! */
|
|
averageWidth = avgwidth;
|
|
|
|
/* Set the space width. */
|
|
totalWidth = typeface.typefacePaint.measureText (" ");
|
|
spaceWidth = Math.round (totalWidth);
|
|
|
|
/* Set the height and default ascent. */
|
|
height = ascent + descent;
|
|
defaultAscent = ascent;
|
|
}
|
|
};
|
|
|
|
private String[] fontFamilyList;
|
|
private Sdk7Typeface[] typefaceList;
|
|
private Sdk7Typeface fallbackTypeface;
|
|
|
|
public
|
|
EmacsSdk7FontDriver ()
|
|
{
|
|
int i;
|
|
File systemFontsDirectory, fontFile;
|
|
Typeface typeface;
|
|
|
|
systemFontsDirectory = new File ("/system/fonts");
|
|
|
|
fontFamilyList = systemFontsDirectory.list ();
|
|
typefaceList = new Sdk7Typeface[fontFamilyList.length + 3];
|
|
|
|
/* It would be nice to avoid opening each and every font upon
|
|
startup. But that doesn't seem to be possible on
|
|
Android. */
|
|
|
|
for (i = 0; i < fontFamilyList.length; ++i)
|
|
{
|
|
fontFile = new File (systemFontsDirectory,
|
|
fontFamilyList[i]);
|
|
typeface = Typeface.createFromFile (fontFile);
|
|
typefaceList[i] = new Sdk7Typeface (fontFile.getName (),
|
|
typeface);
|
|
}
|
|
|
|
/* Initialize the default monospace and serif typefaces. */
|
|
fallbackTypeface = new Sdk7Typeface ("monospace",
|
|
Typeface.MONOSPACE);
|
|
typefaceList[fontFamilyList.length] = fallbackTypeface;
|
|
|
|
fallbackTypeface = new Sdk7Typeface ("Monospace",
|
|
Typeface.MONOSPACE);
|
|
typefaceList[fontFamilyList.length + 1] = fallbackTypeface;
|
|
|
|
fallbackTypeface = new Sdk7Typeface ("Sans Serif",
|
|
Typeface.DEFAULT);
|
|
typefaceList[fontFamilyList.length + 2] = fallbackTypeface;
|
|
}
|
|
|
|
private boolean
|
|
checkMatch (Sdk7Typeface typeface, FontSpec fontSpec)
|
|
{
|
|
if (fontSpec.family != null
|
|
&& !fontSpec.family.equals (typeface.familyName))
|
|
return false;
|
|
|
|
if (fontSpec.slant != null
|
|
&& !fontSpec.weight.equals (typeface.weight))
|
|
return false;
|
|
|
|
if (fontSpec.spacing != null
|
|
&& !fontSpec.spacing.equals (typeface.spacing))
|
|
return false;
|
|
|
|
if (fontSpec.weight != null
|
|
&& !fontSpec.weight.equals (typeface.weight))
|
|
return false;
|
|
|
|
if (fontSpec.width != null
|
|
&& !fontSpec.width.equals (typeface.width))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public FontEntity[]
|
|
list (FontSpec fontSpec)
|
|
{
|
|
LinkedList<FontEntity> list;
|
|
int i;
|
|
|
|
list = new LinkedList<FontEntity> ();
|
|
|
|
for (i = 0; i < typefaceList.length; ++i)
|
|
{
|
|
if (checkMatch (typefaceList[i], fontSpec))
|
|
list.add (new Sdk7FontEntity (typefaceList[i]));
|
|
}
|
|
|
|
return (FontEntity[]) list.toArray (new FontEntity[0]);
|
|
}
|
|
|
|
@Override
|
|
public FontEntity
|
|
match (FontSpec fontSpec)
|
|
{
|
|
FontEntity[] entities;
|
|
int i;
|
|
|
|
entities = this.list (fontSpec);
|
|
|
|
if (entities.length == 0)
|
|
return new Sdk7FontEntity (fallbackTypeface);
|
|
|
|
return entities[0];
|
|
}
|
|
|
|
@Override
|
|
public String[]
|
|
listFamilies ()
|
|
{
|
|
return fontFamilyList;
|
|
}
|
|
|
|
@Override
|
|
public FontObject
|
|
openFont (FontEntity fontEntity, int pixelSize)
|
|
{
|
|
return new Sdk7FontObject (((Sdk7FontEntity) fontEntity).typeface,
|
|
pixelSize);
|
|
}
|
|
|
|
@Override
|
|
public int
|
|
hasChar (FontSpec font, char charCode)
|
|
{
|
|
float missingGlyphWidth, emGlyphWidth, width;
|
|
Rect rect1, rect2;
|
|
Paint paint;
|
|
Sdk7FontObject fontObject;
|
|
|
|
if (font instanceof Sdk7FontObject)
|
|
{
|
|
fontObject = (Sdk7FontObject) font;
|
|
paint = fontObject.typeface.typefacePaint;
|
|
}
|
|
else
|
|
paint = ((Sdk7FontEntity) font).typeface.typefacePaint;
|
|
|
|
paint.setTextSize (10);
|
|
|
|
if (Character.isWhitespace (charCode))
|
|
return 1;
|
|
|
|
missingGlyphWidth = paint.measureText (TOFU_STRING);
|
|
emGlyphWidth = paint.measureText (EM_STRING);
|
|
width = paint.measureText ("" + charCode);
|
|
|
|
if (width == 0f)
|
|
return 0;
|
|
|
|
if (width != missingGlyphWidth)
|
|
return 1;
|
|
|
|
rect1 = new Rect ();
|
|
rect2 = new Rect ();
|
|
|
|
paint.getTextBounds (TOFU_STRING, 0, TOFU_STRING.length (),
|
|
rect1);
|
|
paint.getTextBounds ("" + charCode, 0, 1, rect2);
|
|
return rect1.equals (rect2) ? 0 : 1;
|
|
}
|
|
|
|
private void
|
|
textExtents1 (Sdk7FontObject font, int code, FontMetrics metrics,
|
|
Paint paint, Rect bounds)
|
|
{
|
|
char[] text;
|
|
|
|
text = new char[1];
|
|
text[0] = (char) code;
|
|
|
|
paint.getTextBounds (text, 0, 1, bounds);
|
|
|
|
/* bounds is the bounding box of the glyph corresponding to CODE.
|
|
Translate these into XCharStruct values.
|
|
|
|
The origin is at 0, 0, and lbearing is the distance counting
|
|
rightwards from the origin to the left most pixel in the glyph
|
|
raster. rbearing is the distance between the origin and the
|
|
rightmost pixel in the glyph raster. ascent is the distance
|
|
counting upwards between the the topmost pixel in the glyph
|
|
raster. descent is the distance (once again counting
|
|
downwards) between the origin and the bottommost pixel in the
|
|
glyph raster.
|
|
|
|
width is the distance between the origin and the origin of any
|
|
character to the right. */
|
|
|
|
metrics.lbearing = (short) bounds.left;
|
|
metrics.rbearing = (short) bounds.right;
|
|
metrics.ascent = (short) -bounds.top;
|
|
metrics.descent = (short) bounds.bottom;
|
|
metrics.width = (short) paint.measureText ("" + text[0]);
|
|
}
|
|
|
|
@Override
|
|
public void
|
|
textExtents (FontObject font, int code[], FontMetrics fontMetrics)
|
|
{
|
|
int i;
|
|
Paint paintCache;
|
|
Rect boundsCache;
|
|
Sdk7FontObject fontObject;
|
|
char[] text;
|
|
float width;
|
|
|
|
fontObject = (Sdk7FontObject) font;
|
|
paintCache = fontObject.typeface.typefacePaint;
|
|
paintCache.setTextSize (fontObject.pixelSize);
|
|
boundsCache = new Rect ();
|
|
|
|
if (code.length == 0)
|
|
{
|
|
fontMetrics.lbearing = 0;
|
|
fontMetrics.rbearing = 0;
|
|
fontMetrics.ascent = 0;
|
|
fontMetrics.descent = 0;
|
|
fontMetrics.width = 0;
|
|
}
|
|
else if (code.length == 1)
|
|
textExtents1 ((Sdk7FontObject) font, code[0], fontMetrics,
|
|
paintCache, boundsCache);
|
|
else
|
|
{
|
|
text = new char[code.length];
|
|
|
|
for (i = 0; i < code.length; ++i)
|
|
text[i] = (char) code[i];
|
|
|
|
paintCache.getTextBounds (text, 0, code.length,
|
|
boundsCache);
|
|
width = paintCache.measureText (text, 0, code.length);
|
|
|
|
fontMetrics.lbearing = (short) boundsCache.left;
|
|
fontMetrics.rbearing = (short) boundsCache.right;
|
|
fontMetrics.ascent = (short) -boundsCache.top;
|
|
fontMetrics.descent = (short) boundsCache.bottom;
|
|
fontMetrics.width = (short) Math.round (width);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int
|
|
encodeChar (FontObject fontObject, char charCode)
|
|
{
|
|
return charCode;
|
|
}
|
|
|
|
@Override
|
|
public int
|
|
draw (FontObject fontObject, EmacsGC gc, EmacsDrawable drawable,
|
|
int[] chars, int x, int y, int backgroundWidth,
|
|
boolean withBackground)
|
|
{
|
|
Rect backgroundRect, bounds;
|
|
Sdk7FontObject sdk7FontObject;
|
|
char[] charsArray;
|
|
int i;
|
|
Canvas canvas;
|
|
Paint paint;
|
|
|
|
sdk7FontObject = (Sdk7FontObject) fontObject;
|
|
charsArray = new char[chars.length];
|
|
|
|
for (i = 0; i < chars.length; ++i)
|
|
charsArray[i] = (char) chars[i];
|
|
|
|
backgroundRect = new Rect ();
|
|
backgroundRect.top = y - sdk7FontObject.ascent;
|
|
backgroundRect.left = x;
|
|
backgroundRect.right = x + backgroundWidth;
|
|
backgroundRect.bottom = y + sdk7FontObject.descent;
|
|
|
|
canvas = drawable.lockCanvas ();
|
|
|
|
if (canvas == null)
|
|
return 0;
|
|
|
|
canvas.save ();
|
|
paint = gc.gcPaint;
|
|
|
|
if (gc.real_clip_rects != null)
|
|
{
|
|
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
|
canvas.clipRect (gc.real_clip_rects[i]);
|
|
}
|
|
|
|
paint.setStyle (Paint.Style.FILL);
|
|
|
|
if (withBackground)
|
|
{
|
|
paint.setColor (gc.background | 0xff000000);
|
|
canvas.drawRect (backgroundRect, paint);
|
|
paint.setColor (gc.foreground | 0xff000000);
|
|
}
|
|
|
|
paint.setTextSize (sdk7FontObject.pixelSize);
|
|
paint.setTypeface (sdk7FontObject.typeface.typeface);
|
|
paint.setAntiAlias (true);
|
|
canvas.drawText (charsArray, 0, chars.length, x, y, paint);
|
|
|
|
canvas.restore ();
|
|
bounds = new Rect ();
|
|
paint.getTextBounds (charsArray, 0, chars.length, bounds);
|
|
bounds.offset (x, y);
|
|
bounds.union (backgroundRect);
|
|
drawable.damageRect (bounds);
|
|
paint.setAntiAlias (false);
|
|
return 1;
|
|
}
|
|
};
|