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

/**
 * @constructor
 * @param {number} id Picture's unique id number.
 * @param {string} name Name of the picture. May be null.
 * @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 {Array.<HTMLImageElement|HTMLCanvasElement>=} brushTextureData Set of brush textures to use. Can be undefined
 * if no textures are needed.
 */
var Picture = function(id, name, boundsRect, bitmapScale, mode, brushTextureData) {
    this.id = id;
    this.name = name;
    if (mode === undefined) {
        mode = 'webgl';
    }
    this.mode = mode;
    this.parsedVersion = null;
    this.brushTextureData = brushTextureData;

    this.freed = false; // Freed picture has no bitmaps. They can be regenerated.

    this.animating = false;

    this.activeSid = 0;
    this.activeSessionEventId = 0;

    this.buffers = [];
    this.currentEventAttachment = -1;
    this.currentEvent = null;
    this.currentEventMode = PictureEvent.Mode.normal;
    this.currentEventColor = [255, 255, 255];

    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);

    // Shouldn't use more GPU memory than this for buffers and rasterizers
    // combined. Just guessing for a good generic limit, since WebGL won't give
    // out an exact one. Assuming that 2D canvas elements count towards this.
    this.memoryBudget = 256 * 1024 * 1024;
    // Allocate space for the compositing buffer
    this.memoryUse = this.bitmapWidth() * this.bitmapHeight() * 4;

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

    if (this.usesWebGl()) {
        if (!this.setupGLState()) {
            this.mode = undefined;
            return;
        }
    } else if (this.mode === 'canvas') {
        this.ctx = this.canvas.getContext('2d');
        this.compositor = new CanvasCompositor(this.ctx);
        this.brushTextures = new CanvasBrushTextures();
        this.initBrushTextures();
        this.initRasterizers();
    } else {
        this.mode = undefined;
        return;
    }
};

/**
 * Initialize brush textures to use in rasterizers from the given brush texture data.
 * @protected
 */
Picture.prototype.initBrushTextures = function() {
    if (!this.brushTextureData) {
        return;
    }
    for (var i = 0; i < this.brushTextureData.length; ++i) {
        this.brushTextures.addTexture(this.brushTextureData[i]);
    }
};

/**
 * Set up state in an existing gl context.
 * @return {boolean} Whether buffer initialization succeeded.
 */
Picture.prototype.setupGLState = function() {
    var useFloatRasterizer = (this.mode === 'webgl' || this.mode === 'no-texdata-webgl');
    if (useFloatRasterizer && !glUtils.floatFboSupported) {
        return false;
    }

    this.gl = Picture.initWebGL(this.canvas);
    if (!this.gl) {
        return false;
    }
    this.glManager = glStateManager(this.gl);
    this.loseContext = this.gl.getExtension('WEBGL_lose_context');

    this.brushTextures = new GLBrushTextures(this.gl, this.glManager);
    this.initBrushTextures();

    if (useFloatRasterizer) {
        if (this.mode === 'webgl') {
            this.glRasterizerConstructor = GLFloatTexDataRasterizer;
        } else {
            // TODO: assert(this.mode === 'no-texdata-webgl');
            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;
    }

    this.compositor = new GLCompositor(this.glManager, this.gl,
                                       glUtils.maxTextureUnits);
    return true;
};

/**
 * Kill WebGL context if one exists to free as many resources as possible.
 * Meant mainly for testing.
 */
Picture.prototype.destroy = function() {
    if (this.gl) {<commit_msg>Add WebGL sanity failure flag<commit_after>/*
 * Copyright <NAME> 2012-2013.
 */

/**
 * @constructor
 * @param {number} id Picture's unique id number.
 * @param {string} name Name of the picture. May be null.
 * @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 {Array.<HTMLImageElement|HTMLCanvasElement>=} brushTextureData Set of brush textures to use. Can be undefined
 * if no textures are needed.
 */
var Picture = function(id, name, boundsRect, bitmapScale, mode, brushTextureData) {
    this.id = id;
    this.name = name;
    if (mode === undefined) {
        mode = 'webgl';
    }
    this.mode = mode;
    this.parsedVersion = null;
    this.brushTextureData = brushTextureData;

    this.freed = false; // Freed picture has no bitmaps. They can be regenerated.

    this.animating = false;

    this.activeSid = 0;
    this.activeSessionEventId = 0;

    this.buffers = [];
    this.currentEventAttachment = -1;
    this.currentEvent = null;
    this.currentEventMode = PictureEvent.Mode.normal;
    this.currentEventColor = [255, 255, 255];

    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);

    // Shouldn't use more GPU memory than this for buffers and rasterizers
    // combined. Just guessing for a good generic limit, since WebGL won't give
    // out an exact one. Assuming that 2D canvas elements count towards this.
    this.memoryBudget = 256 * 1024 * 1024;
    // Allocate space for the compositing buffer
    this.memoryUse = this.bitmapWidth() * this.bitmapHeight() * 4;

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

    if (this.usesWebGl()) {
        if (!this.setupGLState()) {
            this.mode = undefined;
            return;
        }
    } else if (this.mode === 'canvas') {
        this.ctx = this.canvas.getContext('2d');
        this.compositor = new CanvasCompositor(this.ctx);
        this.brushTextures = new CanvasBrushTextures();
        this.initBrushTextures();
        this.initRasterizers();
    } else {
        this.mode = undefined;
        return;
    }
};

Picture.hasFailedWebGLSanity = false;

/**
 * Initialize brush textures to use in rasterizers from the given brush texture data.
 * @protected
 */
Picture.prototype.initBrushTextures = function() {
    if (!this.brushTextureData) {
        return;
    }
    for (var i = 0; i < this.brushTextureData.length; ++i) {
        this.brushTextures.addTexture(this.brushTextureData[i]);
    }
};

/**
 * Set up state in an existing gl context.
 * @return {boolean} Whether buffer initialization succeeded.
 */
Picture.prototype.setupGLState = function() {
    var useFloatRasterizer = (this.mode === 'webgl' || this.mode === 'no-texdata-webgl');
    if (useFloatRasterizer && !glUtils.floatFboSupported) {
        return false;
    }

    this.gl = Picture.initWebGL(this.canvas);
    if (!this.gl) {
        return false;
    }
    this.glManager = glStateManager(this.gl);
    this.loseContext = this.gl.getExtension('WEBGL_lose_context');

    this.brushTextures = new GLBrushTextures(this.gl, this.glManager);
    this.initBrushTextures();

    if (useFloatRasterizer) {
        if (this.mode === 'webgl') {
            this.glRasterizerConstructor = GLFloatTexDataRasterizer;
        } else {
            // TODO: assert(this.mode === 'no-texdata-webgl');
            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()) {
        Picture.hasFailedWebGLSanity = true;
        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;
    }

    this.compositor = new GLCompositor(this.glManager, this.gl,
                                       glUtils.maxTextureUnits);
    return true;
};

/**
 * Kill WebGL context if one exists to free as many resources as possible.
 * Meant mainly for testing.
 */
Picture.prototype.destroy = function() {
    if (this.gl) {
{'fraction_non_alphanumeric': 0.11483350151362261, 'fraction_numerical': 0.007669021190716448, 'mean_word_length': 2.5909420289855074, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, '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': '7001143', 'n_tokens_mistral': 2998, 'n_tokens_neox': 2867, 'n_words': 766}