Check font has same encoded glyphs as version hosted on
  fonts.google.com
356362
def com_google_fonts_check_production_encoded_glyphs(ttFont, api_gfonts_ttFont):
  """"""
  cmap = ttFont['cmap'].getcmap(3, 1).cmap
  gf_cmap = api_gfonts_ttFont['cmap'].getcmap(3, 1).cmap
  missing_codepoints = set(gf_cmap.keys()) - set(cmap.keys())

  if missing_codepoints:
    hex_codepoints = ['0x' + hex(c).upper()[2:].zfill(4) for c
                      in missing_codepoints]
    yield FAIL, ("Font is missing the following glyphs"
                 " from the previous release"
                 " [{}]").format(', '.join(hex_codepoints))
  else:
    yield PASS, ('Font has all the glyphs from the previous release')
1145406
def com_google_fonts_check_fontbakery_version():
  """"""

  try:
    import subprocess
    installed_str = None
    latest_str = None
    is_latest = False
    failed = False
    pip_cmd = ["pip", "search", "fontbakery"]
    pip_output = subprocess.check_output(pip_cmd, stderr=subprocess.STDOUT)
    for line in pip_output.decode().split('\n'):
      if 'INSTALLED' in line:
        installed_str = line.split('INSTALLED')[1].strip()
      if 'LATEST' in line:
        latest_str = line.split('LATEST')[1].strip()
      if '(latest)' in line:
        is_latest = True

    if not (is_latest or is_up_to_date(installed_str, latest_str)):
      failed = True
      yield FAIL, (f"Current Font Bakery version is {installed_str},"
                   f" while a newer {latest_str} is already available."
                    " Please upgrade it with 'pip install -U fontbakery'")
    yield INFO, pip_output.decode()
  except subprocess.CalledProcessError as e:
    yield ERROR, ("Running 'pip search fontbakery' returned an error code."
                  " Output follows :\n\n{}\n").format(e.output.decode())

  if not failed:
    yield PASS, "Font Bakery is up-to-date"
1199146
def font(self):
        """"""
        if self._font is not None:
            return self._font

        # Sort UFOS in the original order from the Glyphs file
        sorted_sources = self.to_glyphs_ordered_masters()

        # Convert all full source UFOs to Glyphs masters. Sources with layer names
        # are assumed to be sparse or "brace" layers and are ignored because Glyphs
        # considers them to be special layers and will handle them itself.
        self._font = self.glyphs_module.GSFont()
        self._sources = OrderedDict()  # Same as in UFOBuilder
        for index, source in enumerate(s for s in sorted_sources if not s.layerName):
            master = self.glyphs_module.GSFontMaster()

            # Filter bracket glyphs out of public.glyphOrder.
            if GLYPH_ORDER_KEY in source.font.lib:
                source.font.lib[GLYPH_ORDER_KEY] = [
                    glyph_name
                    for glyph_name in source.font.lib[GLYPH_ORDER_KEY]
                    if ".BRACKET." not in glyph_name
                ]

            self.to_glyphs_font_attributes(source, master, is_initial=(index == 0))
            self.to_glyphs_master_attributes(source, master)
            self._font.masters.insert(len(self._font.masters), master)
            self._sources[master.id] = source

            # First, move free-standing bracket glyphs back to layers to avoid dealing
            # with GSLayer transplantation.
            for bracket_glyph in [g for g in source.font if ".BRACKET." in g.name]:
                base_glyph, threshold = bracket_glyph.name.split(".BRACKET.")
                try:
                    int(threshold)
                except ValueError:
                    raise ValueError(
                        "Glyph '{}' has malformed bracket layer name. Must be '<glyph "
                        "name>.BRACKET.<crossover value>'.".format(bracket_glyph)
                    )
                layer_name = bracket_glyph.lib.get(
                    GLYPHLIB_PREFIX + "_originalLayerName", "[{}]".format(threshold)
                )
                if layer_name not in source.font.layers:
                    ufo_layer = source.font.newLayer(layer_name)
                else:
                    ufo_layer = source.font.layers[layer_name]
                bracket_glyph_new = ufo_layer.newGlyph(base_glyph)
                bracket_glyph_new.copyDataFromGlyph(bracket_glyph)

                # Remove all freestanding bracket layer glyphs from all layers.
                for layer in source.font.layers:
                    if bracket_glyph.name in layer:
                        del layer[bracket_glyph.name]

            for layer in _sorted_backgrounds_last(source.font.layers):
                self.to_glyphs_layer_lib(layer)
                for glyph in layer:
                    self.to_glyphs_glyph(glyph, layer, master)

        self.to_glyphs_features()
        self.to_glyphs_groups()
        self.to_glyphs_kerning()

        # Now that all GSGlyph are built, restore the glyph order
        if self.designspace.sources:
            first_ufo = self.designspace.sources[0].font
            if GLYPH_ORDER_KEY in first_ufo.lib:
                glyph_order = first_ufo.lib[GLYPH_ORDER_KEY]
                lookup = {name: i for i, name in enumerate(glyph_order)}
                self.font.glyphs = sorted(
                    self.font.glyphs, key=lambda glyph: lookup.get(glyph.name, 1 << 63)
                )
            # FIXME: (jany) We only do that on the first one. Maybe we should
            # merge the various `public.glyphorder` values?

            # Restore the layer ordering in each glyph
            for glyph in self._font.glyphs:
                self.to_glyphs_layer_order(glyph)

        self.to_glyphs_family_user_data_from_designspace()
        self.to_glyphs_axes()
        self.to_glyphs_sources()
        self.to_glyphs_instances()

        return self._font
