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

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

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

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

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

package malik.emulator.media.graphics;

import malik.emulator.util.*;

public class RasterCanvas extends Object
{
    private static final int OPAQUE = 0x01;
    private static final int SCREEN = 0x02;
    public static final int MIN_SCREEN_WIDTH = 96;
    public static final int MIN_SCREEN_HEIGHT = 128;
    public static final int MAX_SCREEN_WIDTH = 1024;
    public static final int MAX_SCREEN_HEIGHT = 768;
    public static final int TRANSFORM_NONE = 0;
    public static final int TRANSFORM_ROTATE_90 = 1;
    public static final int TRANSFORM_ROTATE_180 = 2;
    public static final int TRANSFORM_ROTATE_270 = 3;
    public static final int TRANSFORM_MIRROR = 4;
    public static final int TRANSFORM_MIRROR_ROTATE_90 = 5;
    public static final int TRANSFORM_MIRROR_ROTATE_180 = 6;
    public static final int TRANSFORM_MIRROR_ROTATE_270 = 7;

    public static final RasterCanvas screen;

    static {
        int scan;
        int size;
        int width;
        int height;
        RasterBuffer buffer;
        RasterBufferDescriptor dst;
        MalikSystem.syscall((long) (dst = new RasterBufferDescriptor()).getDescriptorAddress() << 32, 0x0022);
        scan = dst.scan;
        width = (size = dst.size) & 0xffff;
        height = size >>> 16;
        buffer = RasterBuffer.create(Array.createSystemIntArray(dst.base, scan * MAX_SCREEN_HEIGHT), 0, scan, scan, MAX_SCREEN_HEIGHT, true);
        screen = new RasterCanvas(buffer, width, height, true);
    }

    public static int getGUIElementSize(int type, int subtype, int state) {
        return (int) MalikSystem.syscall((long) ((state & 0xff) << 16 | (subtype & 0xff) << 8 | (type & 0xff)), 0x0024);
    }

    public static int getSystemColor(int index) {
        return (int) MalikSystem.syscall((long) index, 0x0026);
    }

    private boolean sizeChanged;
    private final int flags;
    private int width;
    private int height;
    private PrimitiveRender drawableRender;
    private StringDrawDescriptor stringDescriptor;
    private GUIElementDescriptor elementDescriptor;
    private StretchDrawDescriptor stretchDescriptor;
    private RasterBufferDescriptor rasterDescriptor;
    protected final RasterBuffer buffer;
    protected final Object monitor;

    public RasterCanvas(RasterBuffer buffer) {
        this(buffer, buffer != null ? buffer.getWidth() : 0, buffer != null ? buffer.getHeight() : 0, false);
    }

    public RasterCanvas(RasterBuffer buffer, int width, int height) {
        this(buffer, width, height, false);
    }

    private RasterCanvas(RasterBuffer buffer, int width, int height, boolean screen) {
        if(buffer == null)
        {
            throw new NullPointerException("RasterCanvas: аргумент buffer равен нулевой ссылке.");
        }
        if(width < 1 || width > buffer.getWidth())
        {
            throw new IllegalArgumentException("RasterCanvas: аргумент width выходит из диапазона.");
        }
        if(height < 1 || height > buffer.getHeight())
        {
            throw new IllegalArgumentException("RasterCanvas: аргумент height выходит из диапазона.");
        }
        this.flags = (screen ? SCREEN : 0) | (buffer.isOpaque() ? OPAQUE : 0);
        this.width = width;
        this.height = height;
        this.buffer = buffer;
        this.monitor = new Object();
    }

