/* 18.8.23 fonts CT_Fonts
766168
function parse_fonts(t, styles, themes, opts) {
	styles.Fonts = [];
	var font = {};
	var pass = false;
	t[0].match(tagregex).forEach(function(x) {
		var y = parsexmltag(x);
		switch(strip_ns(y[0])) {
			case '<fonts': case '<fonts>': case '</fonts>': break;

			/* 18.8.22 font CT_Font */
			case '<font': case '<font>': break;
			case '</font>': case '<font/>':
				styles.Fonts.push(font);
				font = {};
				break;

			/* 18.8.29 name CT_FontName */
			case '<name': if(y.val) font.name = y.val; break;
			case '<name/>': case '</name>': break;

			/* 18.8.2  b CT_BooleanProperty */
			case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
			case '<b/>': font.bold = 1; break;

			/* 18.8.26 i CT_BooleanProperty */
			case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
			case '<i/>': font.italic = 1; break;

			/* 18.4.13 u CT_UnderlineProperty */
			case '<u':
				switch(y.val) {
					case "none": font.underline = 0x00; break;
					case "single": font.underline = 0x01; break;
					case "double": font.underline = 0x02; break;
					case "singleAccounting": font.underline = 0x21; break;
					case "doubleAccounting": font.underline = 0x22; break;
				} break;
			case '<u/>': font.underline = 1; break;

			/* 18.4.10 strike CT_BooleanProperty */
			case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
			case '<strike/>': font.strike = 1; break;

			/* 18.4.2  outline CT_BooleanProperty */
			case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
			case '<outline/>': font.outline = 1; break;

			/* 18.8.36 shadow CT_BooleanProperty */
			case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
			case '<shadow/>': font.shadow = 1; break;

			/* 18.8.12 condense CT_BooleanProperty */
			case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
			case '<condense/>': font.condense = 1; break;

			/* 18.8.17 extend CT_BooleanProperty */
			case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
			case '<extend/>': font.extend = 1; break;

			/* 18.4.11 sz CT_FontSize */
			case '<sz': if(y.val) font.sz = +y.val; break;
			case '<sz/>': case '</sz>': break;

			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
			case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
			case '<vertAlign/>': case '</vertAlign>': break;

			/* 18.8.18 family CT_FontFamily */
			case '<family': if(y.val) font.family = parseInt(y.val,10); break;
			case '<family/>': case '</family>': break;

			/* 18.8.35 scheme CT_FontScheme */
			case '<scheme': if(y.val) font.scheme = y.val; break;
			case '<scheme/>': case '</scheme>': break;

			/* 18.4.1 charset CT_IntProperty */
			case '<charset':
				if(y.val == '1') break;
				y.codepage = CS2CP[parseInt(y.val, 10)];
				break;

			/* 18.?.? color CT_Color */
			case '<color':
				if(!font.color) font.color = {};
				if(y.auto) font.color.auto = parsexmlbool(y.auto);

				if(y.rgb) font.color.rgb = y.rgb.slice(-6);
				else if(y.indexed) {
					font.color.index = parseInt(y.indexed, 10);
					var icv = XLSIcv[font.color.index];
					if(font.color.index == 81) icv = XLSIcv[1];
					if(!icv) throw new Error(x);
					font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
				} else if(y.theme) {
					font.color.theme = parseInt(y.theme, 10);
					if(y.tint) font.color.tint = parseFloat(y.tint);
					if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
						font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
					}
				}

				break;
			case '<color/>': case '</color>': break;

			/* 18.2.10 extLst CT_ExtensionList ? */
			case '<extLst': case '<extLst>': case '</extLst>': break;
			case '<ext': pass = true; break;
			case '</ext>': pass = false; break;
			default: if(opts && opts.WTF) {
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
			}
		}
	});
}
1082307
function get_font_family() {
  
    $DEBUGCSS=DEBUGCSS; //=DEBUGCSS; Allow override of global setting for ad hoc debug

    // Select the appropriate font.  First determine the subtype, then check
    // the specified font-families for a candidate.

    // Resolve font-weight
    $weight = $this->__get("font_weight");
    
    if ( is_numeric($weight) ) {

      if ( $weight < 600 )
        $weight = "normal";
      else
        $weight = "bold";

    } else if ( $weight === "bold" || $weight === "bolder" ) {
      $weight = "bold";

    } else {
      $weight = "normal";

    }

    // Resolve font-style
    $font_style = $this->__get("font_style");

    if ( $weight === "bold" && ($font_style === "italic" || $font_style === "oblique") )
      $subtype = "bold_italic";
    else if ( $weight === "bold" && $font_style !== "italic" && $font_style !== "oblique" )
      $subtype = "bold";
    else if ( $weight !== "bold" && ($font_style === "italic" || $font_style === "oblique") )
      $subtype = "italic";
    else
      $subtype = "normal";
    
    // Resolve the font family
    if ($DEBUGCSS) {
      print "<pre>[get_font_family:";
      print '('.$this->_props["font_family"].'.'.$font_style.'.'.$this->__get("font_weight").'.'.$weight.'.'.$subtype.')';
    }
    $families = explode(",", $this->_props["font_family"]);
    $families = array_map('trim',$families);
    reset($families);

    $font = null;
    while ( current($families) ) {
      list(,$family) = each($families);
      //remove leading and trailing string delimiters, e.g. on font names with spaces;
      //remove leading and trailing whitespace
      $family = trim($family, " \t\n\r\x0B\"'");
      if ($DEBUGCSS) print '('.$family.')';
      $font = Font_Metrics::get_font($family, $subtype);

      if ( $font ) {
        if ($DEBUGCSS)  print '('.$font.")get_font_family]\n</pre>";
        return $font;
      }
    }

    $family = null;
    if ($DEBUGCSS)  print '(default)';
    $font = Font_Metrics::get_font($family, $subtype);

    if ( $font ) {
      if ($DEBUGCSS) print '('.$font.")get_font_family]\n</pre>";
      return $font;
    }
    throw new DOMPDF_Exception("Unable to find a suitable font replacement for: '" . $this->_props["font_family"] ."'");
    
  }