522484
def _get_version():
    
    with open('Lib/fontParts/__init__.py', 'r', encoding='utf-8') as f:
        for line in f:
            if line.startswith(u'__version__'):
                return ast.parse(line).body[0].value.s
        raise RuntimeError("No __version__ string found!")
790083
def com_google_fonts_check_name_family_and_style_max_length(ttFont):
  """"""
  from fontbakery.utils import (get_name_entries,
                                get_name_entry_strings)
  failed = False
  for familyname in get_name_entries(ttFont,
                                     NameID.FONT_FAMILY_NAME):
    # we'll only match family/style name entries with the same platform ID:
    plat = familyname.platformID
    familyname_str = familyname.string.decode(familyname.getEncoding())
    for stylename_str in get_name_entry_strings(ttFont,
                                                NameID.FONT_SUBFAMILY_NAME,
                                                platformID=plat):
      if len(familyname_str + stylename_str) > 27:
        failed = True
        yield WARN, ("The combined length of family and style"
                     " exceeds 27 chars in the following '{}' entries:"
                     " FONT_FAMILY_NAME = '{}' / SUBFAMILY_NAME = '{}'"
                     "").format(PlatformID(plat).name,
                                familyname_str,
                                stylename_str)
        yield WARN, ("Please take a look at the conversation at"
                     " https://github.com/googlefonts/fontbakery/issues/2179"
                     " in order to understand the reasoning behing these"
                     " name table records max-length criteria.")
  if not failed:
    yield PASS, "All name entries are good."
61887
def com_google_fonts_check_metadata_regular_is_400(family_metadata):
  """"""
  badfonts = []
  for f in family_metadata.fonts:
    if f.full_name.endswith("Regular") and f.weight != 400:
      badfonts.append(f"{f.filename} (weight: {f.weight})")
  if len(badfonts) > 0:
    yield FAIL, ("METADATA.pb: Regular font weight must be 400."
                 " Please fix these: {}").format(", ".join(badfonts))
  else:
    yield PASS, "Regular has weight = 400."
167403
def com_google_fonts_check_aat(ttFont):
  """"""
  UNWANTED_TABLES = {
    'EBSC', 'Zaph', 'acnt', 'ankr', 'bdat', 'bhed', 'bloc',
    'bmap', 'bsln', 'fdsc', 'feat', 'fond', 'gcid', 'just',
    'kerx', 'lcar', 'ltag', 'mort', 'morx', 'opbd', 'prop',
    'trak', 'xref'
  }
  unwanted_tables_found = []
  for table in ttFont.keys():
    if table in UNWANTED_TABLES:
      unwanted_tables_found.append(table)

  if len(unwanted_tables_found) > 0:
    yield FAIL, ("Unwanted AAT tables were found"
                 " in the font and should be removed, either by"
                 " fonttools/ttx or by editing them using the tool"
                 " they built with:"
                 " {}").format(", ".join(unwanted_tables_found))
  else:
    yield PASS, "There are no unwanted AAT tables."
