<commit_before>/**
 * This module defines the <a href="#/p5.Font">p5.Font</a> class and functions for
 * drawing text to the display canvas.
 * @module Typography
 * @submodule Loading & Displaying
 * @requires core
 * @requires constants
 */

import p5 from '../core/main';
import * as constants from '../core/constants';

/**
 * Base class for font handling
 * @class p5.Font
 * @constructor
 * @param {p5} [pInst] pointer to p5 instance
 */
p5.Font = function(p) {
  this.parent = p;

  this.cache = {};

  /**
   * Underlying opentype font implementation
   * @property font
   */
  this.font = undefined;
};

/**
 * Returns a tight bounding box for the given text string using this
 * font (currently only supports single lines)
 *
 * @method textBounds
 * @param  {String} line     a line of text
 * @param  {Number} x        x-position
 * @param  {Number} y        y-position
 * @param  {Number} [fontSize] font size to use (optional) Default is 12.
 * @param  {Object} [options] opentype options (optional)
 *                            opentype fonts contains alignment and baseline options.
 *                            Default is 'LEFT' and 'alphabetic'
 *
 *
 * @return {Object}          a rectangle object with properties: x, y, w, h
 *
 * @example
 * <div>
 * <code>
 * let font;
 * let textString = 'Lorem ipsum dolor sit amet.';
 * function preload() {
 *   font = loadFont('./assets/Regular.otf');
 * }
 * function setup() {
 *   background(210);
 *
 *   let bbox = font.textBounds(textString, 10, 30, 12);
 *   fill(255);
 *   stroke(0);
 *   rect(bbox.x, bbox.y, bbox.w, bbox.h);
 *   fill(0);
 *   noStroke();
 *
 *   textFont(font);
 *   textSize(12);
 *   text(textString, 10, 30);
 * }
 * </code>
 * </div>
 *
 * @alt
 *words Lorem ipsum dol go off canvas and contained by white bounding box
 *
 */