    public void copyPixels(RasterBuffer src, int transform, int left, int top, int width, int height, Clip clip) {
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент src равен нулевой ссылке.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            int right;
            int bottom;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && (right = left + width) > clipLeft && top < clipBottom && (bottom = top + height) > clipTop)
            {
                int step;
                int length;
                int areaLeft = clipLeft;
                int areaTop = clipTop;
                int areaRight = clipRight;
                int areaBottom = clipBottom;
                int[] thisPixels;
                RasterBuffer thisBuffer = this.buffer;
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                if(areaLeft < left) areaLeft = left;
                if(areaTop < top) areaTop = top;
                if(areaRight > right) areaRight = right;
                if(areaBottom > bottom) areaBottom = bottom;
                thisPixels = thisBuffer.getPixels();
                step = thisBuffer.getScanlength();
                length = areaRight - areaLeft;
                for(int offset = thisBuffer.getOffset() + areaLeft + areaTop * step, i = areaTop; i < areaBottom; offset += step, i++) Array.fill(thisPixels, offset, length, 0);
                srcDescriptor.assignBuffer(src);
                dstDescriptor.assignBuffer(thisBuffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                dstDescriptor.assignAlpha(true);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void copyPixels(RasterBuffer src, int transform, Rectangle region, Clip clip) {
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент src равен нулевой ссылке.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: аргумент transform имеет недопустимое значение.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            int right;
            int bottom;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && (right = left + width) > clipLeft && top < clipBottom && (bottom = top + height) > clipTop)
            {
                int step;
                int length;
                int areaLeft = clipLeft;
                int areaTop = clipTop;
                int areaRight = clipRight;
                int areaBottom = clipBottom;
                int[] thisPixels;
                RasterBuffer thisBuffer = this.buffer;
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                if(areaLeft < left) areaLeft = left;
                if(areaTop < top) areaTop = top;
                if(areaRight > right) areaRight = right;
                if(areaBottom > bottom) areaBottom = bottom;
                thisPixels = thisBuffer.getPixels();
                step = thisBuffer.getScanlength();
                length = areaRight - areaLeft;
                for(int offset = thisBuffer.getOffset() + areaLeft + areaTop * step, i = areaTop; i < areaBottom; offset += step, i++) Array.fill(thisPixels, offset, length, 0);
                srcDescriptor.assignBuffer(src);
                dstDescriptor.assignBuffer(thisBuffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                dstDescriptor.assignAlpha(true);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void copyPixels(RasterBuffer src, int srcLeft, int srcTop, int srcWidth, int srcHeight, int transform, int left, int top, int width, int height, Clip clip) {
        int lim;
        int size;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент src равен нулевой ссылке.");
        }
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            int right;
            int bottom;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && (right = left + width) > clipLeft && top < clipBottom && (bottom = top + height) > clipTop)
            {
                int step;
                int length;
                int areaLeft = clipLeft;
                int areaTop = clipTop;
                int areaRight = clipRight;
                int areaBottom = clipBottom;
                int[] thisPixels;
                RasterBuffer thisBuffer = this.buffer;
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                if(areaLeft < left) areaLeft = left;
                if(areaTop < top) areaTop = top;
                if(areaRight > right) areaRight = right;
                if(areaBottom > bottom) areaBottom = bottom;
                thisPixels = thisBuffer.getPixels();
                step = thisBuffer.getScanlength();
                length = areaRight - areaLeft;
                for(int offset = thisBuffer.getOffset() + areaLeft + areaTop * step, i = areaTop; i < areaBottom; offset += step, i++) Array.fill(thisPixels, offset, length, 0);
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(thisBuffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                dstDescriptor.assignAlpha(true);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void copyPixels(RasterBuffer src, int srcLeft, int srcTop, int srcWidth, int srcHeight, int transform, Rectangle region, Clip clip) {
        int lim;
        int size;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент src равен нулевой ссылке.");
        }
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: аргумент transform имеет недопустимое значение.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            int right;
            int bottom;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && (right = left + width) > clipLeft && top < clipBottom && (bottom = top + height) > clipTop)
            {
                int step;
                int length;
                int areaLeft = clipLeft;
                int areaTop = clipTop;
                int areaRight = clipRight;
                int areaBottom = clipBottom;
                int[] thisPixels;
                RasterBuffer thisBuffer = this.buffer;
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                if(areaLeft < left) areaLeft = left;
                if(areaTop < top) areaTop = top;
                if(areaRight > right) areaRight = right;
                if(areaBottom > bottom) areaBottom = bottom;
                thisPixels = thisBuffer.getPixels();
                step = thisBuffer.getScanlength();
                length = areaRight - areaLeft;
                for(int offset = thisBuffer.getOffset() + areaLeft + areaTop * step, i = areaTop; i < areaBottom; offset += step, i++) Array.fill(thisPixels, offset, length, 0);
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(thisBuffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                dstDescriptor.assignAlpha(true);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void copyPixels(RasterBuffer src, Rectangle srcRegion, int transform, int left, int top, int width, int height, Clip clip) {
        int lim;
        int size;
        int srcLeft;
        int srcTop;
        int srcWidth;
        int srcHeight;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент src равен нулевой ссылке.");
        }
        if(srcRegion == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент srcRegion равен нулевой ссылке.");
        }
        srcLeft = srcRegion.getLeft();
        srcTop = srcRegion.getTop();
        srcWidth = srcRegion.getWidth();
        srcHeight = srcRegion.getHeight();
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            int right;
            int bottom;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && (right = left + width) > clipLeft && top < clipBottom && (bottom = top + height) > clipTop)
            {
                int step;
                int length;
                int areaLeft = clipLeft;
                int areaTop = clipTop;
                int areaRight = clipRight;
                int areaBottom = clipBottom;
                int[] thisPixels;
                RasterBuffer thisBuffer = this.buffer;
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                if(areaLeft < left) areaLeft = left;
                if(areaTop < top) areaTop = top;
                if(areaRight > right) areaRight = right;
                if(areaBottom > bottom) areaBottom = bottom;
                thisPixels = thisBuffer.getPixels();
                step = thisBuffer.getScanlength();
                length = areaRight - areaLeft;
                for(int offset = thisBuffer.getOffset() + areaLeft + areaTop * step, i = areaTop; i < areaBottom; offset += step, i++) Array.fill(thisPixels, offset, length, 0);
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(thisBuffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                dstDescriptor.assignAlpha(true);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void copyPixels(RasterBuffer src, Rectangle srcRegion, int transform, Rectangle region, Clip clip) {
        int lim;
        int size;
        int srcLeft;
        int srcTop;
        int srcWidth;
        int srcHeight;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент src равен нулевой ссылке.");
        }
        if(srcRegion == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент srcRegion равен нулевой ссылке.");
        }
        srcLeft = srcRegion.getLeft();
        srcTop = srcRegion.getTop();
        srcWidth = srcRegion.getWidth();
        srcHeight = srcRegion.getHeight();
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.copyPixels: аргумент transform имеет недопустимое значение.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.copyPixels: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            int right;
            int bottom;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && (right = left + width) > clipLeft && top < clipBottom && (bottom = top + height) > clipTop)
            {
                int step;
                int length;
                int areaLeft = clipLeft;
                int areaTop = clipTop;
                int areaRight = clipRight;
                int areaBottom = clipBottom;
                int[] thisPixels;
                RasterBuffer thisBuffer = this.buffer;
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                if(areaLeft < left) areaLeft = left;
                if(areaTop < top) areaTop = top;
                if(areaRight > right) areaRight = right;
                if(areaBottom > bottom) areaBottom = bottom;
                thisPixels = thisBuffer.getPixels();
                step = thisBuffer.getScanlength();
                length = areaRight - areaLeft;
                for(int offset = thisBuffer.getOffset() + areaLeft + areaTop * step, i = areaTop; i < areaBottom; offset += step, i++) Array.fill(thisPixels, offset, length, 0);
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(thisBuffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                dstDescriptor.assignAlpha(true);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawPixels(RasterBuffer src, int transform, int left, int top, int width, int height, Clip clip) {
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент src равен нулевой ссылке.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                srcDescriptor.assignBuffer(src);
                dstDescriptor.assignBuffer(this.buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawPixels(RasterBuffer src, int transform, Rectangle region, Clip clip) {
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент src равен нулевой ссылке.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                srcDescriptor.assignBuffer(src);
                dstDescriptor.assignBuffer(this.buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, TRANSFORM_NONE, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawPixels(RasterBuffer src, int srcLeft, int srcTop, int srcWidth, int srcHeight, int transform, int left, int top, int width, int height, Clip clip) {
        int lim;
        int size;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент src равен нулевой ссылке.");
        }
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(this.buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawPixels(RasterBuffer src, int srcLeft, int srcTop, int srcWidth, int srcHeight, int transform, Rectangle region, Clip clip) {
        int lim;
        int size;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент src равен нулевой ссылке.");
        }
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(this.buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, TRANSFORM_NONE, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawPixels(RasterBuffer src, Rectangle srcRegion, int transform, int left, int top, int width, int height, Clip clip) {
        int lim;
        int size;
        int srcLeft;
        int srcTop;
        int srcWidth;
        int srcHeight;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент src равен нулевой ссылке.");
        }
        if(srcRegion == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент srcRegion равен нулевой ссылке.");
        }
        srcLeft = srcRegion.getLeft();
        srcTop = srcRegion.getTop();
        srcWidth = srcRegion.getWidth();
        srcHeight = srcRegion.getHeight();
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(this.buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, transform, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawPixels(RasterBuffer src, Rectangle srcRegion, int transform, Rectangle region, Clip clip) {
        int lim;
        int size;
        int srcLeft;
        int srcTop;
        int srcWidth;
        int srcHeight;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент clip равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент src равен нулевой ссылке.");
        }
        if(srcRegion == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент srcRegion равен нулевой ссылке.");
        }
        srcLeft = srcRegion.getLeft();
        srcTop = srcRegion.getTop();
        srcWidth = srcRegion.getWidth();
        srcHeight = srcRegion.getHeight();
        if(
            (lim = srcLeft + srcWidth) > (size = src.getWidth()) || lim < srcLeft || srcLeft > size || srcLeft < 0 ||
            (lim = srcTop + srcHeight) > (size = src.getHeight()) || lim < srcTop || srcTop > size || srcTop < 0
        )
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: заданный регион выходит за пределы буфера.");
        }
        if(transform < 0 || transform > 7)
        {
            throw new IllegalArgumentException("RasterCanvas.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.drawPixels: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor srcDescriptor = getRasterDescriptor();
                StretchDrawDescriptor dstDescriptor = getStretchDescriptor();
                srcDescriptor.assignBuffer(src, srcLeft, srcTop, srcWidth, srcHeight);
                dstDescriptor.assignBuffer(this.buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dstDescriptor.assignStretch(srcDescriptor, TRANSFORM_NONE, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dstDescriptor.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawGUIElement(int type, int subtype, int state, int left, int top, int width, int height, Clip clip) {
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawGUIElement: аргумент clip равен нулевой ссылке.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                GUIElementDescriptor dst = getElementDescriptor();
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignGUIElement(type, subtype, state, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x0025);
            }
        }
    }

    public void drawGUIElement(int type, int subtype, int state, Rectangle region, Clip clip) {
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(clip == null)
        {
            throw new NullPointerException("RasterCanvas.drawGUIElement: аргумент clip равен нулевой ссылке.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.drawGUIElement: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        left += clip.getTranslateX();
        top += clip.getTranslateY();
        clipLeft = clip.getLeft();
        clipTop = clip.getTop();
        clipRight = clipLeft + clip.getWidth();
        clipBottom = clipTop + clip.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                GUIElementDescriptor dst = getElementDescriptor();
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignGUIElement(type, subtype, state, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x0025);
            }
        }
    }

    public void drawCharacter(int charCode, int x, int y, Paint paint) {
        boolean underline;
        boolean strikeout;
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int error;
        SystemFont font;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacter: аргумент paint равен нулевой ссылке.");
        }

        /* реализация метода */
        if(paint instanceof TextPaint)
        {
            TextPaint tpaint;
            font = (tpaint = (TextPaint) paint).getFont();
            underline = tpaint.isUnderline();
            strikeout = tpaint.isStrikeout();
        } else
        {
            font = SystemFont.getDefault();
            underline = false;
            strikeout = false;
        }
        error = 0;
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                StringDrawDescriptor dst;
                (dst = getStringDescriptor()).assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignString(false, MalikSystem.getLocalVariableAddress(charCode), 1, x - clipLeft, y - clipTop, color, font.getHandle(), underline, strikeout, alpha);
                if(font.isSystem())
                {
                    MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                } else
                {
                    synchronized(SystemFont.monitor())
                    {
                        if(!font.isInstalled())
                        {
                            error = 1;
                        } else
                        {
                            MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                        }
                    }
                }
            }
        }
        if(error == 1)
        {
            throw new UninstalledFontException("RasterCanvas.drawCharacter: заданный шрифт был удалён из системы.");
        }
    }

    public void drawCharacters(char[] src, int x, int y, Paint paint) {
        boolean underline;
        boolean strikeout;
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int error;
        int length;
        SystemFont font;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент paint равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент src равен нулевой ссылке.");
        }
        length = src.length;

        /* реализация метода */
        if(paint instanceof TextPaint)
        {
            TextPaint tpaint;
            font = (tpaint = (TextPaint) paint).getFont();
            underline = tpaint.isUnderline();
            strikeout = tpaint.isStrikeout();
        } else
        {
            font = SystemFont.getDefault();
            underline = false;
            strikeout = false;
        }
        error = 0;
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                StringDrawDescriptor dst;
                (dst = getStringDescriptor()).assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignString(true, Array.getFirstElementAddress(src), length, x - clipLeft, y - clipTop, color, font.getHandle(), underline, strikeout, alpha);
                if(font.isSystem())
                {
                    if(length > 0) MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                } else
                {
                    synchronized(SystemFont.monitor())
                    {
                        if(!font.isInstalled())
                        {
                            error = 1;
                        }
                        else if(length > 0)
                        {
                            MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                        }
                    }
                }
            }
        }
        if(error == 1)
        {
            throw new UninstalledFontException("RasterCanvas.drawCharacters: заданный шрифт был удалён из системы.");
        }
    }

    public void drawCharacters(char[] src, int offset, int length, int x, int y, Paint paint) {
        boolean underline;
        boolean strikeout;
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int error;
        SystemFont font;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент paint равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент src равен нулевой ссылке.");
        }
        Array.checkBound("RasterCanvas.drawCharacters", src.length, offset, length);

        /* реализация метода */
        if(paint instanceof TextPaint)
        {
            TextPaint tpaint;
            font = (tpaint = (TextPaint) paint).getFont();
            underline = tpaint.isUnderline();
            strikeout = tpaint.isStrikeout();
        } else
        {
            font = SystemFont.getDefault();
            underline = false;
            strikeout = false;
        }
        error = 0;
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                StringDrawDescriptor dst;
                (dst = getStringDescriptor()).assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignString(true, Array.getFirstElementAddress(src) + (offset << 1), length, x - clipLeft, y - clipTop, color, font.getHandle(), underline, strikeout, alpha);
                if(font.isSystem())
                {
                    if(length > 0) MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                } else
                {
                    synchronized(SystemFont.monitor())
                    {
                        if(!font.isInstalled())
                        {
                            error = 1;
                        }
                        else if(length > 0)
                        {
                            MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                        }
                    }
                }
            }
        }
        if(error == 1)
        {
            throw new UninstalledFontException("RasterCanvas.drawCharacters: заданный шрифт был удалён из системы.");
        }
    }

    public void drawCharacters(int[] src, int x, int y, Paint paint) {
        boolean underline;
        boolean strikeout;
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int error;
        int length;
        SystemFont font;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент paint равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент src равен нулевой ссылке.");
        }
        length = src.length;

        /* реализация метода */
        if(paint instanceof TextPaint)
        {
            TextPaint tpaint;
            font = (tpaint = (TextPaint) paint).getFont();
            underline = tpaint.isUnderline();
            strikeout = tpaint.isStrikeout();
        } else
        {
            font = SystemFont.getDefault();
            underline = false;
            strikeout = false;
        }
        error = 0;
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                StringDrawDescriptor dst;
                (dst = getStringDescriptor()).assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignString(false, Array.getFirstElementAddress(src), length, x - clipLeft, y - clipTop, color, font.getHandle(), underline, strikeout, alpha);
                if(font.isSystem())
                {
                    if(length > 0) MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                } else
                {
                    synchronized(SystemFont.monitor())
                    {
                        if(!font.isInstalled())
                        {
                            error = 1;
                        }
                        else if(length > 0)
                        {
                            MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                        }
                    }
                }
            }
        }
        if(error == 1)
        {
            throw new UninstalledFontException("RasterCanvas.drawCharacters: заданный шрифт был удалён из системы.");
        }
    }

    public void drawCharacters(int[] src, int offset, int length, int x, int y, Paint paint) {
        boolean underline;
        boolean strikeout;
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int error;
        SystemFont font;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент paint равен нулевой ссылке.");
        }
        if(src == null)
        {
            throw new NullPointerException("RasterCanvas.drawCharacters: аргумент src равен нулевой ссылке.");
        }
        Array.checkBound("RasterCanvas.drawCharacters", src.length, offset, length);

        /* реализация метода */
        if(paint instanceof TextPaint)
        {
            TextPaint tpaint;
            font = (tpaint = (TextPaint) paint).getFont();
            underline = tpaint.isUnderline();
            strikeout = tpaint.isStrikeout();
        } else
        {
            font = SystemFont.getDefault();
            underline = false;
            strikeout = false;
        }
        error = 0;
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                StringDrawDescriptor dst;
                (dst = getStringDescriptor()).assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignString(false, Array.getFirstElementAddress(src) + (offset << 1), length, x - clipLeft, y - clipTop, color, font.getHandle(), underline, strikeout, alpha);
                if(font.isSystem())
                {
                    if(length > 0) MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                } else
                {
                    synchronized(SystemFont.monitor())
                    {
                        if(!font.isInstalled())
                        {
                            error = 1;
                        }
                        else if(length > 0)
                        {
                            MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                        }
                    }
                }
            }
        }
        if(error == 1)
        {
            throw new UninstalledFontException("RasterCanvas.drawCharacters: заданный шрифт был удалён из системы.");
        }
    }

    public void drawString(String string, int x, int y, Paint paint) {
        boolean underline;
        boolean strikeout;
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int error;
        int length;
        SystemFont font;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawString: аргумент paint равен нулевой ссылке.");
        }
        if(string == null)
        {
            throw new NullPointerException("RasterCanvas.drawString: аргумент string равен нулевой ссылке.");
        }
        length = string.length();

        /* реализация метода */
        if(paint instanceof TextPaint)
        {
            TextPaint tpaint;
            font = (tpaint = (TextPaint) paint).getFont();
            underline = tpaint.isUnderline();
            strikeout = tpaint.isStrikeout();
        } else
        {
            font = SystemFont.getDefault();
            underline = false;
            strikeout = false;
        }
        error = 0;
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                StringDrawDescriptor dst;
                (dst = getStringDescriptor()).assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignString(true, Array.getFirstElementAddress(string), length, x - clipLeft, y - clipTop, color, font.getHandle(), underline, strikeout, alpha);
                if(font.isSystem())
                {
                    if(length > 0) MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                } else
                {
                    synchronized(SystemFont.monitor())
                    {
                        if(!font.isInstalled())
                        {
                            error = 1;
                        }
                        else if(length > 0)
                        {
                            MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                        }
                    }
                }
            }
        }
        if(error == 1)
        {
            throw new UninstalledFontException("RasterCanvas.drawString: заданный шрифт был удалён из системы.");
        }
    }

    public void drawSubstring(String string, int offset, int length, int x, int y, Paint paint) {
        boolean underline;
        boolean strikeout;
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int error;
        SystemFont font;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawSubstring: аргумент paint равен нулевой ссылке.");
        }
        if(string == null)
        {
            throw new NullPointerException("RasterCanvas.drawSubstring: аргумент string равен нулевой ссылке.");
        }
        String.checkBound("RasterCanvas.drawSubstring", string.length(), offset, length);

        /* реализация метода */
        if(paint instanceof TextPaint)
        {
            TextPaint tpaint;
            font = (tpaint = (TextPaint) paint).getFont();
            underline = tpaint.isUnderline();
            strikeout = tpaint.isStrikeout();
        } else
        {
            font = SystemFont.getDefault();
            underline = false;
            strikeout = false;
        }
        error = 0;
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                StringDrawDescriptor dst;
                (dst = getStringDescriptor()).assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignString(true, Array.getFirstElementAddress(string) + (offset << 1), length, x - clipLeft, y - clipTop, color, font.getHandle(), underline, strikeout, alpha);
                if(font.isSystem())
                {
                    if(length > 0) MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                } else
                {
                    synchronized(SystemFont.monitor())
                    {
                        if(!font.isInstalled())
                        {
                            error = 1;
                        }
                        else if(length > 0)
                        {
                            MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x002d);
                        }
                    }
                }
            }
        }
        if(error == 1)
        {
            throw new UninstalledFontException("RasterCanvas.drawSubstring: заданный шрифт был удалён из системы.");
        }
    }

    public void drawPixel(int x, int y, Paint paint) {
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawHorizontalLine: аргумент paint равен нулевой ссылке.");
        }

        /* реализация метода */
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && x < clipRight && x >= clipLeft && y < clipBottom && y >= clipTop)
            {
                RasterBufferDescriptor src = getRasterDescriptor();
                StretchDrawDescriptor dst = getStretchDescriptor();
                src.assignBuffer(MalikSystem.getLocalVariableAddress(color), 1, 1, 1, alpha);
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignStretch(src, TRANSFORM_NONE, x - clipLeft, y - clipTop, 1, 1);
                MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawHorizontalLine(int x, int y, int length, Paint paint) {
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawHorizontalLine: аргумент paint равен нулевой ссылке.");
        }
        if(length <= 0) return;

        /* реализация метода */
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && x < clipRight && x + length > clipLeft && y < clipBottom && y >= clipTop)
            {
                RasterBufferDescriptor src = getRasterDescriptor();
                StretchDrawDescriptor dst = getStretchDescriptor();
                src.assignBuffer(MalikSystem.getLocalVariableAddress(color), 1, 1, 1, alpha);
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignStretch(src, TRANSFORM_NONE, x - clipLeft, y - clipTop, length, 1);
                MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawVerticalLine(int x, int y, int length, Paint paint) {
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawVerticalLine: аргумент paint равен нулевой ссылке.");
        }
        if(length <= 0) return;

        /* реализация метода */
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && x < clipRight && x >= clipLeft && y < clipBottom && y + length > clipTop)
            {
                RasterBufferDescriptor src = getRasterDescriptor();
                StretchDrawDescriptor dst = getStretchDescriptor();
                src.assignBuffer(MalikSystem.getLocalVariableAddress(color), 1, 1, 1, alpha);
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignStretch(src, TRANSFORM_NONE, x - clipLeft, y - clipTop, 1, length);
                MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void drawCustom(Drawable figure, int x, int y, Paint paint) {
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.drawCustom: аргумент paint равен нулевой ссылке.");
        }
        if(figure == null)
        {
            throw new NullPointerException("RasterCanvas.drawCustom: аргумент figure равен нулевой ссылке.");
        }

        /* реализация метода */
        alpha = paint.hasAlpha();
        color = paint.getColor();
        x += paint.getTranslateX();
        y += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom)
            {
                RasterBufferDescriptor src = getRasterDescriptor();
                StretchDrawDescriptor dst = getStretchDescriptor();
                src.assignBuffer(MalikSystem.getLocalVariableAddress(color), 1, 1, 1, alpha);
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                figure.draw(getDrawableRender(x - clipLeft, y - clipTop));
            }
        }
    }

    public void fillRectangle(int left, int top, int width, int height, Paint paint) {
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.fillRectangle: аргумент paint равен нулевой ссылке.");
        }
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        alpha = paint.hasAlpha();
        color = paint.getColor();
        left += paint.getTranslateX();
        top += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor src = getRasterDescriptor();
                StretchDrawDescriptor dst = getStretchDescriptor();
                src.assignBuffer(MalikSystem.getLocalVariableAddress(color), 1, 1, 1, alpha);
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignStretch(src, TRANSFORM_NONE, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void fillRectangle(Rectangle region, Paint paint) {
        boolean alpha;
        int clipLeft;
        int clipTop;
        int clipRight;
        int clipBottom;
        int color;
        int left;
        int top;
        int width;
        int height;

        /* проверка данных */
        if(paint == null)
        {
            throw new NullPointerException("RasterCanvas.fillRectangle: аргумент paint равен нулевой ссылке.");
        }
        if(region == null)
        {
            throw new NullPointerException("RasterCanvas.fillRectangle: аргумент region равен нулевой ссылке.");
        }
        left = region.getLeft();
        top = region.getTop();
        width = region.getWidth();
        height = region.getHeight();
        if(width <= 0 || height <= 0) return;

        /* реализация метода */
        alpha = paint.hasAlpha();
        color = paint.getColor();
        left += paint.getTranslateX();
        top += paint.getTranslateY();
        clipLeft = paint.getLeft();
        clipTop = paint.getTop();
        clipRight = clipLeft + paint.getWidth();
        clipBottom = clipTop + paint.getHeight();
        if(clipLeft < 0) clipLeft = 0;
        if(clipTop < 0) clipTop = 0;
        synchronized(monitor)
        {
            int len;
            if(clipRight > (len = this.width)) clipRight = len;
            if(clipBottom > (len = this.height)) clipBottom = len;
            if(clipLeft < clipRight && clipTop < clipBottom && left < clipRight && left + width > clipLeft && top < clipBottom && top + height > clipTop)
            {
                RasterBufferDescriptor src = getRasterDescriptor();
                StretchDrawDescriptor dst = getStretchDescriptor();
                src.assignBuffer(MalikSystem.getLocalVariableAddress(color), 1, 1, 1, alpha);
                dst.assignBuffer(buffer, clipLeft, clipTop, clipRight - clipLeft, clipBottom - clipTop);
                dst.assignStretch(src, TRANSFORM_NONE, left - clipLeft, top - clipTop, width, height);
                MalikSystem.syscall((long) dst.getDescriptorAddress(), 0x0027);
            }
        }
    }

    public void setSize(int width, int height) {
        int error;
        if(width < 1)
        {
            throw new IllegalArgumentException("RasterCanvas.setSize: аргумент width выходит из диапазона.");
        }
        if(height < 1)
        {
            throw new IllegalArgumentException("RasterCanvas.setSize: аргумент height выходит из диапазона.");
        }
        error = 0;
        synchronized(monitor)
        {
            label0:
            {
                RasterBuffer b = buffer;
                if(width > b.getWidth())
                {
                    error = 1;
                    break label0;
                }
                if(height > b.getHeight())
                {
                    error = 2;
                    break label0;
                }
                sizeChanged = true;
                this.width = width;
                this.height = height;
            }
        }
        switch(error)
        {
        case 1:
            throw new IllegalArgumentException("RasterCanvas.setSize: аргумент width выходит из диапазона.");
        case 2:
            throw new IllegalArgumentException("RasterCanvas.setSize: аргумент height выходит из диапазона.");
        }
    }

    public final void getPixels(RasterBuffer buffer, int left, int top) {
        int error;
        if(buffer == null)
        {
            throw new NullPointerException("RasterCanvas.getPixels: аргумент buffer равен нулевой ссылке.");
        }
        error = 0;
        synchronized(monitor)
        {
            label0:
            {
                int lim;
                int len;
                int istep;
                int jstep;
                int width;
                int height;
                int[] pixels;
                int[] thisPixels;
                RasterBuffer thisBuffer;
                if((lim = left + (width = buffer.getWidth())) > (len = this.width) || lim < left || left > len || left < 0)
                {
                    error = 1;
                    break label0;
                }
                if((lim = top + (height = buffer.getHeight())) > (len = this.height) || lim < top || top > len || top < 0)
                {
                    error = 1;
                    break label0;
                }
                thisBuffer = this.buffer;
                pixels = buffer.getPixels();
                jstep = buffer.getScanlength();
                istep = thisBuffer.getScanlength();
                thisPixels = thisBuffer.getPixels();
                for(int i = thisBuffer.getOffset() + left + top * istep, j = buffer.getOffset(), k = height; k-- > 0; i += istep, j += jstep) Array.copy(thisPixels, i, pixels, j, width);
            }
        }
        if(error == 1)
        {
            throw new IllegalArgumentException("RasterCanvas.getPixels: заданный регион выходит за пределы растровой канвы.");
        }
    }

    public final void updateScreen() {
        if((flags & SCREEN) == 0)
        {
            throw new IllegalStateException("RasterCanvas.updateScreen: эта растровая канва не является экраном.");
        }
        if(sizeChanged) synchronized(monitor)
        {
            if(sizeChanged)
            {
                RasterBufferDescriptor r;
                sizeChanged = false;
                (r = getRasterDescriptor()).assignBuffer(buffer, 0, 0, width, height);
                MalikSystem.syscall(0, r.getDescriptorAddress(), 0x0023);
            }
        }
        MalikSystem.syscall(0L, 0x0020);
    }

    public final boolean isScreen() {
        return (flags & SCREEN) != 0;
    }

    public final boolean isOpaque() {
        return (flags & OPAQUE) != 0;
    }

    public final int getWidth() {
        return width;
    }

    public final int getHeight() {
        return height;
    }

    public final RasterBuffer getBuffer() {
        return buffer;
    }

    private PrimitiveRender getDrawableRender(int x, int y) {
        PrimitiveRender result;
        if((result = drawableRender) == null) result = drawableRender = new PrimitiveRender(rasterDescriptor, stretchDescriptor);
        result.setCoordinates(x, y);
        return result;
    }

    private StringDrawDescriptor getStringDescriptor() {
        StringDrawDescriptor result;
        if((result = stringDescriptor) == null) result = stringDescriptor = new StringDrawDescriptor();
        return result;
    }

    private GUIElementDescriptor getElementDescriptor() {
        GUIElementDescriptor result;
        if((result = elementDescriptor) == null) result = elementDescriptor = new GUIElementDescriptor();
        return result;
    }

    private StretchDrawDescriptor getStretchDescriptor() {
        StretchDrawDescriptor result;
        if((result = stretchDescriptor) == null) result = stretchDescriptor = new StretchDrawDescriptor();
        return result;
    }

    private RasterBufferDescriptor getRasterDescriptor() {
        RasterBufferDescriptor result;
        if((result = rasterDescriptor) == null) result = rasterDescriptor = new RasterBufferDescriptor();
        return result;
    }
}