382135
def com_google_fonts_check_post_table_version(ttFont, is_ttf):
  """"""
  formatType = ttFont['post'].formatType
  if is_ttf:
    expected = 2
  else:
    expected = 3
  if formatType != expected:
    yield FAIL, ("Post table should be version {} instead of {}."
                 " More info at https://github.com/google/fonts/"
                 "issues/215").format(expected, formatType)
  else:
    yield PASS, f"Font has post table version {expected}."
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"])
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;
	}
822500
function hasFontLoaded (window, fontName) {
    var testSize = 16
    if (!fontTestElement) {
        fontTestElement = window.document.createElement('canvas')
        fontTestElement.width = testSize
        fontTestElement.height = testSize
        fontTestElement.style.display = 'none'

        ctx = fontTestElement.getContext('2d')
        window.document.body.appendChild(fontTestElement)
    }

    fontTestElement.width = testSize
    ctx.fillStyle = 'rgba(0, 0, 0, 0)'
    ctx.fillRect(0, 0, testSize, testSize)
    ctx.font = testSize + "px __cc2d_" + fontName
    ctx.fillStyle = 'rgba(255, 255, 255, 1)'
    ctx.fillText("M", 0, testSize);

    var pixels = ctx.getImageData(0, 0, testSize, testSize).data

    for (var i = 0; i < testSize * testSize; i++) {
        if (pixels[i * 4] != 0) {
            fontTestElement.parentNode.removeChild(fontTestElement)
            fontTestElement = null
            return true
        }
    }

    return false
}
619202
def com_google_fonts_check_fontforge(fontforge_check_results, fontforge_skip_checks):
  """"""
  if "skip" in fontforge_check_results:
    yield SKIP, fontforge_check_results["skip"]
    return

  validation_state = fontforge_check_results["validation_state"]
  fontforge_checks = (
      ("Contours are closed?",
       0x2, FAIL,
       "Contours are not closed!", "Contours are closed.")

    , ("Contours do not intersect",
       0x4, WARN,
       "There are countour intersections!",
       "Contours do not intersect.")

    , ("Contours have correct directions",
       0x8, WARN,
       "Contours have incorrect directions!",
       "Contours have correct directions.")

    , ("References in the glyph haven't been flipped",
       0x10, FAIL,
       "References in the glyph have been flipped!",
       "References in the glyph haven't been flipped.")

    , ("Glyphs have points at extremas",
       0x20, WARN,
       "Glyphs do not have points at extremas!",
       "Glyphs have points at extremas.")

    , ("Glyph names referred to from glyphs present in the font",
       0x40, FAIL,
       "Glyph names referred to from glyphs"
       " not present in the font!",
       "Glyph names referred to from glyphs"
       " present in the font.")

    , ("Points (or control points) are not too far apart",
       0x40000, FAIL,
       "Points (or control points) are too far apart!",
       "Points (or control points) are not too far apart.")

    , ("Not more than 1,500 points in any glyph"
       " (a PostScript limit)",
       0x80, FAIL,
       "There are glyphs with more than 1,500 points!"
       "Exceeds a PostScript limit.",
       "Not more than 1,500 points in any glyph"
       " (a PostScript limit).")

    , ("PostScript has a limit of 96 hints in glyphs",
       0x100, FAIL,
       "Exceeds PostScript limit of 96 hints per glyph",
       "Font respects PostScript limit of 96 hints per glyph")

    , ("Font doesn't have invalid glyph names",
       0x200, FAIL,
       "Font has invalid glyph names!",
       "Font doesn't have invalid glyph names.")

    , ("Glyphs have allowed numbers of points defined in maxp",
       0x400, FAIL,
       "Glyphs exceed allowed numbers of points defined in maxp",
       "Glyphs have allowed numbers of points defined in maxp.")

    , ("Glyphs have allowed numbers of paths defined in maxp",
       0x800, FAIL,
       "Glyphs exceed allowed numbers of paths defined in maxp!",
       "Glyphs have allowed numbers of paths defined in maxp.")

    , ("Composite glyphs have allowed numbers"
       " of points defined in maxp?",
       0x1000, FAIL,
       "Composite glyphs exceed allowed numbers"
       " of points defined in maxp!",
       "Composite glyphs have allowed numbers"
       " of points defined in maxp.")

    , ("Composite glyphs have allowed numbers"
       " of paths defined in maxp",
       0x2000, FAIL,
       "Composite glyphs exceed"
       " allowed numbers of paths defined in maxp!",
       "Composite glyphs have"
       " allowed numbers of paths defined in maxp.")

    , ("Glyphs instructions have valid lengths",
       0x4000, FAIL,
       "Glyphs instructions have invalid lengths!",
       "Glyphs instructions have valid lengths.")

    , ("Points in glyphs are integer aligned",
       0x80000, FAIL,
       "Points in glyphs are not integer aligned!",
       "Points in glyphs are integer aligned.")

    # According to the opentype spec, if a glyph contains an anchor point
    # for one anchor class in a subtable, it must contain anchor points
    # for all anchor classes in the subtable. Even it, logically,
    # they do not apply and are unnecessary.
    , ("Glyphs have all required anchors.",
       0x100000, FAIL,
       "Glyphs do not have all required anchors!",
       "Glyphs have all required anchors.")

    , ("Glyph names are unique?",
       0x200000, FAIL,
       "Glyph names are not unique!",
       "Glyph names are unique.")

    , ("Unicode code points are unique?",
       0x400000, FAIL,
       "Unicode code points are not unique!",
       "Unicode code points are unique.")

    , ("Do hints overlap?",
       0x800000, FAIL,
       "Hints should NOT overlap!",
       "Hints do not overlap.")
  )

  for description, bit, failure_status_override, fail_msg, ok_msg in fontforge_checks:
    if fontforge_skip_checks is not None and \
       bool(fontforge_skip_checks & bit) is not False:
      yield SKIP, description
    elif bool(validation_state & bit) is not False:
      yield failure_status_override, f"fontforge-check: {fail_msg}"
    else:
      yield PASS, f"fontforge-check: {ok_msg}"