1287812
function(context, font, stroke) {
        context.font = font.font;
        context.fillStyle = font.fillStyle.toRGBA();
        if (stroke === true) {
            context.strokeStyle = font.strokeStyle.toRGBA();
            context.lineWidth = font.lineWidth;
        }
        context.textAlign = font.textAlign;
        context.textBaseline = font.textBaseline;
    }
654423
def com_google_fonts_check_fontvalidator(font):
  """"""

  # In some cases we want to override the severity level of
  # certain checks in FontValidator:
  downgrade_to_warn = [
    # There are reports that this fontval check has an out-of-date
    # understanding of valid bits in fsSelection.
    # More info at:
    # https://github.com/googlei18n/fontmake/issues/414#issuecomment-379408127
    "There are undefined bits set in fsSelection field",

    # FIX-ME: Why did we downgrade this one to WARN?
    "Misoriented contour"
  ]

  # Some other checks we want to completely disable:
  disabled_fval_checks = [
    # FontVal E4012 thinks that
    # "Versions 0x00010000 and 0x0001002 are currently
    #  the only defined versions of the GDEF table."
    # but the GDEF chapter of the OpenType specification at
    # https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
    # describes GDEF header version 1.3, which is not yet recognized
    # by FontVal, thus resulting in this spurious false-FAIL:
    "The version number is neither 0x00010000 nor 0x0001002",

    # These messages below are simply fontval given user feedback
    # on the progress of runnint it. It has nothing to do with
    # actual issues on the font files:
    "Validating glyph with index",
    "Table Test:",

    # No software is affected by Mac strings nowadays.
    # More info at: googlei18n/fontmake#414
    "The table doesn't contain strings for Mac platform",
    "The PostScript string is not present for both required platforms",

    # Font Bakery has got a native check for the xAvgCharWidth field
    # which is: com.google.fonts/check/xavgcharwidth
    "The xAvgCharWidth field does not equal the calculated value",

    # The optimal ordering suggested by FVal check W0020 seems to only be
    # relevant to performance optimizations on old versions of Windows
    # running on old hardware. Since such performance considerations
    # are most likely negligible, we're not going to bother users with
    # this check's table ordering requirements.
    # More info at:
    # https://github.com/googlefonts/fontbakery/issues/2105
    "Tables are not in optimal order",

    # Font Bakery has its own check for required/optional tables:
    # com.google.fonts/check/required_tables
    "Recommended table is missing"
  ]

  # There are also some checks that do not make
  # sense when we're dealing with variable fonts:
  VARFONT_disabled_fval_checks = [
    # Variable fonts typically do have lots of self-intersecting
    # contours because they are used to draw each portion
    # of variable glyph features.
    "Intersecting contours",
    "Intersecting components of composite glyph",

    # DeltaFormat = 32768 (same as 0x8000) means VARIATION_INDEX,
    # according to https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2
    # The FontVal problem description for this check (E5200) only mentions
    # the other values as possible valid ones. So apparently this means FontVal
    # implementation is not up-to-date with more recent versions of the OpenType spec
    # and that's why these spurious FAILs are being emitted.
    # That's good enough reason to mute it.
    # More info at:
    # https://github.com/googlefonts/fontbakery/issues/2109
    "The device table's DeltaFormat value is invalid"
  ]

  from fontTools.ttLib import TTFont
  if is_variable_font(TTFont(font)):
    disabled_fval_checks.extend(VARFONT_disabled_fval_checks)

  try:
    import subprocess
    fval_cmd = [
        "FontValidator", "-file", font, "-all-tables",
        "-report-in-font-dir", "-no-raster-tests"
    ]
    subprocess.check_output(fval_cmd, stderr=subprocess.STDOUT)
  except subprocess.CalledProcessError as e:
    filtered_msgs = ""
    for line in e.output.decode().split("\n"):
      disable_it = False
      for substring in disabled_fval_checks:
        if substring in line:
          disable_it = True
      if not disable_it:
        filtered_msgs += line + "\n"
    yield INFO, ("Microsoft Font Validator returned an error code."
                 " Output follows :\n\n{}\n").format(filtered_msgs)
  except (OSError, IOError) as error:
    yield ERROR, ("Mono runtime and/or "
                  "Microsoft Font Validator are not available!")
    raise error

  def report_message(msg, details):
    if details:
      if isinstance(details, list) and len(details) > 1:
        # We'll print lists with one item per line for
        # improved readability.
        if None in details:
          details.remove(None)

        # A designer will likely not need the full list
        # in order to fix a problem.
        # Showing only the 10 first ones is more than enough
        # and helps avoid flooding the report.
        if len(details) > 25:
          num_similar = len(details) - 10
          details = details[:10]
          details.append(f"NOTE: {num_similar} other similar"
                          " results were hidden!")
        details = '\n\t- ' + '\n\t- '.join(details)
      return f"MS-FonVal: {msg} DETAILS: {details}"
    else:
      return f"MS-FonVal: {msg}"

  xml_report_file = f"{font}.report.xml"
  html_report_file = f"{font}.report.html"
  fval_file = os.path.join(os.path.dirname(font), 'fval.xsl')

  grouped_msgs = {}
  with open(xml_report_file, "rb") as xml_report:
    import defusedxml.lxml
    doc = defusedxml.lxml.parse(xml_report)

    for report in doc.iter('Report'):
      msg = report.get("Message")
      details = report.get("Details")

      disable_it = False
      for substring in disabled_fval_checks:
        if substring in msg:
          disable_it = True
      if disable_it:
        continue

      if msg not in grouped_msgs:
        grouped_msgs[msg] = {"errortype": report.get("ErrorType"),
                             "details": [details]}
      else:
        if details not in grouped_msgs[msg]["details"]:
          # avoid cluttering the output with tons of identical reports
          # yield INFO, 'grouped_msgs[msg]["details"]: {}'.format(grouped_msgs[msg]["details"])
          grouped_msgs[msg]["details"].append(details)

  # ---------------------------
  # Clean-up generated files...
  os.remove(xml_report_file)
  # FontVal internal detail: HTML report generated only on non-Windows due to
  # Mono or the used HTML renderer not being able to render XML with a
  # stylesheet directly. https://github.com/googlefonts/fontbakery/issues/1747
  if os.path.exists(html_report_file):
    os.remove(html_report_file)
  os.remove(fval_file)

  # ---------------------------
  # Here we start emitting the grouped log messages
  for msg, data in grouped_msgs.items():
    # But before printing we try to make the "details" more
    # readable. Otherwise the user would get the text terminal
    # flooded with messy data.

    # No need to print is as a list if wereally only
    # got one log message of this kind:
    if len(data["details"]) == 1:
      data["details"] = data["details"][0]

    # Simplify the list of glyph indices by only displaying
    # their numerical values in a list:
    for glyph_index in ["Glyph index ", "glyph# "]:
      if data["details"] and \
         data["details"][0] and \
         glyph_index in data["details"][0]:
        try:
          data["details"] = {'Glyph index': [int(x.split(glyph_index)[1])
                                             for x in data["details"]]}
          break
        except ValueError:
          pass

    # And, finally, the log messages are emitted:
    if data["errortype"] == "P":
      yield PASS, report_message(msg, data["details"])

    elif data["errortype"] == "E":
      status = FAIL
      for substring in downgrade_to_warn:
        if substring in msg:
          status = WARN
      yield status, report_message(msg, data["details"])

    elif data["errortype"] == "W":
      yield WARN, report_message(msg, data["details"])

    else:
      yield INFO, report_message(msg, data["details"])
