<commit_before>/*
 * Copyright <NAME> 2012-2013.
 */

/**
 * @constructor
 * @param {number} id Picture's unique id number.
 * @param {Rect} boundsRect Picture bounds. x and y should always be zero.
 * @param {number} bitmapScale Scale for rasterizing the picture. Events that
 * are pushed to this picture get this scale applied to them.
 * @param {string=} mode Either 'webgl', 'no-texdata-webgl' or 'canvas'.
 * Defaults to 'webgl'.
 * @param {number} currentEventAttachment Which buffer index to attach the
 * picture's current event to. Can be set to -1 if no current event is needed.
 */
var Picture = function(id, boundsRect, bitmapScale, mode,
                       currentEventAttachment) {
    this.id = id;
    if (mode === undefined) {
        mode = 'webgl';
    }
    this.mode = mode;

    this.animating = false;

    this.buffers = [];
    this.currentEventAttachment = currentEventAttachment;
    this.currentEvent = null;
    this.currentEventMode = BrushEvent.Mode.normal;

    this.boundsRect = boundsRect;
    this.bitmapScale = bitmapScale;
    var bitmapWidth = Math.floor(this.boundsRect.width() * this.bitmapScale);
    var bitmapHeight = Math.floor(this.boundsRect.height() * this.bitmapScale);
    this.bitmapRect = new Rect(0, bitmapWidth, 0, bitmapHeight);

    this.container = null;
    this.canvas = document.createElement('canvas');
    this.canvas.width = this.bitmapWidth();
    this.canvas.height = this.bitmapHeight();

    if (this.usesWebGl()) {
        this.gl = Picture.initWebGL(this.canvas);
        if (this.gl === null || !this.setupGLState()) {
            this.mode = undefined;
            return;
        }
    } else if (this.mode === 'canvas') {
        this.ctx = this.canvas.getContext('2d');
        this.compositingCanvas = document.createElement('canvas');
        this.compositingCanvas.width = this.bitmapWidth();
        this.compositingCanvas.height = this.bitmapHeight();
        this.compositingCtx = this.compositingCanvas.getContext('2d');
        this.initRasterizers();
    } else {
        this.mode = undefined;
        return;
    }
    this.generationTime = 0;
};

/**
 * Set up state in an existing gl context.
 * @return {boolean} Whether buffer initialization succeeded.
 */
Picture.prototype.setupGLState = function() {
    this.glManager = glStateManager(this.gl);

    console.log(this.glManager.availableExtensions);

    var useFloatRasterizer = (this.mode === 'webgl' ||
                              this.mode === 'no-texdata-webgl');
    if (useFloatRasterizer) {
        if (this.glManager.extensionTextureFloat === null) {
            return false;
        }
        if (this.mode === 'webgl') {
            this.glRasterizerConstructor = GLFloatTexDataRasterizer;
        } else {
            this.glRasterizerConstructor = GLFloatRasterizer;
        }
    } else {
        this.glRasterizerConstructor = GLDoubleBufferedRasterizer;
    }

    this.texBlitProgram = this.glManager.shaderProgram(blitShader.blitSrc,
                                                       blitShader.blitVertSrc,
                                                       {uSrcTex: 'tex2d'});
    this.texBlitUniforms = {
        uSrcTex: null
    };

    if (!this.initRasterizers()) {
        console.log('WebGL accelerated rasterizer did not pass sanity test ' +
                    '(mode ' + this.mode + '). Update your graphics drivers ' +
                    'or try switching browsers if possible.');
        return false;
    }
    return true;
};

/**
 * Add a buffer to the top of the buffer stack.
 * @param {number} id Identifier for this buffer. Unique at the Picture level.
 * Can be -1 if events won't be serialized separately from this buffer.
 * @param {Array.<number>} clearColor 4-component array with RGBA color that's
 * used to clear this buffer.
 * @param {boolean} hasUndoStates Does the buffer store undo states?
 * @param {boolean} hasAlpha Does the buffer have an alpha channel?
 */
Picture.prototype.addBuffer = function(id, clearColor, hasUndoStates,
                                       hasAlpha) {
    var buffer = this.createBuffer(id, clearColor, hasUndoStates, hasAlpha);
    this.buffers.push(buffer);
};

/**
 * Move a buffer to the given index in the buffer stack. Current event stays
 * attached to the moved buffer, if it exists.
 * @param {number} fromPosition The position of the buffer to move. Must be an
 * integer between 0 and Picture.buffers.length - 1.
 * @param {number} toPosition The position to move this buffer to. Must be an
 * integer between 0 and Picture.buffers.length - 1.
 */
Picture.prototype.moveBuffer = function(fromPosition, toPosition) {
    // TODO: assert that buffer count is respected
    var buffer = this.buffers[fromPosition];
    this.buffers.splice(fromPosition, 1);
    this.buffers.splice(toPosition, 0, buffer);
    if (this.currentEventAttachment === fromPosition) {
        this.currentEventAttachment = toPosition;
    }
};

/**
 * Update the current event compositing mode.
 * @protected
 */
