<commit_before>
/**
 * Associates a canvas to a given image, containing a number of renderings
 * of the image at various sizes.
 *
 * This technique is known as 'mipmapping'.
 *
 * NOTE: Images can also be of type 'data:svg+xml`. This code also works
 *       for svg, but the mipmapping may not be necessary.
 *
 * @param {Image} image
 */
class CachedImage {
  /**
   * @param {Image} image
   */
  constructor(image) {  // eslint-disable-line no-unused-vars
    this.NUM_ITERATIONS = 4;  // Number of items in the coordinates array

    this.image  = new Image();
    this.canvas = document.createElement('canvas');
  }


  /**
   * Called when the image has been successfully loaded.
   */
  init() {
    if (this.initialized()) return;

    this.src = this.image.src;  // For same interface with Image
    var w = this.image.width;
    var h = this.image.height;

    // Ease external access
    this.width  = w;
    this.height = h;

    // Make canvas as small as possible
    this.canvas.width  = 3*w/4;
    this.canvas.height = h/2;

    // Coordinates and sizes of images contained in the canvas
    // Values per row:  [top x, left y, width, height]
    this.coordinates = [
      [ 0    , 0  , w/2 , h/2],
      [ w/2  , 0  , w/4 , h/4],
      [ w/2  , h/4, w/8 , h/8],
      [ 5*w/8, h/4, w/16, h/16]
    ];

    this._fillMipMap();
  }


  /**
   * @return {Boolean} true if init() has been called, false otherwise.
   */
  initialized() {
    return (this.coordinates !== undefined);
  }


  /**
   * Redraw main image in various sizes to the context.
   *
   * The rationale behind this is to reduce artefacts due to interpolation
   * at differing zoom levels.
   *
   * Source: http://stackoverflow.com/q/18761404/1223531
   *
   * This methods takes the resizing out of the drawing loop, in order to
   * reduce performance overhead.
   *
   * TODO: The code assumes that a 2D context can always be gotten. This is
   *       not necessarily true! OTOH, if not true then usage of this class
   *       is senseless.
   *
   * @private
   */
  _fillMipMap() {
    var ctx = this.canvas.getContext('2d');

    // First zoom-level comes from the image
    var to  = this.coordinates[0];
    ctx.drawImage(this.image, to[0], to[1], to[2], to[3]);

    // The rest are copy actions internal to the canvas/context
    for (let iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
      let from = this.coordinates[iterations - 1];
      let to   = this.coordinates[iterations];

      ctx.drawImage(this.canvas,
        from[0], from[1], from[2], from[3],
          to[0],   to[1],   to[2],   to[3]
      );
    }
  }


  /**
   * Draw the image, using the mipmap if necessary.
   *
   * MipMap is only used if param factor > 2; otherwise, original bitmap
   * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
   *
   * Credits to '<NAME>' for original implementation.
   *
   * @param {CanvasRenderingContext2D} ctx  context on which to draw zoomed image
   * @param {Float} factor scale factor at which to draw
   * @param {number} left
   * @param {number} top
   * @param {number} width
   * @param {number} height
   */
  drawImageAtPosition(ctx, factor, left, top, width, height) {
    if (factor > 2 && this.initialized()) {
      // Determine which zoomed image to use
      factor *= 0.5;
      let iterations = 0;
      while (factor > 2 && iterations < this.NUM_ITERATIONS) {
        factor *= 0.5;
        iterations += 1;
      }

      if (iterations >= this.NUM_ITERATIONS) {
        iterations = this.NUM_ITERATIONS - 1;
      }
      //console.log("iterations: " + iterations);

      let from = this.coordinates[iterations];
      ctx.drawImage(this.canvas,
        from[0], from[1], from[2], from[3],
           left,     top,   width,  height
      );
    } else if (this._isImageOk()) {
      // Draw image directly
      ctx.drawImage(this.image, left, top, width, height);
    }
  }


  /**
   * Check if image is loaded
   *
   * Source: http://stackoverflow.com/a/1977898/1223531
   *
   * @returns {boolean}
   * @private
   */
  _isImageOk() {
    var img = this.image;

    // During the onload event, IE correctly identifies any images that
    // weren’t downloaded as not complete. Others should too. Gecko-based
    // browsers act like NS4 in that they report this incorrectly.
    if (!img.complete) {
        return false;
    }

    // However, they do have two very useful properties: naturalWidth and
    // naturalHeight. These give the true size of the image. If it failed
    // to load, either of these should be zero.

    if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) {
        return false;
    }

    // No other way of checking: assume it’s ok.
    return true;
  }
}