953116
function (styles) {
				if (styles) {
					var textStyles = {};
					styles = merge(styles); // create a copy to avoid altering the original object (#537)
					each(['fontSize', 'fontWeight', 'fontFamily', 'color', 'lineHeight', 'width', 'textDecoration', 'textShadow'], function (prop) {
						if (styles[prop] !== UNDEFINED) {
							textStyles[prop] = styles[prop];
							delete styles[prop];
						}
					});
					text.css(textStyles);
				}
				return baseCss.call(wrapper, styles);
			}
610097
function parseFont(fontObject) {
    const pdfStreamInput = cpyCxtParser.parseNewObject(fontObject.getObjectID());
    const fontDictionary = pdfStreamInput.toJSObject();
    // See "Introduction to Font Data Structures" from PDF specification
    if (fontDictionary.Subtype.value === 'Type0') {
      // TODO: properly support composite fonts with multiple descendants
      const descendant = cpyCxtParser
        .parseNewObject(fontDictionary.DescendantFonts.toJSArray()[0].getObjectID())
        .toJSObject();
      if (descendant.Subtype.value == 'CIDFontType2') {
        const descriptor = cpyCxtParser
          .parseNewObject(descendant.FontDescriptor.getObjectID())
          .toJSObject();
        const id = descriptor.FontFile2.getObjectID();
        const buffer = readStream(cpyCxtParser.parseNewObject(id));
        const font = Font.create(buffer, { type: 'ttf', hinting: true });
        // PDF font name does not contain sub family on Windows 10 so a more robust key
        // is computed from the font metadata
        const name = descriptor.FontName.value + ' - ' + fontMetadataKey(font.data.name);
        if (context.pdfFonts[name]) {
          const f = context.pdfFonts[name].font;
          font.data.glyf.forEach((g, i) => {
            if (g.contours && g.contours.length > 0) {
              if (!f.data.glyf[i].contours || f.data.glyf[i].contours.length === 0) {
                f.data.glyf[i] = g;
              }
            } else if (g.compound) {
              if (typeof f.data.glyf[i].compound === 'undefined'
                  && f.data.glyf[i].contours.length === 0) {
                f.data.glyf[i] = g;
              }
            }
          });
          const replacement = {};
          replacement[id] = context.pdfFonts[name].id;
          cpyCxt.replaceSourceObjects(replacement);
        } else {
          const xObjectId = printer.getObjectsContext().allocateNewObjectID();
          context.pdfFonts[name] = { id: xObjectId, font: font };
          const replacement = {};
          replacement[id] = xObjectId;
          cpyCxt.replaceSourceObjects(replacement);
        }
      }
    }
  }
