def validateDesignspaceDoc(dsDoc, dsoptions, **kwArgs):
    """
    Validate the dsDoc DesignSpaceDocument object, using supplied dsoptions
    and kwArgs. Raises Exceptions if certain criteria are not met. These
    are above and beyond the basic validations in fontTools.designspaceLib
    and are specific to makeinstancesufo.
    """
    if dsDoc.sources:
        for src in dsDoc.sources:
            if not os.path.exists(src.path):
                raise DesignSpaceDocumentError(
                    f"Source file {src.path} does not exist")
    else:
        raise DesignSpaceDocumentError("Designspace file contains no sources.")

    if dsDoc.instances:
        if dsoptions.indexList:
            # bounds check on indexList
            maxinstidx = max(dsoptions.indexList)
            if maxinstidx >= len(dsDoc.instances):
                raise IndexError(f"Instance index {maxinstidx} out-of-range")
    else:
        raise DesignSpaceDocumentError(
            "Designspace file contains no instances.")

    for i, inst in enumerate(dsDoc.instances):
        if dsoptions.indexList and i not in dsoptions.indexList:
            continue
        for attr_name in ('familyName', 'postScriptFontName', 'styleName'):
            if getattr(inst, attr_name, None) is None:
                logger.warning(
                    f"Instance at index {i} has no '{attr_name}' attribute.")
        if inst.path is None:
            raise DesignSpaceDocumentError(
                f"Instance at index {i} has no 'filename' attribute.")
Exemplo n.º 2
0
def validateDesignspaceDoc(dsDoc, dsoptions, **kwArgs):
    """
    Validate the dsDoc DesignSpaceDocument object, using supplied dsoptions
    and kwArgs. Raises Exceptions if certain criteria are not met. These
    are above and beyond the basic validations in fontTools.designspaceLib
    and are specific to makeinstancesufo.
    """
    if dsDoc.sources:
        for src in dsDoc.sources:
            if not os.path.exists(src.path):
                raise DesignSpaceDocumentError(
                    "Source file {} does not exist".format(src.path, ))
    else:
        raise DesignSpaceDocumentError("Designspace file contains no sources.")

    if dsDoc.instances:
        if dsoptions.indexList:
            # bounds check on indexList
            maxinstidx = max(dsoptions.indexList)
            if maxinstidx >= len(dsDoc.instances):
                raise IndexError("Instance index {} out-of-range".format(
                    maxinstidx, ))
    else:
        raise DesignSpaceDocumentError(
            "Designspace file contains no instances.")
Exemplo n.º 3
0
def validateDesignspaceDoc(dsDoc, dsoptions, **kwArgs):
    """
    Validate the dsDoc DesignSpaceDocument object, using supplied dsoptions
    and kwArgs. Raises Exceptions if certain criteria are not met. These
    are above and beyond the basic validations in fontTools.designspaceLib
    and are specific to makeinstancesufo.
    """
    if dsDoc.sources:
        for src in dsDoc.sources:
            if not os.path.exists(src.path):
                raise DesignSpaceDocumentError(
                    f"Source file {src.path} does not exist")
    else:
        raise DesignSpaceDocumentError("Designspace file contains no sources.")

    if dsDoc.instances:
        if dsoptions.indexList:
            # bounds check on indexList
            maxinstidx = max(dsoptions.indexList)
            if maxinstidx >= len(dsDoc.instances):
                raise IndexError(f"Instance index {maxinstidx} out-of-range")
    else:
        raise DesignSpaceDocumentError(
            "Designspace file contains no instances.")

    if dsoptions.useVarlib:
        axis_map = dict()
        for axis in dsDoc.axes:
            ad = axis.asdict()
            axis_map[ad['name']] = axis

    for i, inst in enumerate(dsDoc.instances):
        if dsoptions.indexList and i not in dsoptions.indexList:
            continue
        for attr_name in ('familyname', 'postscriptfontname', 'stylename'):
            if getattr(inst, attr_name, None) is None:
                logger.warning(
                    f"Instance at index {i} has no '{attr_name}' attribute.")
        if inst.path is None:
            raise DesignSpaceDocumentError(
                f"Instance at index {i} has no 'filename' attribute.")

        if dsoptions.useVarlib:
            # check for extrapolation, which is not supported by varLib
            # for these only warn, do not raise exception
            for dim, val in inst.location.items():
                axis = axis_map[dim]
                mval = axis.map_backward(val)
                if mval < axis.minimum or mval > axis.maximum:
                    logger.warning("Extrapolation is not supported with varlib"
                                   f" ({inst.familyName} {inst.styleName} "
                                   f"{dim}: {val})")
