/*
	Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
	и других спецификаций для функционирования компактных приложений на языке
	Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

	Copyright © 2016, 2019 Малик Разработчик

	Это свободная программа: вы можете перераспространять ее и/или изменять
	ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
	в каком она была опубликована Фондом свободного программного обеспечения;
	либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

	Эта программа распространяется в надежде, что она будет полезной,
	но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
	или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
	общественной лицензии GNU.

	Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
	вместе с этой программой. Если это не так, см.
	<https://www.gnu.org/licenses/>.
*/


package javax.microedition.lcdui;

import malik.emulator.media.graphics.*;
import malik.emulator.media.text.*;

public class Graphics extends Object
{
	public static final int HCENTER = 1;
	public static final int VCENTER = 2;
	public static final int LEFT = 4;
	public static final int RIGHT = 8;
	public static final int TOP = 16;
	public static final int BOTTOM = 32;
	public static final int BASELINE = 64;
	public static final int SOLID = 0;
	public static final int DOTTED = 1;

	static int spriteTransformToMalik(int transform)
	{
		switch(transform)
		{
		default:
			return -1;
		case 0:
			return RasterCanvas.TRANSFORM_NONE;
		case 5:
			return RasterCanvas.TRANSFORM_ROTATE_90;
		case 3:
			return RasterCanvas.TRANSFORM_ROTATE_180;
		case 6:
			return RasterCanvas.TRANSFORM_ROTATE_270;
		case 2:
			return RasterCanvas.TRANSFORM_MIRROR;
		case 7:
			return RasterCanvas.TRANSFORM_MIRROR_ROTATE_90;
		case 1:
			return RasterCanvas.TRANSFORM_MIRROR_ROTATE_180;
		case 4:
			return RasterCanvas.TRANSFORM_MIRROR_ROTATE_270;
		}
	}


	private int translateX;
	private int translateY;
	private int clipLeft;
	private int clipTop;
	private int clipWidth;
	private int clipHeight;
	private int color;
	private int stroke;
	private Object[] extensions;
	private Object lock;
	private Font font;
	private RasterCanvas canvas;

	Graphics(GraphicBuffer buffer)
	{
		this.clipWidth = buffer.getWidth();
		this.clipHeight = buffer.getHeight();
		this.lock = new Object();
		this.font = Font.getDefaultFont();
		this.canvas = new RasterCanvas(buffer);
	}

	Graphics(RasterCanvas canvas)
	{
		this.clipWidth = canvas.getWidth();
		this.clipHeight = canvas.getHeight();
		this.lock = new Object();
		this.font = Font.getDefaultFont();
		this.canvas = canvas;
	}