159803
public function get_google_fonts() {

		// Get fonts from cache.
		self::$google_fonts = get_site_transient( 'kirki_googlefonts_cache' );

		// If cache is populated, return cached fonts array.
		if ( self::$google_fonts ) {
			return self::$google_fonts;
		}

		// If we got this far, cache was empty so we need to get from JSON.
		$fonts = $this->get_array();

		self::$google_fonts = [];
		if ( is_array( $fonts ) ) {
			foreach ( $fonts['items'] as $font ) {
				self::$google_fonts[ $font['family'] ] = [
					'label'    => $font['family'],
					'variants' => $font['variants'],
					'category' => $font['category'],
				];
			}
		}

		// Apply the 'kirki_fonts_google_fonts' filter.
		self::$google_fonts = apply_filters( 'kirki_fonts_google_fonts', self::$google_fonts );

		// Save the array in cache.
		$cache_time = apply_filters( 'kirki_googlefonts_transient_time', HOUR_IN_SECONDS );
		set_site_transient( 'kirki_googlefonts_cache', self::$google_fonts, $cache_time );

		return self::$google_fonts;
	}
1272938
function parse_FontFlags(data) {
	var d = data.read_shift(1);
	data.l++;
	var out = {
		/* fBold: d & 0x01 */
		fItalic: d & 0x02,
		/* fUnderline: d & 0x04 */
		fStrikeout: d & 0x08,
		fOutline: d & 0x10,
		fShadow: d & 0x20,
		fCondense: d & 0x40,
		fExtend: d & 0x80
	};
	return out;
}
37913
def com_google_fonts_check_family_control_chars(ttFonts):
  """"""
  # list of unacceptable control character glyph names
  # definition includes the entire control character Unicode block except:
  #    - .null (U+0000)
  #    - CR (U+000D)
  unacceptable_cc_list = [
      "uni0001",
      "uni0002",
      "uni0003",
      "uni0004",
      "uni0005",
      "uni0006",
      "uni0007",
      "uni0008",
      "uni0009",
      "uni000A",
      "uni000B",
      "uni000C",
      "uni000E",
      "uni000F",
      "uni0010",
      "uni0011",
      "uni0012",
      "uni0013",
      "uni0014",
      "uni0015",
      "uni0016",
      "uni0017",
      "uni0018",
      "uni0019",
      "uni001A",
      "uni001B",
      "uni001C",
      "uni001D",
      "uni001E",
      "uni001F"
  ]

  # a dict with key:value of font path that failed check : list of unacceptable glyph names
  failed_font_dict = {}

  for ttFont in ttFonts:
    font_failed = False
    unacceptable_glyphs_in_set = []  # a list of unacceptable glyph names identified
    glyph_name_set = set(ttFont["glyf"].glyphs.keys())
    fontname = ttFont.reader.file.name

    for unacceptable_glyph_name in unacceptable_cc_list:
      if unacceptable_glyph_name in glyph_name_set:
        font_failed = True
        unacceptable_glyphs_in_set.append(unacceptable_glyph_name)

    if font_failed:
        failed_font_dict[fontname] = unacceptable_glyphs_in_set

  if len(failed_font_dict) > 0:
    unacceptable_cc_report_string = "The following unacceptable control characters were identified:\n"
    for fnt in failed_font_dict.keys():
      unacceptable_cc_report_string += " {}: {}\n".format(
          fnt, ", ".join(failed_font_dict[fnt])
      )
    yield FAIL, ("{}".format(unacceptable_cc_report_string))
  else:
    yield PASS, ("Unacceptable control characters were not identified.")