def validateDesignspaceDoc(dsDoc, **kwArgs):
    """
    Validate the dsDoc DesignSpaceDocument object. Raises Exceptions if
    certain criteria are not met. These are above and beyond the basic
    validations in fontTools.designspaceLib and are specific to
    buildmasterotfs.
    """
    if dsDoc.sources:
        for src in dsDoc.sources:
            if not os.path.exists(src.path):
                raise DesignSpaceDocumentError(
                    f"Source file {src.path} does not exist")
    else:
        raise DesignSpaceDocumentError("Designspace file contains no sources.")
Exemplo n.º 5
0
def buildVFStatTable(ttFont: TTFont, doc: DesignSpaceDocument,
                     vfName: str) -> None:
    """Build the STAT table for the variable font identified by its name in
    the given document.

    Knowing which variable we're building STAT data for is needed to subset
    the STAT locations to only include what the variable font actually ships.

    .. versionadded:: 5.0

    .. seealso::
        - :func:`getStatAxes()`
        - :func:`getStatLocations()`
        - :func:`fontTools.otlLib.builder.buildStatTable()`
    """
    for vf in doc.getVariableFonts():
        if vf.name == vfName:
            break
    else:
        raise DesignSpaceDocumentError(
            f"Cannot find the variable font by name {vfName}")

    region = getVFUserRegion(doc, vf)

    return fontTools.otlLib.builder.buildStatTable(
        ttFont,
        getStatAxes(doc, region),
        getStatLocations(doc, region),
        doc.elidedFallbackName if doc.elidedFallbackName is not None else 2,
    )
Exemplo n.º 6
0
def getVFUserRegion(doc: DesignSpaceDocument,
                    vf: VariableFontDescriptor) -> Region:
    vfUserRegion: Region = {}
    # For each axis, 2 cases:
    #  - it has a range = it's an axis in the VF DS
    #  - it's a single location = use it to know which rules should apply in the VF
    for axisSubset in vf.axisSubsets:
        axis = doc.getAxis(axisSubset.name)
        if axis is None:
            raise DesignSpaceDocumentError(
                f"Cannot find axis named '{axisSubset.name}' for variable font '{vf.name}'."
            )
        if hasattr(axisSubset, "userMinimum"):
            # Mypy doesn't support narrowing union types via hasattr()
            # TODO(Python 3.10): use TypeGuard
            # https://mypy.readthedocs.io/en/stable/type_narrowing.html
            axisSubset = cast(RangeAxisSubsetDescriptor, axisSubset)
            if not hasattr(axis, "minimum"):
                raise DesignSpaceDocumentError(
                    f"Cannot select a range over '{axis.name}' for variable font '{vf.name}' "
                    "because it's a discrete axis, use only 'userValue' instead."
                )
            axis = cast(AxisDescriptor, axis)
            vfUserRegion[axis.name] = Range(
                max(axisSubset.userMinimum, axis.minimum),
                min(axisSubset.userMaximum, axis.maximum),
                axisSubset.userDefault or axis.default,
            )
        else:
            axisSubset = cast(ValueAxisSubsetDescriptor, axisSubset)
            vfUserRegion[axis.name] = axisSubset.userValue
    # Any axis not mentioned explicitly has a single location = default value
    for axis in doc.axes:
        if axis.name not in vfUserRegion:
            assert isinstance(
                axis.default,
                (int,
                 float)), f"Axis '{axis.name}' has no valid default value."
            vfUserRegion[axis.name] = axis.default
    return vfUserRegion
Exemplo n.º 7
0
def userRegionToDesignRegion(doc: DesignSpaceDocument,
                             userRegion: Region) -> Region:
    designRegion = {}
    for name, value in userRegion.items():
        axis = doc.getAxis(name)
        if axis is None:
            raise DesignSpaceDocumentError(
                f"Cannot find axis named '{name}' for region.")
        if isinstance(value, (float, int)):
            designRegion[name] = axis.map_forward(value)
        else:
            designRegion[name] = Range(
                axis.map_forward(value.minimum),
                axis.map_forward(value.maximum),
                axis.map_forward(value.default),
            )
    return designRegion