Picture.prototype.updateCurrentEventMode = function() {
    if (this.currentEvent !== null && this.currentEventAttachment >= 0) {
        // TODO: assert(this.currentEventAttachment < this.buffers.length)
        this.currentEventMode = this.currentEvent.mode;
        if (this.currentEventMode === BrushEvent.Mode.eraser &&
            !this.buffers[this.currentEventAttachment].hasAlpha) {
            this.currentEventMode = BrushEvent.Mode.normal;
        }
    }
};

/**
 * Attach the current event to the given buffer in the stack.
 * @param {number} attachment Which buffer index to attach the picture's current
 * event to. Can be set to -1 if no current event is needed.
 */
Picture.prototype.setCurrentEventAttachment = function(attachment) {
    this.currentEventAttachment = attachment;
    this.updateCurrentEventMode();
};

/**
 * Set one of this picture's buffers visible or invisible.
 * @param {PictureBuffer} buffer The buffer to adjust.
 * @param {boolean} visible Is the buffer visible?
 */
Picture.prototype.setBufferVisible = function(buffer, visible) {
    // TODO: assert that the buffer belongs to this picture.
    buffer.visible = visible;
};

/**
 * Create a Picture object.
 * @param {number} id Picture's unique id number.
 * @param {number} width Picture width.
 * @param {number} height Picture height.
 * @param {number} bitmapScale Scale for rasterizing the picture. Events that
 * are pushed to this picture get this scale applied to them.
 * @param {Array.<string>} modesToTry Modes to try to initialize the picture.
 * Can contain either 'webgl', 'no-texdata-webgl', 'no-float-webgl' or 'canvas'.
 * Modes are tried in the order they are in the array.
 * @param {number} currentEventAttachment Which buffer index to attach the
 * picture's current event to. Can be set to -1 if no current event is needed.
 * @return {Picture} The created picture or null if one couldn't be created.
 */