export default CachedImage;<commit_msg>IE11 svg image fixes (#3477)<commit_after>
/**
 * Associates a canvas to a given image, containing a number of renderings
 * of the image at various sizes.
 *
 * This technique is known as 'mipmapping'.
 *
 * NOTE: Images can also be of type 'data:svg+xml`. This code also works
 *       for svg, but the mipmapping may not be necessary.
 *
 * @param {Image} image
 */
class CachedImage {
  /**
   * @ignore
   */  
  constructor() {  // eslint-disable-line no-unused-vars
    this.NUM_ITERATIONS = 4;  // Number of items in the coordinates array

    this.image  = new Image();
    this.canvas = document.createElement('canvas');
  }


  /**
   * Called when the image has been successfully loaded.
   */
  init() {
    if (this.initialized()) return;

    this.src = this.image.src;  // For same interface with Image
    var w = this.image.width;
    var h = this.image.height;

    // Ease external access
    this.width  = w;
    this.height = h;

    var h2 = Math.floor(h/2);
    var h4 = Math.floor(h/4);
    var h8 = Math.floor(h/8);
    var h16 = Math.floor(h/16);

    var w2 = Math.floor(w/2);
    var w4 = Math.floor(w/4);
    var w8 = Math.floor(w/8);
    var w16 = Math.floor(w/16);

    // Make canvas as small as possible
    this.canvas.width  = 3*w4;
    this.canvas.height = h2;

    // Coordinates and sizes of images contained in the canvas
    // Values per row:  [top x, left y, width, height]

    this.coordinates = [
      [ 0    , 0  , w2 , h2],
      [ w2  , 0  , w4 , h4],
      [ w2  , h4, w8 , h8],
      [ 5*w8, h4, w16, h16]
    ];

    this._fillMipMap();
  }


  /**
   * @return {Boolean} true if init() has been called, false otherwise.
   */
  initialized() {
    return (this.coordinates !== undefined);
  }


  /**
   * Redraw main image in various sizes to the context.
   *
   * The rationale behind this is to reduce artefacts due to interpolation
   * at differing zoom levels.
   *
   * Source: http://stackoverflow.com/q/18761404/1223531
   *
   * This methods takes the resizing out of the drawing loop, in order to
   * reduce performance overhead.
   *
   * TODO: The code assumes that a 2D context can always be gotten. This is
   *       not necessarily true! OTOH, if not true then usage of this class
   *       is senseless.
   *
   * @private
   */
  _fillMipMap() {
    var ctx = this.canvas.getContext('2d');

    // First zoom-level comes from the image
    var to  = this.coordinates[0];
    ctx.drawImage(this.image, to[0], to[1], to[2], to[3]);

    // The rest are copy actions internal to the canvas/context
    for (let iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
      let from = this.coordinates[iterations - 1];
      let to   = this.coordinates[iterations];

      ctx.drawImage(this.canvas,
        from[0], from[1], from[2], from[3],
          to[0],   to[1],   to[2],   to[3]
      );
    }
  }


  /**
   * Draw the image, using the mipmap if necessary.
   *
   * MipMap is only used if param factor > 2; otherwise, original bitmap
   * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
   *
   * Credits to '<NAME>' for original implementation.
   *
   * @param {CanvasRenderingContext2D} ctx  context on which to draw zoomed image
   * @param {Float} factor scale factor at which to draw
   * @param {number} left
   * @param {number} top
   * @param {number} width
   * @param {number} height
   */
  drawImageAtPosition(ctx, factor, left, top, width, height) {

    if(!this.initialized())
      return; //can't draw image yet not intialized

    if (factor > 2) {
      // Determine which zoomed image to use
      factor *= 0.5;
      let iterations = 0;
      while (factor > 2 && iterations < this.NUM_ITERATIONS) {
        factor *= 0.5;
        iterations += 1;
      }

      if (iterations >= this.NUM_ITERATIONS) {
        iterations = this.NUM_ITERATIONS - 1;
      }
      //console.log("iterations: " + iterations);

      let from = this.coordinates[iterations];
      ctx.drawImage(this.canvas,
        from[0], from[1], from[2], from[3],
           left,     top,   width,  height
      );
    } else {
      // Draw image directly
      ctx.drawImage(this.image, left, top, width, height);
    }
  }

}


export default CachedImage;
{'fraction_non_alphanumeric': 0.12136508284867771, 'fraction_numerical': 0.020190936025458135, 'mean_word_length': 2.316593886462882, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '486718', 'n_tokens_mistral': 3050, 'n_tokens_neox': 2888, 'n_words': 963}