1232256
def maxCtxFont(font):
    """"""

    maxCtx = 0
    for tag in ('GSUB', 'GPOS'):
        if tag not in font:
            continue
        table = font[tag].table
        if table.LookupList is None:
            continue
        for lookup in table.LookupList.Lookup:
            for st in lookup.SubTable:
                maxCtx = maxCtxSubtable(maxCtx, tag, lookup.LookupType, st)
    return maxCtx
1314855
function isFontInstalled(fontName) {
  const testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';
  const testText = 'mmmmmmmmmmwwwww';
  const testSize = '200px';

  var canvas = document.createElement('canvas');
  var context = canvas.getContext('2d');

  context.font = testSize + " '" + testFontName + "'";
  const originalWidth = context.measureText(testText).width;

  context.font = testSize + " '" + fontName + "', '" + testFontName + "'";
  const width = context.measureText(testText).width;

  return originalWidth !== width;
}
956904
function checkFont() {
      fontName      = fontdetect.whichFont($contentDomNode[0]);
      isFontLoaded  = fontdetect.isFontLoaded(fontName);

      if (!isFontLoaded) {
        $el.append(jQuery('<div/>').css('fontFamily',fontName).addClass('ut-font-detect'));
        fontdetect.onFontLoaded(fontName, function(){
          isFontLoaded = true;
          $('.ut-font-detect',$el).remove();
        }, function(){
          isFontLoaded = false;
          $('.ut-font-detect',$el).remove();
        }, {msInterval: 100, msTimeout: 10000});
      }
    }