class RasterBufferDescriptor extends SystemDescriptor
{
    public int base;
    public int scan;
    public int size;
    public int alpha;

    public RasterBufferDescriptor() {
    }

    public final void assignAlpha(boolean alpha) {
        this.alpha = alpha ? 1 : 0;
    }

    public final void assignBuffer(int base, int scan, int width, int height, boolean alpha) {
        this.base = base;
        this.scan = scan;
        this.size = width & 0xffff | height << 16;
        this.alpha = alpha ? 1 : 0;
    }

    public final void assignBuffer(RasterBuffer buffer) {
        this.base = buffer.getBase();
        this.scan = buffer.getScanlength();
        this.size = buffer.getSize();
        this.alpha = buffer.isOpaque() ? 0 : 1;
    }

    public final void assignBuffer(RasterBuffer buffer, int left, int top, int width, int height) {
        int s;
        this.base = buffer.getBase() + ((left + top * (s = buffer.getScanlength())) << 2);
        this.scan = s;
        this.size = width & 0xffff | height << 16;
        this.alpha = buffer.isOpaque() ? 0 : 1;
    }
}

class GUIElementDescriptor extends RasterBufferDescriptor
{
    public int origin;
    public int size;
    public int element;

    public GUIElementDescriptor() {
    }

    public final void assignGUIElement(int type, int subtype, int state, int left, int top, int width, int height) {
        this.origin = left & 0xffff | top << 16;
        this.size = width & 0xffff | height << 16;
        this.element = type & 0xff | (subtype & 0xff) << 8 | (state & 0xff) << 16;
    }
}

