emacs/java/org/gnu/emacs/EmacsDrawLine.java

161 lines
4.1 KiB
Java

/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
Copyright (C) 2023-2024 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 android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
public final class EmacsDrawLine
{
/* Return the normalized slope and magnitude of a line whose extrema
are DX and DY removed, on the X and Y axes respectively, from its
origin point. */
private static float[]
measureLine (float dx, float dy)
{
float hypot;
if (dx == 0f && dy == 0f)
return new float[] { 0f, 0f, 0f, };
if (dx == 0f)
return new float[] { 0f, dy > 0f ? 1f : -1f, Math.abs (dy), };
else if (dy == 0f)
return new float[] { dx > 0f ? 1f : -1f, 0f, Math.abs (dx), };
else
{
hypot = (float) Math.hypot (dx, dy);
return new float[] { dx / hypot, dy / hypot, hypot, };
}
}
private static void
polyDashPattern (EmacsGC gc, Canvas canvas, Paint paint, float x0,
float y0, float x1, float y1)
{
int patternTotal, i, offset;
float dx, dy, mag, dash_mag, rem, lx1, ly1;
float[] measured;
boolean which;
/* Compute the total length of this pattern. */
patternTotal = 0;
for (i = 0; i < gc.dashes.length; ++i)
patternTotal += gc.dashes[i];
if ((gc.dashes.length & 1) != 0)
patternTotal += patternTotal;
/* Subtract as much of the offset as does not contribute to the
phase at the first pixel of the line. */
offset = gc.dash_offset % patternTotal;
/* Set I to the first dash that ought to be drawn and WHICH to its
phase. */
i = 0;
which = true;
while (offset >= gc.dashes[i])
{
offset -= gc.dashes[i++];
if (i >= gc.dashes.length)
i = 0;
which = !which;
}
/* Compute the length of the first visible segment. */
dash_mag = gc.dashes[i] - offset;
/* Compute the slope of the line. */
dx = x1 - x0;
dy = y1 - y0;
measured = measureLine (dx, dy);
dx = measured[0];
dy = measured[1];
rem = mag = measured[2];
lx1 = x0;
ly1 = y0;
while (rem > 0f)
{
dash_mag = Math.min (dash_mag, rem);
rem -= dash_mag;
/* End of this segment. */
x1 = (mag - rem) * dx + x0;
y1 = (mag - rem) * dy + y0;
if (which)
canvas.drawLine (lx1, ly1, x1, y1, paint);
which = !which;
/* Start of the next segment. */
lx1 = x1;
ly1 = y1;
i++;
if (i >= gc.dashes.length)
i = 0;
dash_mag = gc.dashes[i];
}
}
public static void
perform (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int x2, int y2)
{
Canvas canvas;
Paint paint;
int x0, x1, y0, y1;
/* TODO implement stippling. */
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
return;
/* Calculate the leftmost and rightmost points. */
x0 = Math.min (x, x2 + 1);
x1 = Math.max (x, x2 + 1);
y0 = Math.min (y, y2 + 1);
y1 = Math.max (y, y2 + 1);
/* And the clip rectangle. */
paint = gc.gcPaint;
canvas = drawable.lockCanvas (gc);
if (canvas == null)
return;
if (gc.clip_mask == null)
{
if (gc.line_style != EmacsGC.GC_LINE_ON_OFF_DASH)
canvas.drawLine ((float) x, (float) y, (float) x2, (float) y2,
paint);
else
polyDashPattern (gc, canvas, paint, (float) x, (float) y,
(float) x2, (float) y2);
}
/* DrawLine with clip mask not implemented; it is not used by
Emacs. */
drawable.damageRect (x0, y0, x1, y1);
}
}