28339
def has_kerning_info(ttFont):
  """"""
  if "GPOS" not in ttFont:
    return False

  if not ttFont["GPOS"].table.LookupList:
    return False

  for lookup in ttFont["GPOS"].table.LookupList.Lookup:
    if lookup.LookupType == 2:  # type 2 = Pair Adjustment
      return True
    elif lookup.LookupType == 9:  # type 9 = Extension subtable
      for ext in lookup.SubTable:
        if ext.ExtensionLookupType == 2:  # type 2 = Pair Adjustment
          return True
804091
def check(*args, **kwds):
  
  def wrapper(checkfunc):
    return wraps(checkfunc)(FontBakeryCheck(checkfunc, *args, **kwds))
  return wrapper
782845
def com_google_fonts_check_vendor_id(ttFont, registered_vendor_ids):
  """"""

  SUGGEST_MICROSOFT_VENDORLIST_WEBSITE = (
    " You should set it to your own 4 character code,"
    " and register that code with Microsoft at"
    " https://www.microsoft.com"
  "/typography/links/vendorlist.aspx")

  vid = ttFont['OS/2'].achVendID
  bad_vids = ['UKWN', 'ukwn', 'PfEd']
  if vid is None:
    yield WARN, Message("not set", "OS/2 VendorID is not set." +
                                   SUGGEST_MICROSOFT_VENDORLIST_WEBSITE)
  elif vid in bad_vids:
    yield WARN, Message("bad", ("OS/2 VendorID is '{}',"
                                " a font editor default.").format(vid) +
                                SUGGEST_MICROSOFT_VENDORLIST_WEBSITE)
  elif vid not in registered_vendor_ids.keys():
    yield WARN, Message("unknown", ("OS/2 VendorID value '{}' is not"
                                    " a known registered id.").format(vid) +
                                    SUGGEST_MICROSOFT_VENDORLIST_WEBSITE)
  else:
    yield PASS, f"OS/2 VendorID '{vid}' looks good!"
1168649
def com_google_fonts_check_metadata_unique_full_name_values(family_metadata):
  
  fonts = {}
  for f in family_metadata.fonts:
    fonts[f.full_name] = f

  if len(set(fonts.keys())) != len(family_metadata.fonts):
    yield FAIL, ("Found duplicated \"full_name\" values"
                 " in METADATA.pb fonts field.")
  else:
    yield PASS, ("METADATA.pb \"fonts\" field only has"
                 " unique \"full_name\" values.")
577564
public static function is_google_font( $fontname ) {
		if ( is_string( $fontname ) ) {
			$fonts = self::get_google_fonts();
			return isset( $fonts[ $fontname ] );
		}
		return false;
	}