896868
function AutosizeText($text, $w, $font, $style, $szfont = 72)
	{

		$text = ' ' . $text . ' ';

		$this->SetFont($font, $style, $szfont, false);

		$text = $this->purify_utf8_text($text);
		if ($this->text_input_as_HTML) {
			$text = $this->all_entities_to_utf8($text);
		}
		if ($this->usingCoreFont) {
			$text = mb_convert_encoding($text, $this->mb_enc, 'UTF-8');
		}

		// DIRECTIONALITY
		if (preg_match("/([" . $this->pregRTLchars . "])/u", $text)) {
			$this->biDirectional = true;
		}

		$textvar = 0;
		$save_OTLtags = $this->OTLtags;
		$this->OTLtags = [];

		if ($this->useKerning) {
			if ($this->CurrentFont['haskernGPOS']) {
				$this->OTLtags['Plus'] .= ' kern';
			} else {
				$textvar = ($textvar | TextVars::FC_KERNING);
			}
		}

		/* -- OTL -- */
		// Use OTL OpenType Table Layout - GSUB & GPOS
		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
			$text = $this->otl->applyOTL($text, $this->CurrentFont['useOTL']);
			$OTLdata = $this->otl->OTLdata;
		}
		/* -- END OTL -- */

		$this->OTLtags = $save_OTLtags;

		$this->magic_reverse_dir($text, $this->directionality, $OTLdata);

		$width = $this->sizeConverter->convert($w);
		$loop = 0;

		while ($loop == 0) {

			$this->SetFont($font, $style, $szfont, false);
			$sz = $this->GetStringWidth($text, true, $OTLdata, $textvar);

			if ($sz > $w) {
				$szfont --;
			} else {
				$loop ++;
			}
		}

		$this->SetFont($font, $style, $szfont, true, true);
		$this->Cell($w, 0, $text, 0, 0, "C", 0, '', 0, 0, 0, 'M', 0, false, $OTLdata, $textvar);
	}