p5.Font.prototype.textBounds = function(str, x = 0, y = 0, fontSize, opts) {
  // Check cache for existing bounds. Take into consideration the text alignment
  // settings. Default alignment should match opentype's origin: left-aligned &
  // alphabetic baseline.
  const p = (opts && opts.renderer && opts.renderer._pInst) || this.parent;

  const ctx = p._renderer.drawingContext;
  const alignment = ctx.textAlign || constants.LEFT;
  const baseline = ctx.textBaseline || constants.BASELINE;
  const cacheResults = false;
  let result;
  let key;

  fontSize = fontSize || p._renderer._textSize;

  // NOTE: cache disabled for now pending further discussion of #3436
  if (cacheResults) {
    key = cacheKey('textBounds', str, x, y, fontSize, alignment, baseline);
    result = this.cache[key];
  }

  if (!result) {
    var minX = [];
    var minY;
    var maxX = [];
    var maxY;
    var pos;
    var xCoords = [];
    xCoords[0] = [];
    var yCoords = [];
    var scale = this._scale(fontSize);
    var lineCount = 0;
    var lineHeight = p._renderer.textLeading();

    this.font.forEachGlyph(str, x, y, fontSize, opts, function(
      glyph,
      gX,
      gY,
      gFontSize
    ) {
      var gm = glyph.getMetrics();
      if (glyph.index === 0 || glyph.index === 10) {
        lineCount += 1;
        xCoords[lineCount] = [];
      } else {
        xCoords[lineCount].push(gX + gm.xMin * scale);
        xCoords[lineCount].push(gX + gm.xMax * scale);
        yCoords.push(gY + lineCount * lineHeight + -gm.yMin * scale);
        yCoords.push(gY + lineCount * lineHeight + -gm.yMax * scale);
      }
    });

    if (xCoords[lineCount].length > 0) {
      minX[lineCount] = Math.min.apply(null, xCoords[lineCount]);
      maxX[lineCount] = Math.max.apply(null, xCoords[lineCount]);
    }

    var finalMaxX = 0;
    for (var i = 0; i <= lineCount; i++) {
      minX[i] = Math.min.apply(null, xCoords[i]);
      maxX[i] = Math.max.apply(null, xCoords[i]);

      var lineLength = maxX[i] - minX[i];
      if (lineLength > finalMaxX) {
        finalMaxX = lineLength;
      }
    }

    var finalMinX = Math.min.apply(null, minX);
    minY = Math.min.apply(null, yCoords);
    maxY = Math.max.apply(null, yCoords);<commit_msg>minimizing line changes and adjusted documentation that said the function did not support multiline<commit_after>/**
 * This module defines the <a href="#/p5.Font">p5.Font</a> class and functions for
 * drawing text to the display canvas.
 * @module Typography
 * @submodule Loading & Displaying
 * @requires core
 * @requires constants
 */

import p5 from '../core/main';
import * as constants from '../core/constants';

/**
 * Base class for font handling
 * @class p5.Font
 * @constructor
 * @param {p5} [pInst] pointer to p5 instance
 */
p5.Font = function(p) {
  this.parent = p;

  this.cache = {};

  /**
   * Underlying opentype font implementation
   * @property font
   */
  this.font = undefined;
};

/**
 * Returns a tight bounding box for the given text string using this
 * font
 *
 * @method textBounds
 * @param  {String} line     a line of text
 * @param  {Number} x        x-position
 * @param  {Number} y        y-position
 * @param  {Number} [fontSize] font size to use (optional) Default is 12.
 * @param  {Object} [options] opentype options (optional)
 *                            opentype fonts contains alignment and baseline options.
 *                            Default is 'LEFT' and 'alphabetic'
 *
 *
 * @return {Object}          a rectangle object with properties: x, y, w, h
 *
 * @example
 * <div>
 * <code>
 * let font;
 * let textString = 'Lorem ipsum dolor sit amet.';
 * function preload() {
 *   font = loadFont('./assets/Regular.otf');
 * }
 * function setup() {
 *   background(210);
 *
 *   let bbox = font.textBounds(textString, 10, 30, 12);
 *   fill(255);
 *   stroke(0);
 *   rect(bbox.x, bbox.y, bbox.w, bbox.h);
 *   fill(0);
 *   noStroke();
 *
 *   textFont(font);
 *   textSize(12);
 *   text(textString, 10, 30);
 * }
 * </code>
 * </div>
 *
 * @alt
 *words Lorem ipsum dol go off canvas and contained by white bounding box
 *
 */
p5.Font.prototype.textBounds = function(str, x = 0, y = 0, fontSize, opts) {
  // Check cache for existing bounds. Take into consideration the text alignment
  // settings. Default alignment should match opentype's origin: left-aligned &
  // alphabetic baseline.
  const p = (opts && opts.renderer && opts.renderer._pInst) || this.parent;

  const ctx = p._renderer.drawingContext;
  const alignment = ctx.textAlign || constants.LEFT;
  const baseline = ctx.textBaseline || constants.BASELINE;
  const cacheResults = false;
  let result;
  let key;

  fontSize = fontSize || p._renderer._textSize;

  // NOTE: cache disabled for now pending further discussion of #3436
  if (cacheResults) {
    key = cacheKey('textBounds', str, x, y, fontSize, alignment, baseline);
    result = this.cache[key];
  }

  if (!result) {
    let minX = [];
    let minY;
    let maxX = [];
    let maxY;
    let pos;
    const xCoords = [];
    xCoords[0] = [];
    const yCoords = [];
    const scale = this._scale(fontSize);
    const lineHeight = p._renderer.textLeading();
    let lineCount = 0;

    this.font.forEachGlyph(
      str,
      x,
      y,
      fontSize,
      opts,
      (glyph, gX, gY, gFontSize) => {
        const gm = glyph.getMetrics();
        if (glyph.index === 0 || glyph.index === 10) {
          lineCount += 1;
          xCoords[lineCount] = [];
        } else {
          xCoords[lineCount].push(gX + gm.xMin * scale);
          xCoords[lineCount].push(gX + gm.xMax * scale);
          yCoords.push(gY + lineCount * lineHeight + -gm.yMin * scale);
          yCoords.push(gY + lineCount * lineHeight + -gm.yMax * scale);
        }
      }
    );

    if (xCoords[lineCount].length > 0) {
      minX[lineCount] = Math.min.apply(null, xCoords[lineCount]);
      maxX[lineCount] = Math.max.apply(null, xCoords[lineCount]);
    }

    var finalMaxX = 0;
    for (var i = 0; i <= lineCount; i++) {
      minX[i] = Math.min.apply(null, xCoords[i]);
      maxX[i] = Math.max.apply(null, xCoords[i]);

      var lineLength = maxX[i] - minX[i];
      if (lineLength > finalMaxX) {
        finalMaxX = lineLength;
      }
    }

    var finalMinX = Math.min.apply(null, minX);
    minY = Math.min.apply(null, yCoords);
    maxY = Math.max.apply(null, yCoords);
{'fraction_non_alphanumeric': 0.14059454191033138, 'fraction_numerical': 0.010964912280701754, 'mean_word_length': 2.622683142100618, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3796965', 'n_tokens_mistral': 2817, 'n_tokens_neox': 2716, 'n_words': 763}