	public void copyArea(int left, int top, int width, int height, int x, int y, int anchor)
	{
		int lim;
		int len;
		int tx;
		int ty;
		RasterCanvas canvas;
		if((canvas = this.canvas).isOpaque())
		{
			throw new IllegalStateException("Graphics.copyArea: " +
					"эта растровая канва представляет экран устройства, " +
					"поэтому её пикселы читать нельзя.");
		}
		if(width <= 0 || height <= 0)
		{
			return;
		}
		if((lim = (left += (tx = translateX)) + width) > (len = canvas.getWidth()) ||
				lim < left || left > len || left < 0 ||
				(lim = (top += (ty = translateY)) + height) > (len = canvas.getHeight()) ||
				lim < top || top > len || top < 0)
		{
			throw new IllegalArgumentException("Graphics.copyArea: " +
					"заданная прямоугольная область выходит за пределы растровой канвы.");
		}
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.copyArea: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			break;
		case LEFT | VCENTER:
			y -= height / 2;
			break;
		case LEFT | BOTTOM:
			y -= height;
			break;
		case HCENTER | TOP:
			x -= width / 2;
			break;
		case HCENTER | VCENTER:
			x -= width / 2;
			y -= height / 2;
			break;
		case HCENTER | BOTTOM:
			x -= width / 2;
			y -= height;
			break;
		case RIGHT | TOP:
			x -= width;
			break;
		case RIGHT | VCENTER:
			x -= width;
			y -= height / 2;
			break;
		case RIGHT | BOTTOM:
			x -= width;
			y -= height;
			break;
		}
		canvas.copyArea(clipLeft, clipTop, clipWidth, clipHeight,
				left, top, width, height, x + tx, y + ty);
	}

	public void drawImage(Image src, int x, int y, int anchor)
	{
		int width;
		int height;
		GraphicBuffer buffer;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawImage: " +
					"параметр src равен нулевой ссылке.");
		}
		width = (buffer = src.getBuffer()).getWidth();
		height = buffer.getHeight();
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawImage: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			break;
		case LEFT | VCENTER:
			y -= height / 2;
			break;
		case LEFT | BOTTOM:
			y -= height;
			break;
		case HCENTER | TOP:
			x -= width / 2;
			break;
		case HCENTER | VCENTER:
			x -= width / 2;
			y -= height / 2;
			break;
		case HCENTER | BOTTOM:
			x -= width / 2;
			y -= height;
			break;
		case RIGHT | TOP:
			x -= width;
			break;
		case RIGHT | VCENTER:
			x -= width;
			y -= height / 2;
			break;
		case RIGHT | BOTTOM:
			x -= width;
			y -= height;
			break;
		}
		canvas.drawPixelsArea(clipLeft, clipTop, clipWidth, clipHeight,
				buffer, 0, 0, width, height, RasterCanvas.TRANSFORM_NONE,
				x + translateX, y + translateY, width, height, true);
	}

	public void drawRegion(Image src, int left, int top, int width, int height, int transform,
			int x, int y, int anchor)
	{
		int lim;
		int len;
		int dstWidth;
		int dstHeight;
		GraphicBuffer buffer;
		RasterCanvas canvas;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawRegion: " +
					"параметр src равен нулевой ссылке.");
		}
		if((buffer = src.getBuffer()) == (canvas = this.canvas).getBuffer())
		{
			throw new IllegalArgumentException("Graphics.drawRegion: " +
					"нельзя рисовать регион изображения на этом же изображении.");
		}
		if(width <= 0 || height <= 0)
		{
			return;
		}
		if((lim = left + width) > (len = buffer.getWidth()) ||
				lim < left || left > len || left < 0 ||
				(lim = top + height) > (len = buffer.getHeight()) ||
				lim < top || top > len || top < 0)
		{
			throw new IllegalArgumentException("Graphics.drawRegion: " +
					"заданная прямоугольная область выходит за пределы растровой канвы.");
		}
		if((transform = spriteTransformToMalik(transform)) < 0)
		{
			throw new IllegalArgumentException("Graphics.drawRegion: " +
					"недопустимое значение параметра transform.");
		}
		if((transform & 1) == 0)
		{
			dstWidth = width;
			dstHeight = height;
		} else
		{
			dstWidth = height;
			dstHeight = width;
		}
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawRegion: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			break;
		case LEFT | VCENTER:
			y -= dstHeight / 2;
			break;
		case LEFT | BOTTOM:
			y -= dstHeight;
			break;
		case HCENTER | TOP:
			x -= dstWidth / 2;
			break;
		case HCENTER | VCENTER:
			x -= dstWidth / 2;
			y -= dstHeight / 2;
			break;
		case HCENTER | BOTTOM:
			x -= dstWidth / 2;
			y -= dstHeight;
			break;
		case RIGHT | TOP:
			x -= dstWidth;
			break;
		case RIGHT | VCENTER:
			x -= dstWidth;
			y -= dstHeight / 2;
			break;
		case RIGHT | BOTTOM:
			x -= dstWidth;
			y -= dstHeight;
			break;
		}
		canvas.drawPixelsArea(clipLeft, clipTop, clipWidth, clipHeight,
				buffer, left, top, width, height, transform,
				x + translateX, y + translateY, dstWidth, dstHeight, true);
	}

	public void drawStretchRegion(Image src, int left, int top, int width, int height,
			int transform, int x, int y, int dstWidth, int dstHeight, int anchor)
	{
		int lim;
		int len;
		GraphicBuffer buffer;
		RasterCanvas canvas;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawStretchRegion: " +
					"параметр src равен нулевой ссылке.");
		}
		if((buffer = src.getBuffer()) == (canvas = this.canvas).getBuffer())
		{
			throw new IllegalArgumentException("Graphics.drawStretchRegion: " +
					"нельзя рисовать регион изображения на этом же изображении.");
		}
		if(width <= 0 || height <= 0 || dstWidth <= 0 || dstHeight <= 0)
		{
			return;
		}
		if((lim = left + width) > (len = buffer.getWidth()) ||
				lim < left || left > len || left < 0 ||
				(lim = top + height) > (len = buffer.getHeight()) ||
				lim < top || top > len || top < 0)
		{
			throw new IllegalArgumentException("Graphics.drawStretchRegion: " +
					"заданная прямоугольная область выходит за пределы растровой канвы.");
		}
		if((transform = spriteTransformToMalik(transform)) < 0)
		{
			throw new IllegalArgumentException("Graphics.drawStretchRegion: " +
					"недопустимое значение параметра transform.");
		}
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawStretchRegion: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			break;
		case LEFT | VCENTER:
			y -= dstHeight / 2;
			break;
		case LEFT | BOTTOM:
			y -= dstHeight;
			break;
		case HCENTER | TOP:
			x -= dstWidth / 2;
			break;
		case HCENTER | VCENTER:
			x -= dstWidth / 2;
			y -= dstHeight / 2;
			break;
		case HCENTER | BOTTOM:
			x -= dstWidth / 2;
			y -= dstHeight;
			break;
		case RIGHT | TOP:
			x -= dstWidth;
			break;
		case RIGHT | VCENTER:
			x -= dstWidth;
			y -= dstHeight / 2;
			break;
		case RIGHT | BOTTOM:
			x -= dstWidth;
			y -= dstHeight;
			break;
		}
		canvas.drawPixelsArea(clipLeft, clipTop, clipWidth, clipHeight,
				buffer, left, top, width, height, transform,
				x + translateX, y + translateY, dstWidth, dstHeight, true);
	}

	public void drawRGB(int[] src, int offset, int scanlength,
			int left, int top, int width, int height, boolean alpha)
	{
		int lim;
		int len;
		int i;
		int length;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawRGB: " +
					"параметр src равен нулевой ссылке.");
		}
		if(width <= 0 || height <= 0)
		{
			return;
		}
		if(scanlength >= 0)
		{
			i = 0;
			length = width + (height - 1) * scanlength;
		} else
		{
			i = (-scanlength) * (height - 1);
			length = width + i;
		}
		offset -= i;
		if((lim = offset + length) > (len = src.length) ||
				lim < offset || offset > len || offset < 0)
		{
			throw new ArrayIndexOutOfBoundsException("Graphics.drawRGB: " +
					"индекс выходит из диапазона.");
		}
		offset += i;
		canvas.drawPixelsArea(clipLeft, clipTop, clipWidth, clipHeight,
				src, offset, scanlength, width, height, RasterCanvas.TRANSFORM_NONE,
				left + translateX, top + translateY, width, height, alpha);
	}

	public void drawElementOfGUI(int type, int subtype, int state,
			int left, int top, int width, int height)
	{
		if(width <= 0 || height <= 0)
		{
			return;
		}
		canvas.drawElementOfGUI(clipLeft, clipTop, clipWidth, clipHeight,
				type, subtype, state, left + translateX, top + translateY, width, height);
	}

	public void drawCharacter(int charCode, int x, int y, int anchor)
	{
		Font font;
		RasterFont rfont = (font = this.font).getReference();
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawCharacter: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			y += rfont.getBaselinePosition();
			break;
		case LEFT | BASELINE:
			break;
		case LEFT | BOTTOM:
			y -= rfont.getBaselineHeight();
			break;
		case HCENTER | TOP:
			x -= rfont.charWidth(charCode) / 2;
			y += rfont.getBaselinePosition();
			break;
		case HCENTER | BASELINE:
			x -= rfont.charWidth(charCode) / 2;
			break;
		case HCENTER | BOTTOM:
			x -= rfont.charWidth(charCode) / 2;
			y -= rfont.getBaselineHeight();
			break;
		case RIGHT | TOP:
			x -= rfont.charWidth(charCode);
			y += rfont.getBaselinePosition();
			break;
		case RIGHT | BASELINE:
			x -= rfont.charWidth(charCode);
			break;
		case RIGHT | BOTTOM:
			x -= rfont.charWidth(charCode);
			y -= rfont.getBaselineHeight();
			break;
		}
		canvas.drawCharacter(clipLeft, clipTop, clipWidth, clipHeight,
				charCode, x + translateX, y + translateY, color,
				rfont, font.isUnderlined(), false, false);
	}

	public void drawCharacters(int[] src, int offset, int length, int x, int y, int anchor)
	{
		int lim;
		int len;
		Font font;
		RasterFont rfont;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawCharacters: " +
					"параметр src равен нулевой ссылке.");
		}
		if((lim = offset + length) > (len = src.length) ||
				lim < offset || offset > len || offset < 0)
		{
			throw new ArrayIndexOutOfBoundsException("Graphics.drawCharacters: " +
					"индекс выходит из диапазона.");
		}
		rfont = (font = this.font).getReference();
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawCharacters: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			y += rfont.getBaselinePosition();
			break;
		case LEFT | BASELINE:
			break;
		case LEFT | BOTTOM:
			y -= rfont.getBaselineHeight();
			break;
		case HCENTER | TOP:
			x -= rfont.charsWidth(src, offset, length) / 2;
			y += rfont.getBaselinePosition();
			break;
		case HCENTER | BASELINE:
			x -= rfont.charsWidth(src, offset, length) / 2;
			break;
		case HCENTER | BOTTOM:
			x -= rfont.charsWidth(src, offset, length) / 2;
			y -= rfont.getBaselineHeight();
			break;
		case RIGHT | TOP:
			x -= rfont.charsWidth(src, offset, length);
			y += rfont.getBaselinePosition();
			break;
		case RIGHT | BASELINE:
			x -= rfont.charsWidth(src, offset, length);
			break;
		case RIGHT | BOTTOM:
			x -= rfont.charsWidth(src, offset, length);
			y -= rfont.getBaselineHeight();
			break;
		}
		canvas.drawString(clipLeft, clipTop, clipWidth, clipHeight,
				src, offset, length, x + translateX, y + translateY, color,
				rfont, font.isUnderlined(), false, false);
	}

	public void drawChar(char src, int x, int y, int anchor)
	{
		Font font;
		RasterFont rfont = (font = this.font).getReference();
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawChar: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			y += rfont.getBaselinePosition();
			break;
		case LEFT | BASELINE:
			break;
		case LEFT | BOTTOM:
			y -= rfont.getBaselineHeight();
			break;
		case HCENTER | TOP:
			x -= rfont.charWidth(src) / 2;
			y += rfont.getBaselinePosition();
			break;
		case HCENTER | BASELINE:
			x -= rfont.charWidth(src) / 2;
			break;
		case HCENTER | BOTTOM:
			x -= rfont.charWidth(src) / 2;
			y -= rfont.getBaselineHeight();
			break;
		case RIGHT | TOP:
			x -= rfont.charWidth(src);
			y += rfont.getBaselinePosition();
			break;
		case RIGHT | BASELINE:
			x -= rfont.charWidth(src);
			break;
		case RIGHT | BOTTOM:
			x -= rfont.charWidth(src);
			y -= rfont.getBaselineHeight();
			break;
		}
		canvas.drawCharacter(clipLeft, clipTop, clipWidth, clipHeight,
				src, x + translateX, y + translateY, color,
				rfont, font.isUnderlined(), false, false);
	}

	public void drawChars(char[] src, int offset, int length, int x, int y, int anchor)
	{
		int lim;
		int len;
		Font font;
		RasterFont rfont;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawChars: " +
					"параметр src равен нулевой ссылке.");
		}
		if((lim = offset + length) > (len = src.length) ||
				lim < offset || offset > len || offset < 0)
		{
			throw new ArrayIndexOutOfBoundsException("Graphics.drawChars: " +
					"индекс выходит из диапазона.");
		}
		rfont = (font = this.font).getReference();
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawChars: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			y += rfont.getBaselinePosition();
			break;
		case LEFT | BASELINE:
			break;
		case LEFT | BOTTOM:
			y -= rfont.getBaselineHeight();
			break;
		case HCENTER | TOP:
			x -= rfont.charsWidth(src, offset, length) / 2;
			y += rfont.getBaselinePosition();
			break;
		case HCENTER | BASELINE:
			x -= rfont.charsWidth(src, offset, length) / 2;
			break;
		case HCENTER | BOTTOM:
			x -= rfont.charsWidth(src, offset, length) / 2;
			y -= rfont.getBaselineHeight();
			break;
		case RIGHT | TOP:
			x -= rfont.charsWidth(src, offset, length);
			y += rfont.getBaselinePosition();
			break;
		case RIGHT | BASELINE:
			x -= rfont.charsWidth(src, offset, length);
			break;
		case RIGHT | BOTTOM:
			x -= rfont.charsWidth(src, offset, length);
			y -= rfont.getBaselineHeight();
			break;
		}
		canvas.drawString(clipLeft, clipTop, clipWidth, clipHeight,
				src, offset, length, x + translateX, y + translateY, color,
				rfont, font.isUnderlined(), false, false);
	}

	public void drawString(String src, int x, int y, int anchor)
	{
		int length;
		Font font;
		RasterFont rfont;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawString: " +
					"параметр src равен нулевой ссылке.");
		}
		rfont = (font = this.font).getReference();
		length = src.length();
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawString: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			y += rfont.getBaselinePosition();
			break;
		case LEFT | BASELINE:
			break;
		case LEFT | BOTTOM:
			y -= rfont.getBaselineHeight();
			break;
		case HCENTER | TOP:
			x -= rfont.substringWidth(src, 0, length) / 2;
			y += rfont.getBaselinePosition();
			break;
		case HCENTER | BASELINE:
			x -= rfont.substringWidth(src, 0, length) / 2;
			break;
		case HCENTER | BOTTOM:
			x -= rfont.substringWidth(src, 0, length) / 2;
			y -= rfont.getBaselineHeight();
			break;
		case RIGHT | TOP:
			x -= rfont.substringWidth(src, 0, length);
			y += rfont.getBaselinePosition();
			break;
		case RIGHT | BASELINE:
			x -= rfont.substringWidth(src, 0, length);
			break;
		case RIGHT | BOTTOM:
			x -= rfont.substringWidth(src, 0, length);
			y -= rfont.getBaselineHeight();
			break;
		}
		canvas.drawString(clipLeft, clipTop, clipWidth, clipHeight,
				src, 0, length, x + translateX, y + translateY, color,
				rfont, font.isUnderlined(), false, false);
	}

	public void drawSubstring(String src, int offset, int length, int x, int y, int anchor)
	{
		int lim;
		int len;
		Font font;
		RasterFont rfont;
		if(src == null)
		{
			throw new NullPointerException("Graphics.drawSubstring: " +
					"параметр src равен нулевой ссылке.");
		}
		if((lim = offset + length) > (len = src.length()) ||
				lim < offset || offset > len || offset < 0)
		{
			throw new StringIndexOutOfBoundsException("Graphics.drawSubstring: " +
					"индекс выходит из диапазона.");
		}
		rfont = (font = this.font).getReference();
		switch(anchor)
		{
		default:
			throw new IllegalArgumentException("Graphics.drawSubstring: " +
					"недопустимое значение параметра anchor.");
		case 0:
		case LEFT | TOP:
			y += rfont.getBaselinePosition();
			break;
		case LEFT | BASELINE:
			break;
		case LEFT | BOTTOM:
			y -= rfont.getBaselineHeight();
			break;
		case HCENTER | TOP:
			x -= rfont.substringWidth(src, offset, length) / 2;
			y += rfont.getBaselinePosition();
			break;
		case HCENTER | BASELINE:
			x -= rfont.substringWidth(src, offset, length) / 2;
			break;
		case HCENTER | BOTTOM:
			x -= rfont.substringWidth(src, offset, length) / 2;
			y -= rfont.getBaselineHeight();
			break;
		case RIGHT | TOP:
			x -= rfont.substringWidth(src, offset, length);
			y += rfont.getBaselinePosition();
			break;
		case RIGHT | BASELINE:
			x -= rfont.substringWidth(src, offset, length);
			break;
		case RIGHT | BOTTOM:
			x -= rfont.substringWidth(src, offset, length);
			y -= rfont.getBaselineHeight();
			break;
		}
		canvas.drawString(clipLeft, clipTop, clipWidth, clipHeight,
				src, offset, length, x + translateX, y + translateY, color,
				rfont, font.isUnderlined(), false, false);
	}

	public void drawLine(int x1, int y1, int x2, int y2)
	{
		int clipLeft;
		int clipRight;
		int clipTop;
		int clipBottom;
		int clipWidth;
		int clipHeight;
		int color;
		int tmp;
		int xerr;
		int yerr;
		int dx;
		int dy;
		int x;
		int y;
		int incx;
		int incy;
		int d;
		int i;
		int ofs;
		int scan;
		int[] pixels;
		GraphicBuffer buffer;
		RasterCanvas canvas = this.canvas;
		clipLeft = Math.max(tmp = this.clipLeft, 0);
		clipRight = Math.min(tmp + this.clipWidth, canvas.getWidth());
		clipTop = Math.max(tmp = this.clipTop, 0);
		clipBottom = Math.min(tmp + this.clipHeight, canvas.getHeight());
		if((clipWidth = clipRight - clipLeft) <= 0 || (clipHeight = clipBottom - clipTop) <= 0)
		{
			return;
		}
		color = this.color | (canvas.isOpaque() ? 0 : 0xff000000);
		x1 += (tmp = translateX);
		x2 += tmp;
		y1 += (tmp = translateY);
		y2 += tmp;
		if(x1 == x2)
		{
			if(y1 <= y2)
			{
				canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
						x1, y1, y2 - y1 + 1, color, false);
				return;
			} else
			{
				canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
						x2, y2, y1 - y2 + 1, color, false);
				return;
			}
		}
		if(y1 == y2)
		{
			if(x1 <= x2)
			{
				canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
						x1, y1, x2 - x1 + 1, color, false);
				return;
			} else
			{
				canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
						x2, y2, x1 - x2 + 1, color, false);
				return;
			}
		}
		x = x1;
		y = y1;
		xerr = 0;
		yerr = 0;
		incx = (dx = x2 - x1) == 0 ? 0 : (dx < 0 ? -1 : 1);
		incy = (dy = y2 - y1) == 0 ? 0 : (dy < 0 ? -1 : 1);
		d = (dx = dx < 0 ? -dx : dx) >= (dy = dy < 0 ? -dy : dy) ? dx : dy;
		ofs = (buffer = canvas.getBuffer()).getOffset();
		scan = buffer.getScanlength();
		pixels = buffer.getPixels();
		for(i = 0; i <= d; i++)
		{
			xerr += dx;
			yerr += dy;
			if(xerr > d)
			{
				xerr -= d;
				x += incx;
			}
			if(yerr > d)
			{
				yerr -= d;
				y += incy;
			}
			if(x >= clipLeft && x < clipRight && y >= clipTop && y < clipBottom)
			{
				pixels[ofs + x + y * scan] = color;
			}
		}
	}

	public void drawRect(int left, int top, int width, int height)
	{
		int clipLeft;
		int clipTop;
		int clipWidth;
		int clipHeight;
		int color;
		RasterCanvas canvas;
		if(width < 0 || height < 0 ||
				(clipWidth = this.clipWidth) <= 0 || (clipHeight = this.clipHeight) <= 0)
		{
			return;
		}
		clipLeft = this.clipLeft;
		clipTop = this.clipTop;
		color = this.color;
		canvas = this.canvas;
		left += translateX;
		top += translateY;
		if(height == 0)
		{
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					left, top, width + 1, color, false);
			return;
		}
		if(width == 0)
		{
			canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
					left, top, height + 1, color, false);
			return;
		}
		canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
				left, top, width, color, false);
		canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
				left, top + 1, height, color, false);
		canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
				left + width, top, height, color, false);
		canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
				left + 1, top + height, width, color, false);
	}

	public void drawRoundRect(int left, int top, int width, int height,
			int arcWidth, int arcHeight)
	{
		double r;
		int clipLeft;
		int clipTop;
		int clipWidth;
		int clipHeight;
		int color;
		int tmp1;
		int tmp2;
		int d;
		int i;
		int j;
		int k;
		int x1;
		int x2;
		int y1;
		int y2;
		long s;
		RasterCanvas canvas;
		if(width < 0 || height < 0 ||
				(clipWidth = this.clipWidth) <= 0 || (clipHeight = this.clipHeight) <= 0)
		{
			return;
		}
		clipLeft = this.clipLeft;
		clipTop = this.clipTop;
		color = this.color;
		canvas = this.canvas;
		left += translateX;
		top += translateY;
		if(arcWidth <= 0 || arcHeight <= 0)
		{
			if(height == 0)
			{
				canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
						left, top, width + 1, color, false);
				return;
			}
			if(width == 0)
			{
				canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
						left, top, height + 1, color, false);
				return;
			}
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					left, top, width, color, false);
			canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
					left, top + 1, height, color, false);
			canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
					left + width, top, height, color, false);
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					left + 1, top + height, width, color, false);
			return;
		}
		if(arcWidth > (tmp1 = width >> 1))
		{
			arcWidth = tmp1;
		}
		if(arcHeight > (tmp2 = height >> 1))
		{
			arcHeight = tmp2;
		}
		canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
				tmp1 = left + arcWidth, top, tmp2 = width - (arcWidth << 1) + 1, color, false);
		canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
				tmp1, top + height, tmp2, color, false);
		canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
				left, tmp1 = top + arcHeight, tmp2 = height - (arcHeight << 1) + 1, color, false);
		canvas.drawVertLine(clipLeft, clipTop, clipWidth, clipHeight,
				left + width, tmp1, tmp2, color, false);
		r = ((double) arcWidth) / ((double) arcHeight);
		s = ((long) arcHeight) * ((long) arcHeight);
		d = arcHeight;
		for(k = arcWidth, i = 1; i < arcHeight; k = j, i++)
		{
			d--;
			j = ((int) Math.intPart(((double) arcWidth) -
					r * Math.sqrt((double) (s - ((long) d) * ((long) d))))) + 1;
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					x1 = left + j, y1 = top + i, tmp1 = k == j ? 1 : k - j, color, false);
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					x1, y2 = top + height - i, tmp1, color, false);
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					x2 = left + width - j - tmp1 + 1, y1, tmp1, color, false);
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					x2, y2, tmp1, color, false);
		}
	}

	public void drawArc(int left, int top, int width, int height,
			int startAngle, int arcAngle)
	{
		System.out.println("Метод " +
				"javax.microedition.lcdui.Graphics.drawArc(int, int, int, int, int, int) " +
				"не реализован.");
	}

	public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
	{
		int clipLeft;
		int clipTop;
		int clipWidth;
		int clipHeight;
		int color;
		int tmp;
		int y;
		int ix;
		int idx;
		int idy;
		int ixerr;
		int iyerr;
		int iincx;
		int iincy;
		int id;
		int jx;
		int jdx;
		int jdy;
		int jxerr;
		int jyerr;
		int jincx;
		int jincy;
		int jd;
		RasterCanvas canvas;
		if((clipWidth = this.clipWidth) <= 0 || (clipHeight = this.clipHeight) <= 0)
		{
			return;
		}
		clipLeft = this.clipLeft;
		clipTop = this.clipTop;
		color = this.color;
		canvas = this.canvas;
		x1 += (tmp = translateX);
		x2 += tmp;
		x3 += tmp;
		y1 += (tmp = translateY);
		y2 += tmp;
		y3 += tmp;
		if(y1 > y3)
		{
			tmp = y1;
			y1 = y3;
			y3 = tmp;
			tmp = x1;
			x1 = x3;
			x3 = tmp;
		}
		if(y1 > y2)
		{
			tmp = y1;
			y1 = y2;
			y2 = tmp;
			tmp = x1;
			x1 = x2;
			x2 = tmp;
		}
		if(y2 > y3)
		{
			tmp = y2;
			y2 = y3;
			y3 = tmp;
			tmp = x2;
			x2 = x3;
			x3 = tmp;
		}
		ix = x1;
		ixerr = 0;
		iyerr = 0;
		iincx = (idx = x2 - x1) == 0 ? 0 : (idx < 0 ? -1 : 1);
		iincy = (idy = y2 - y1) == 0 ? 0 : (idy < 0 ? -1 : 1);
		id = (idx = idx < 0 ? -idx : idx) >= (idy = idy < 0 ? -idy : idy) ? idx : idy;
		jx = x1;
		jxerr = 0;
		jyerr = 0;
		jincx = (jdx = x3 - x1) == 0 ? 0 : (jdx < 0 ? -1 : 1);
		jincy = (jdy = y3 - y1) == 0 ? 0 : (jdy < 0 ? -1 : 1);
		jd = (jdx = jdx < 0 ? -jdx : jdx) >= (jdy = jdy < 0 ? -jdy : jdy) ? jdx : jdy;
		for(y = y1; y <= y3; y++)
		{
			if(y == y2)
			{
				ix = x2;
				ixerr = 0;
				iyerr = 0;
				iincx = (idx = x3 - x2) == 0 ? 0 : (idx < 0 ? -1 : 1);
				iincy = (idy = y3 - y2) == 0 ? 0 : (idy < 0 ? -1 : 1);
				id = (idx = idx < 0 ? -idx : idx) >= (idy = idy < 0 ? -idy : idy) ? idx : idy;
			}
			if(ix <= jx)
			{
				canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
						ix, y, jx - ix + 1, color, false);
			} else
			{
				canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
						jx, y, ix - jx + 1, color, false);
			}
			while(iincy > 0)
			{
				ixerr += idx;
				iyerr += idy;
				if(ixerr > id)
				{
					ixerr -= id;
					ix += iincx;
				}
				if(iyerr > id)
				{
					iyerr -= id;
					break;
				}
			}
			while(jincy > 0)
			{
				jxerr += jdx;
				jyerr += jdy;
				if(jxerr > jd)
				{
					jxerr -= jd;
					jx += jincx;
				}
				if(jyerr > jd)
				{
					jyerr -= jd;
					break;
				}
			}
		}
	}

	public void fillRect(int left, int top, int width, int height)
	{
		int clipWidth;
		int clipHeight;
		if(width <= 0 || height <= 0 ||
				(clipWidth = this.clipWidth) <= 0 || (clipHeight = this.clipHeight) <= 0)
		{
			return;
		}
		canvas.fillRect(clipLeft, clipTop, clipWidth, clipHeight,
				left + translateX, top + translateY, width, height, color, false);
	}

	public void fillRoundRect(int left, int top, int width, int height,
			int arcWidth, int arcHeight)
	{
		double r;
		int clipLeft;
		int clipTop;
		int clipWidth;
		int clipHeight;
		int color;
		int tmp;
		int d;
		int i;
		int j;
		int x;
		long s;
		RasterCanvas canvas;
		if(width <= 0 || height <= 0 ||
				(clipWidth = this.clipWidth) <= 0 || (clipHeight = this.clipHeight) <= 0)
		{
			return;
		}
		clipLeft = this.clipLeft;
		clipTop = this.clipTop;
		color = this.color;
		canvas = this.canvas;
		left += translateX;
		top += translateY;
		if(arcWidth <= 0 || arcHeight <= 0)
		{
			canvas.fillRect(clipLeft, clipTop, clipWidth, clipHeight,
					left, top, width, height, color, false);
			return;
		}
		if(arcWidth > (tmp = width >> 1))
		{
			arcWidth = tmp;
		}
		if(arcHeight > (tmp = height >> 1))
		{
			arcHeight = tmp;
		}
		if((tmp = height - (arcHeight << 1)) > 0)
		{
			canvas.fillRect(clipLeft, clipTop, clipWidth, clipHeight,
					left, top + arcHeight, width, tmp, color, false);
		}
		r = ((double) arcWidth) / ((double) arcHeight);
		s = ((long) arcHeight) * ((long) arcHeight);
		for(d = arcHeight, i = 0; i < arcHeight; d--, i++)
		{
			j = ((int) Math.intPart(((double) arcWidth) -
					r * Math.sqrt((double) (s - ((long) d) * ((long) d))))) + (i != 0 ? 1 : 0);
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					x = left + j, top + i, tmp = width - (j << 1), color, false);
			canvas.drawHorzLine(clipLeft, clipTop, clipWidth, clipHeight,
					x, top + height - i - 1, tmp, color, false);
		}
	}

	public void fillArc(int left, int top, int width, int height,
			int startAngle, int arcAngle)
	{
		System.out.println("Метод " +
				"javax.microedition.lcdui.Graphics.fillArc(int, int, int, int, int, int) " +
				"не реализован.");
	}

	public void reset()
	{
		RasterCanvas canvas = this.canvas;
		this.translateX = 0;
		this.translateY = 0;
		this.clipLeft = 0;
		this.clipTop = 0;
		this.clipWidth = canvas.getWidth();
		this.clipHeight = canvas.getHeight();
		this.color = 0x000000;
		this.stroke = SOLID;
		this.font = Font.getDefaultFont();
	}

	public void translate(int deltaX, int deltaY)
	{
		this.translateX += deltaX;
		this.translateY += deltaY;
	}

	public void clipRect(int left, int top, int width, int height)
	{
		int clipLeft = this.clipLeft;
		int clipTop = this.clipTop;
		int clipWidth = this.clipWidth;
		int clipHeight = this.clipHeight;
		left += translateX;
		top += translateY;
		this.clipWidth = Math.min(left + width, clipLeft + clipWidth) -
				(this.clipLeft = Math.max(left, clipLeft));
		this.clipHeight = Math.min(top + height, clipTop + clipHeight) -
				(this.clipTop = Math.max(top, clipTop));
	}

	public void setClip(int left, int top, int width, int height)
	{
		this.clipLeft = left + translateX;
		this.clipTop = top + translateY;
		this.clipWidth = width;
		this.clipHeight = height;
	}

	public void setColor(int color)
	{
		this.color = color & 0xffffff;
	}

	public void setColor(int red, int green, int blue)
	{
		if(((red | green | blue) & 0xffffff00) != 0)
		{
			throw new IllegalArgumentException("Graphics.setColor: " +
					"все компоненты могут быть только в диапазоне от 0 до 255.");
		}
		this.color = (red << 16) | (green << 8) | blue;
	}

	public void setGrayScale(int value)
	{
		if((value & 0xffffff00) != 0)
		{
			throw new IllegalArgumentException("Graphics.setGrayScale: " +
					"параметр value может быть только в диапазоне от 0 до 255.");
		}
		this.color = (value << 16) | (value << 8) | value;
	}

	public void setStrokeStyle(int stroke)
	{
		if(stroke != SOLID && stroke != DOTTED)
		{
			throw new IllegalArgumentException("Graphics.setStrokeStyle: " +
					"недопустимое значение параметра stroke.");
		}
		this.stroke = stroke;
	}

	public void setFont(Font font)
	{
		this.font = font == null ? Font.getDefaultFont() : font;
	}

	public int getTranslateX()
	{
		return translateX;
	}

	public int getTranslateY()
	{
		return translateY;
	}

	public int getClipX()
	{
		return clipLeft - translateX;
	}

	public int getClipY()
	{
		return clipTop - translateY;
	}

	public int getClipWidth()
	{
		return clipWidth;
	}

	public int getClipHeight()
	{
		return clipHeight;
	}

	public int getColor()
	{
		return color;
	}

	public int getRedComponent()
	{
		return (color >> 16) & 0xff;
	}

	public int getGreenComponent()
	{
		return (color >> 8) & 0xff;
	}

	public int getBlueComponent()
	{
		return color & 0xff;
	}

	public int getGrayScale()
	{
		int c;
		return (76 * (((c = color) >> 16) & 0xff) +
				152 * ((c >> 8) & 0xff) + 28 * (c & 0xff)) >> 8;
	}

	public int getStrokeStyle()
	{
		return stroke;
	}

	public int getDisplayColor(int color)
	{
		return color & 0xffffff;
	}

	public Font getFont()
	{
		return font;
	}

	public final void addExtension(Object extension)
	{
		int i;
		Object[] extensions;
		if(extension == null)
		{
			return;
		}
		synchronized(lock)
		{
			if((extensions = this.extensions) == null)
			{
				extensions = this.extensions = new Object[2];
			}
			if(indexOfExtension(extensions) < 0)
			{
				if((i = indexOfExtension(null)) < 0)
				{
					Array.copy(extensions, 0, extensions = this.extensions =
							new Object[(i = extensions.length) << 1], 0, i);
				}
				extensions[i] = extension;
			}
		}
	}

	public final void removeExtension(Class extensionClass)
	{
		int i;
		Object[] extensions;
		Object extension;
		if(extensionClass == null)
		{
			return;
		}
		synchronized(lock)
		{
			for(i = (extensions = this.extensions) != null ? extensions.length : 0; i-- > 0; )
			{
				if((extension = extensions[i]) != null &&
						extensionClass.isAssignableFrom(extension.getClass()))
				{
					extensions[i] = null;
				}
			}
		}
	}

	public final Object getExtension(Class extensionClass)
	{
		int i;
		Object[] extensions;
		Object extension;
		if(extensionClass == null)
		{
			throw new NullPointerException("Graphics.getExtension: " +
					"параметр extensionClass равен нулевой ссылке.");
		}
		for(i = (extensions = this.extensions) != null ? extensions.length : 0; i-- > 0; )
		{
			if((extension = extensions[i]) != null &&
					extensionClass.isAssignableFrom(extension.getClass()))
			{
				return extension;
			}
		}
		return null;
	}

	public final GraphicBuffer getBuffer()
	{
		return canvas.getBuffer();
	}

	public final RasterCanvas getCanvas()
	{
		return canvas;
	}

	private int indexOfExtension(Object extension)
	{
		int i;
		Object[] extensions;
		for(i = (extensions = this.extensions).length; i-- > 0; )
		{
			if(extensions[i] == extension)
			{
				return i;
			}
		}
		return -1;
		
	}
}