958522
function _measureText(canvas, ctx, params, lines) {
	var originalSize, curWidth, l,
		propCache = caches.propCache;

	// Used cached width/height if possible
	if (propCache.text === params.text && propCache.fontStyle === params.fontStyle && propCache.fontSize === params.fontSize && propCache.fontFamily === params.fontFamily && propCache.maxWidth === params.maxWidth && propCache.lineHeight === params.lineHeight) {

		params.width = propCache.width;
		params.height = propCache.height;

	} else {
		// Calculate text dimensions only once

		// Calculate width of first line (for comparison)
		params.width = ctx.measureText(lines[0]).width;

		// Get width of longest line
		for (l = 1; l < lines.length; l += 1) {

			curWidth = ctx.measureText(lines[l]).width;
			// Ensure text's width is the width of its longest line
			if (curWidth > params.width) {
				params.width = curWidth;
			}

		}

		// Save original font size
		originalSize = canvas.style.fontSize;
		// Temporarily set canvas font size to retrieve size in pixels
		canvas.style.fontSize = params.fontSize;
		// Save text width and height in parameters object
		params.height = parseFloat($.css(canvas, 'fontSize')) * lines.length * params.lineHeight;
		// Reset font size to original size
		canvas.style.fontSize = originalSize;
	}
}
670710
function fontConvert(content, to, from) {
  if (!content) {
    if (!globalOptions.isSilentMode()) console.warn('Content must be specified on knayi.fontConvert.');
    return '';
  }

  if (content === '' || !mmCharacterRange.test(content))
    return content;

  if (!to) {
    if (!globalOptions.isSilentMode()) console.error('Convert target font must be specified on knayi.fontConvert.');
    return content;
  }

  content = content.trim().replace(/\u200B/g, '');
  to = fontTypes[to];
  from = fontTypes[from];

  if (!to) {
    if (!globalOptions.isSilentMode()) console.error('Convert library dosen\'t have this fontType.')
    return content;
  } else if (!from) {
    from = fontDetect(content);
  }

  if (to === from) {
    return content;
  }

  var debug_logs = {
    to: to, from: from,
    matched_patterns: [],
    steps: []
  }

  content = spellingFix(content, from);
  var refLib = library.convert[from][to];

  for (var i = 0; i < refLib.oneTime.length; i++) {
    var rule1 = refLib.oneTime[i];
    // debugging
    if (this.debug && rule1[0].test(content)) {
      debug_logs.matched_patterns.push(rule1);
      debug_logs.steps.push(content);
    }
    content = content.replace(rule1[0], rule1[1]);
  }

  for (var j = 0; j < refLib.asLongAsMatch.length; j++) {
    var rule2 = refLib.asLongAsMatch[j];
    // debugging
    if (this.debug && rule2[0].test(content)) {
      debug_logs.matched_patterns.push(rule2);
      debug_logs.steps.push(content);
    }
    while (rule2[0].test(content)) {
      content = content.replace(rule2[0], rule2[1]);
    }
  }

  if (this.debug) {
    // final
    debug_logs.steps.push(content);
    return debug_logs;
  }

  return content;
}
1244913
function parse_clrScheme(t, themes, opts) {
	themes.themeElements.clrScheme = [];
	var color = {};
	(t[0].match(tagregex)||[]).forEach(function(x) {
		var y = parsexmltag(x);
		switch(y[0]) {
			/* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
			case '<a:clrScheme': case '</a:clrScheme>': break;

			/* 20.1.2.3.32 srgbClr CT_SRgbColor */
			case '<a:srgbClr':
				color.rgb = y.val; break;

			/* 20.1.2.3.33 sysClr CT_SystemColor */
			case '<a:sysClr':
				color.rgb = y.lastClr; break;

			/* 20.1.4.1.1 accent1 (Accent 1) */
			/* 20.1.4.1.2 accent2 (Accent 2) */
			/* 20.1.4.1.3 accent3 (Accent 3) */
			/* 20.1.4.1.4 accent4 (Accent 4) */
			/* 20.1.4.1.5 accent5 (Accent 5) */
			/* 20.1.4.1.6 accent6 (Accent 6) */
			/* 20.1.4.1.9 dk1 (Dark 1) */
			/* 20.1.4.1.10 dk2 (Dark 2) */
			/* 20.1.4.1.15 folHlink (Followed Hyperlink) */
			/* 20.1.4.1.19 hlink (Hyperlink) */
			/* 20.1.4.1.22 lt1 (Light 1) */
			/* 20.1.4.1.23 lt2 (Light 2) */
			case '<a:dk1>': case '</a:dk1>':
			case '<a:lt1>': case '</a:lt1>':
			case '<a:dk2>': case '</a:dk2>':
			case '<a:lt2>': case '</a:lt2>':
			case '<a:accent1>': case '</a:accent1>':
			case '<a:accent2>': case '</a:accent2>':
			case '<a:accent3>': case '</a:accent3>':
			case '<a:accent4>': case '</a:accent4>':
			case '<a:accent5>': case '</a:accent5>':
			case '<a:accent6>': case '</a:accent6>':
			case '<a:hlink>': case '</a:hlink>':
			case '<a:folHlink>': case '</a:folHlink>':
				if (y[0].charAt(1) === '/') {
					themes.themeElements.clrScheme.push(color);
					color = {};
				} else {
					color.name = y[0].substring(3, y[0].length - 1);
				}
				break;

			default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
		}
	});
}
509085
function rewriteFonts () {
  const style = path.join(target, 'css', 'style.css')
  const css = fs.readFileSync(style)
    .toString()
    .replace(/@import url\(.*?Roboto.*?\);/, `@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600|Source+Code+Pro:400,600');`)
    .replace(/Roboto/g, 'Open Sans')

  fs.writeFileSync(style, `
    ${css}

    code {
      font-family: 'Source Code Pro', monospace;
    }

    pre > code {
      padding: 0.75em 1em;
      line-height: 1.5em;
    }

    ul, ol {
      margin-bottom: 15px;
    }

    hr {
      border: 0;
      height: 2px;
      background: #f5f5f5;
      margin: 15px 0;
    }

    blockquote {
      border-left: 3px solid #eee;
      padding-left: 0.75em;
      margin-bottom: 15px;
      color: #999;
      font-size: 0.9em;
    }
  `)
}