Picture.create = function(id, width, height, bitmapScale, modesToTry,
                          currentEventAttachment) {
    var pictureBounds = new Rect(0, width, 0, height);
    var i = 0;
    var pic = null;
    while (i < modesToTry.length && pic === null) {
        var mode = modesToTry[i];
        if (glUtils.supportsTextureUnits(4) || mode === 'canvas') {
            pic = new Picture(id, pictureBounds, bitmapScale, mode,
                              currentEventAttachment);
            if (pic.mode === undefined) {
                pic = null;<commit_msg>Fix setBufferVisible so that buffers array doesn't need to be accessed<commit_after>/*
 * Copyright <NAME> 2012-2013.
 */

/**
 * @constructor
 * @param {number} id Picture's unique id number.
 * @param {Rect} boundsRect Picture bounds. x and y should always be zero.
 * @param {number} bitmapScale Scale for rasterizing the picture. Events that
 * are pushed to this picture get this scale applied to them.
 * @param {string=} mode Either 'webgl', 'no-texdata-webgl' or 'canvas'.
 * Defaults to 'webgl'.
 * @param {number} currentEventAttachment Which buffer index to attach the
 * picture's current event to. Can be set to -1 if no current event is needed.
 */
var Picture = function(id, boundsRect, bitmapScale, mode,
                       currentEventAttachment) {
    this.id = id;
    if (mode === undefined) {
        mode = 'webgl';
    }
    this.mode = mode;

    this.animating = false;

    this.buffers = [];
    this.currentEventAttachment = currentEventAttachment;
    this.currentEvent = null;
    this.currentEventMode = BrushEvent.Mode.normal;

    this.boundsRect = boundsRect;
    this.bitmapScale = bitmapScale;
    var bitmapWidth = Math.floor(this.boundsRect.width() * this.bitmapScale);
    var bitmapHeight = Math.floor(this.boundsRect.height() * this.bitmapScale);
    this.bitmapRect = new Rect(0, bitmapWidth, 0, bitmapHeight);

    this.container = null;
    this.canvas = document.createElement('canvas');
    this.canvas.width = this.bitmapWidth();
    this.canvas.height = this.bitmapHeight();

    if (this.usesWebGl()) {
        this.gl = Picture.initWebGL(this.canvas);
        if (this.gl === null || !this.setupGLState()) {
            this.mode = undefined;
            return;
        }
    } else if (this.mode === 'canvas') {
        this.ctx = this.canvas.getContext('2d');
        this.compositingCanvas = document.createElement('canvas');
        this.compositingCanvas.width = this.bitmapWidth();
        this.compositingCanvas.height = this.bitmapHeight();
        this.compositingCtx = this.compositingCanvas.getContext('2d');
        this.initRasterizers();
    } else {
        this.mode = undefined;
        return;
    }
    this.generationTime = 0;
};

/**
 * Set up state in an existing gl context.
 * @return {boolean} Whether buffer initialization succeeded.
 */
Picture.prototype.setupGLState = function() {
    this.glManager = glStateManager(this.gl);

    console.log(this.glManager.availableExtensions);

    var useFloatRasterizer = (this.mode === 'webgl' ||
                              this.mode === 'no-texdata-webgl');
    if (useFloatRasterizer) {
        if (this.glManager.extensionTextureFloat === null) {
            return false;
        }
        if (this.mode === 'webgl') {
            this.glRasterizerConstructor = GLFloatTexDataRasterizer;
        } else {
            this.glRasterizerConstructor = GLFloatRasterizer;
        }
    } else {
        this.glRasterizerConstructor = GLDoubleBufferedRasterizer;
    }

    this.texBlitProgram = this.glManager.shaderProgram(blitShader.blitSrc,
                                                       blitShader.blitVertSrc,
                                                       {uSrcTex: 'tex2d'});
    this.texBlitUniforms = {
        uSrcTex: null
    };

    if (!this.initRasterizers()) {
        console.log('WebGL accelerated rasterizer did not pass sanity test ' +
                    '(mode ' + this.mode + '). Update your graphics drivers ' +
                    'or try switching browsers if possible.');
        return false;
    }
    return true;
};

/**
 * Add a buffer to the top of the buffer stack.
 * @param {number} id Identifier for this buffer. Unique at the Picture level.
 * Can be -1 if events won't be serialized separately from this buffer.
 * @param {Array.<number>} clearColor 4-component array with RGBA color that's
 * used to clear this buffer.
 * @param {boolean} hasUndoStates Does the buffer store undo states?
 * @param {boolean} hasAlpha Does the buffer have an alpha channel?
 */
Picture.prototype.addBuffer = function(id, clearColor, hasUndoStates,
                                       hasAlpha) {
    var buffer = this.createBuffer(id, clearColor, hasUndoStates, hasAlpha);
    this.buffers.push(buffer);
};

/**
 * Move a buffer to the given index in the buffer stack. Current event stays
 * attached to the moved buffer, if it exists.
 * @param {number} fromPosition The position of the buffer to move. Must be an
 * integer between 0 and Picture.buffers.length - 1.
 * @param {number} toPosition The position to move this buffer to. Must be an
 * integer between 0 and Picture.buffers.length - 1.
 */
Picture.prototype.moveBuffer = function(fromPosition, toPosition) {
    // TODO: assert that buffer count is respected
    var buffer = this.buffers[fromPosition];
    this.buffers.splice(fromPosition, 1);
    this.buffers.splice(toPosition, 0, buffer);
    if (this.currentEventAttachment === fromPosition) {
        this.currentEventAttachment = toPosition;
    }
};

/**
 * Update the current event compositing mode.
 * @protected
 */
Picture.prototype.updateCurrentEventMode = function() {
    if (this.currentEvent !== null && this.currentEventAttachment >= 0) {
        // TODO: assert(this.currentEventAttachment < this.buffers.length)
        this.currentEventMode = this.currentEvent.mode;
        if (this.currentEventMode === BrushEvent.Mode.eraser &&
            !this.buffers[this.currentEventAttachment].hasAlpha) {
            this.currentEventMode = BrushEvent.Mode.normal;
        }
    }
};

/**
 * Attach the current event to the given buffer in the stack.
 * @param {number} attachment Which buffer index to attach the picture's current
 * event to. Can be set to -1 if no current event is needed.
 */
Picture.prototype.setCurrentEventAttachment = function(attachment) {
    this.currentEventAttachment = attachment;
    this.updateCurrentEventMode();
};

/**
 * Set one of this picture's buffers visible or invisible.
 * @param {number} buffer The index of the buffer to adjust.
 * @param {boolean} visible Is the buffer visible?
 */
Picture.prototype.setBufferVisible = function(buffer, visible) {
    this.buffers[buffer].visible = visible;
};

/**
 * Create a Picture object.
 * @param {number} id Picture's unique id number.
 * @param {number} width Picture width.
 * @param {number} height Picture height.
 * @param {number} bitmapScale Scale for rasterizing the picture. Events that
 * are pushed to this picture get this scale applied to them.
 * @param {Array.<string>} modesToTry Modes to try to initialize the picture.
 * Can contain either 'webgl', 'no-texdata-webgl', 'no-float-webgl' or 'canvas'.
 * Modes are tried in the order they are in the array.
 * @param {number} currentEventAttachment Which buffer index to attach the
 * picture's current event to. Can be set to -1 if no current event is needed.
 * @return {Picture} The created picture or null if one couldn't be created.
 */
Picture.create = function(id, width, height, bitmapScale, modesToTry,
                          currentEventAttachment) {
    var pictureBounds = new Rect(0, width, 0, height);
    var i = 0;
    var pic = null;
    while (i < modesToTry.length && pic === null) {
        var mode = modesToTry[i];
        if (glUtils.supportsTextureUnits(4) || mode === 'canvas') {
            pic = new Picture(id, pictureBounds, bitmapScale, mode,
                              currentEventAttachment);
            if (pic.mode === undefined) {
                pic = null;
{'fraction_non_alphanumeric': 0.10753115884380801, 'fraction_numerical': 0.003977724741447892, 'mean_word_length': 2.778807615230461, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3888673', 'n_tokens_mistral': 4211, 'n_tokens_neox': 4143, 'n_words': 1313}