class StretchDrawDescriptor extends RasterBufferDescriptor
{
    public int origin;
    public int size;
    public int srcBase;
    public int srcScan;
    public int srcSize;
    public int srcAlpha;
    public int transform;

    public StretchDrawDescriptor() {
    }

    public final void assignStretch(RasterBufferDescriptor source, int transform, int left, int top, int width, int height) {
        this.origin = left & 0xffff | top << 16;
        this.size = width & 0xffff | height << 16;
        this.srcBase = source.base;
        this.srcScan = source.scan;
        this.srcSize = source.size;
        this.srcAlpha = source.alpha;
        this.transform = transform & 0x07;
    }
}

class StringDrawDescriptor extends RasterBufferDescriptor
{
    public int handle;
    public int style;
    public int coords;
    public int color;
    public int length;
    public int chars;

    public StringDrawDescriptor() {
    }

    public final void assignString(boolean utf16, int address, int length, int handle) {
        this.handle = handle;
        this.style = utf16 ? 0x80000000 : 0;
        this.length = length;
        this.chars = address;
    }

    public final void assignString(boolean utf16, int address, int length, int x, int y, int colorARGB, int handle, boolean underline, boolean strikeout, boolean alpha) {
        this.handle = handle;
        this.style = (utf16 ? 0x80000000 : 0) | (underline ? 0x00000001 : 0) | (strikeout ? 0x00000002 : 0);
        this.coords = x & 0xffff | y << 16;
        this.color = alpha ? colorARGB : colorARGB | 0xff000000;
        this.length = length;
        this.chars = address;
    }
}
