blob: cfc0de2636674ca411a89431406a2899b3976218 [file] [log] [blame]
/*
* Copyright (C) 2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WI.FontDetailsPanel = class FontDetailsPanel extends WI.StyleDetailsPanel
{
constructor(delegate)
{
const className = "font";
const identifier = "font";
const label = WI.UIString("Font", "Font @ Font Details Sidebar Title", "Title for the Font details sidebar.");
super(delegate, className, identifier, label);
this._fontPropertiesMap = new Map;
this._fontVariationsMap = new Map;
this._fontFeaturesMap = new Map;
}
// Public
refresh(significantChange)
{
super.refresh(significantChange);
let fontMap = this.nodeStyles.computedPrimaryFont?.calculateFontProperties(this.nodeStyles) ?? {};
this._fontPropertiesMap = fontMap.propertiesMap ?? new Map;
this._fontVariationsMap = fontMap.variationsMap ?? new Map;
this._fontFeaturesMap = fontMap.featuresMap ?? new Map;
this._fontNameRow.value = this.nodeStyles.computedPrimaryFont.name;
this._fontSizeRow.value = this._formatSizeValue(this._fontPropertiesMap.get("font-size"));
this._fontStyleRow.value = this._formatStyleValue(this._fontPropertiesMap.get("font-style"));
this._fontWeightRow.value = this._formatSimpleSingleValue(this._fontPropertiesMap.get("font-weight"), "wght", "%s");
this._fontStretchRow.value = this._formatSimpleSingleValue(this._fontPropertiesMap.get("font-stretch"), "wdth", WI.UIString("%s%%", "%s%% @ Font Details Sidebar", "A single value expressed as a percentage where the value has already been converted from a number to a string."));
this._fontVariantLigaturesRow.value = this._formatLigatureValue(this._fontPropertiesMap.get("font-variant-ligatures"));
this._fontVariantPositionRow.value = this._formatPositionValue(this._fontPropertiesMap.get("font-variant-position"));
this._fontVariantCapsRow.value = this._formatCapitalsValue(this._fontPropertiesMap.get("font-variant-caps"));
this._fontVariantNumericRow.value = this._formatNumericValue(this._fontPropertiesMap.get("font-variant-numeric"));
this._fontVariantAlternatesRow.value = this._formatAlternatesValue(this._fontPropertiesMap.get("font-variant-alternates"));
this._fontVariantEastAsianRow.value = this._formatEastAsianValue(this._fontPropertiesMap.get("font-variant-east-asian"));
let featureRows = [];
for (let [key, value] of this._fontFeaturesMap)
featureRows.push(new WI.DetailsSectionSimpleRow(key, value));
this._fontAdditionalFeaturesGroup.rows = featureRows;
this._fontAdditionalFeaturesGroup.hidden = !featureRows.length;
let variationRows = [];
for (let [key, value] of this._fontVariationsMap) {
let name = value.name ? WI.UIString("%s (%s)").format(value.name, key) : key;
variationRows.push(new WI.DetailsSectionSimpleRow(name, this._formatVariationValue(value)));
}
if (!variationRows.length) {
let emptyRow = new WI.DetailsSectionRow(WI.UIString("No additional variation axes.", "No additional variation axes. @ Font Details Sidebar", "Message shown when there are no additional variation axes to show."));
emptyRow.showEmptyMessage();
variationRows.push(emptyRow);
}
this._fontVariationsGroup.rows = variationRows;
}
// Protected
initialLayout()
{
super.initialLayout();
// Identity
this._fontNameRow = new WI.DetailsSectionSimpleRow(WI.UIString("Name", "Name @ Font Details Sidebar Property", "Property title for the family name of the font."));
let previewGroup = new WI.DetailsSectionGroup([this._fontNameRow]);
let fontNameSection = new WI.DetailsSection("font-identity", WI.UIString("Identity", "Identity @ Font Details Sidebar Section", "Section title for font identity information."), [previewGroup]);
this.element.appendChild(fontNameSection.element);
// Basic Properties
this._fontSizeRow = new WI.DetailsSectionSimpleRow(WI.UIString("Size", "Size @ Font Details Sidebar Property", "Property title for `font-size`."));
this._fontStyleRow = new WI.DetailsSectionSimpleRow(WI.UIString("Style", "Style @ Font Details Sidebar Property", "Property title for `font-style`."));
this._fontWeightRow = new WI.DetailsSectionSimpleRow(WI.UIString("Weight", "Weight @ Font Details Sidebar Property", "Property title for `font-weight`."));
this._fontStretchRow = new WI.DetailsSectionSimpleRow(WI.UIString("Stretch", "Stretch @ Font Details Sidebar Property", "Property title for `font-stretch`."));
let basicPropertiesGroup = new WI.DetailsSectionGroup([this._fontSizeRow, this._fontStyleRow, this._fontWeightRow, this._fontStretchRow]);
let fontBasicPropertiesSection = new WI.DetailsSection("font-basic-properties", WI.UIString("Basic Properties", "Basic Properties @ Font Details Sidebar Section", "Section title for basic font properties."), [basicPropertiesGroup]);
this.element.appendChild(fontBasicPropertiesSection.element);
// Feature Properties
this._fontVariantLigaturesRow = new WI.DetailsSectionSimpleRow(WI.UIString("Ligatures", "Ligatures @ Font Details Sidebar Property", "Property title for `font-variant-ligatures`."));
this._fontVariantPositionRow = new WI.DetailsSectionSimpleRow(WI.UIString("Position", "Position @ Font Details Sidebar Property", "Property title for `font-variant-position`."));
this._fontVariantCapsRow = new WI.DetailsSectionSimpleRow(WI.UIString("Capitals", "Capitals @ Font Details Sidebar Property", "Property title for `font-variant-caps`."));
this._fontVariantNumericRow = new WI.DetailsSectionSimpleRow(WI.UIString("Numeric", "Numeric @ Font Details Sidebar Property", "Property title for `font-variant-numeric`."));
this._fontVariantAlternatesRow = new WI.DetailsSectionSimpleRow(WI.UIString("Alternate Glyphs", "Alternate Glyphs @ Font Details Sidebar Property", "Property title for `font-variant-alternates`."));
this._fontVariantEastAsianRow = new WI.DetailsSectionSimpleRow(WI.UIString("East Asian", "East Asian @ Font Details Sidebar Property", "Property title for `font-variant-east-asian`."));
let featurePropertiesGroup = new WI.DetailsSectionGroup([this._fontVariantLigaturesRow, this._fontVariantPositionRow, this._fontVariantCapsRow, this._fontVariantNumericRow, this._fontVariantAlternatesRow, this._fontVariantEastAsianRow]);
this._fontAdditionalFeaturesGroup = new WI.DetailsSectionGroup;
let fontFeaturePropertiesSection = new WI.DetailsSection("font-feature-properties", WI.UIString("Feature Properties", "Feature Properties @ Font Details Sidebar Section", "Section title for font feature properties."), [featurePropertiesGroup, this._fontAdditionalFeaturesGroup]);
this.element.appendChild(fontFeaturePropertiesSection.element);
// Variation Properties
this._fontVariationsGroup = new WI.DetailsSectionGroup;
let fontVariationPropertiesSection = new WI.DetailsSection("font-variation-properties", WI.UIString("Variation Properties", "Variation Properties @ Font Details Sidebar Section", "Section title for font variation properties."), [this._fontVariationsGroup]);
this.element.appendChild(fontVariationPropertiesSection.element);
}
_formatSizeValue(property)
{
return property.value;
}
_formatStyleValue(property)
{
// `slnt` is expressed in negated values relative to `oblique`.
if (this._hasVariationValue(property, "slnt"))
return WI.UIString("Oblique %ddeg", "Oblique %ddeg @ Font Details Sidebar Property Value", "Property value for oblique text.").format(-1 * parseFloat(property.variations.get("slnt").value));
if (this._hasVariationValue(property, "ital"))
return WI.UIString("Italic", "Italic @ Font Details Sidebar Property Value", "Property value for oblique text.");
if (property.value === "normal")
return WI.UIString("Normal", "Normal @ Font Details Sidebar Property Value", "Property value for any `normal` CSS value.");
return property.value;
}
_formatSimpleSingleValue(property, variationTag, variationFormat)
{
let result;
if (this._hasVariationValue(property, variationTag))
result = variationFormat.format(this._formatAxisValueAsString(property.variations.get(variationTag).value));
else
result = this._formatAxisValueAsString(property.value);
if (this._hasVariationValue(property, variationTag, {optional: true})) {
let axis = property.variations.get(variationTag);
return this._createVariationValueElement(result, axis.minimumValue, axis.maximumValue, axis.defaultValue);
}
return result;
}
_formatVariationValue(variation)
{
let value = variation.value || variation.value === 0 ? variation.value : variation.defaultValue;
return this._createVariationValueElement(this._formatAxisValueAsString(value), variation.minimumValue, variation.maximumValue, variation.defaultValue);
}
_createVariationValueElement(value, minimumValue, maximumValue, defaultValue)
{
let valueElement = document.createElement("div");
valueElement.textContent = value;
let secondaryElement = valueElement.appendChild(document.createElement("span"));
secondaryElement.className = "secondary";
secondaryElement.textContent = WI.UIString(" (Range: %s-%s, Default: %s)", " (Range: %s-%s, Default: %s) @ Font Details Sidebar", "A range and default value for a single variation axis of a font.").format(this._formatAxisValueAsString(minimumValue), this._formatAxisValueAsString(maximumValue), this._formatAxisValueAsString(defaultValue));
return valueElement;
}
_formatAxisValueAsString(value)
{
const options = {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
useGrouping: false,
}
return value.toLocaleString(undefined, options);
}
_formatSimpleFeatureValues(property, features, noMatchesResult)
{
let valueParts = property.value.match(WI.Font.SettingPattern);
let results = [];
// Only one result should be pushed per group.
let resultGroups = new Set;
for (let feature of features) {
if ((!feature.group || !resultGroups.has(feature.group)) && this._featureIsEnabled(property, feature.tag, valueParts.includes(feature.name))) {
results.push(feature.result);
resultGroups.add(feature.group);
}
}
if (results.length)
return results.join(WI.UIString(", "));
return noMatchesResult;
}
_formatLigatureValue(property)
{
let valueParts = property.value.match(WI.Font.SettingPattern);
let results = [];
// Common ligatures is a special case where it is on by default, so we have to check if they are disabled.
if (!this._featureIsEnabled(property, WI.unlocalizedString("clig"), !valueParts.includes(WI.unlocalizedString("no-common-ligatures"))))
results.push(WI.UIString("Disabled Common", "Disabled Common @ Font Details Sidebar Property Value", "Property value for `font-variant-ligatures: no-common-ligatures`."));
else
results.push(WI.UIString("Common", "Common @ Font Details Sidebar Property Value", "Property value for `font-variant-ligatures: common-ligatures`."));
// Add the other ligature features only if there was at least one to avoid concatinating with an empty string.
let otherResults = this._formatSimpleFeatureValues(property, [
{
tag: WI.unlocalizedString("dlig"),
name: WI.unlocalizedString("discretionary-ligatures"),
result: WI.UIString("Discretionary", "Discretionary @ Font Details Sidebar Property Value", "Property value for `font-variant-ligatures: discretionary-ligatures`."),
},
{
tag: WI.unlocalizedString("hlig"),
name: WI.unlocalizedString("historical-ligatures"),
result: WI.UIString("Historical", "Historical @ Font Details Sidebar Property Value", "Property value for `font-variant-ligatures: historical-ligatures`."),
},
{
tag: WI.unlocalizedString("calt"),
name: WI.unlocalizedString("contextual"),
result: WI.UIString("Contextual Alternates", "Contextual Alternates @ Font Details Sidebar Property Value", "Property value for `font-variant-ligatures: contextual`."),
},
]);
if (otherResults)
results.push(otherResults);
return results.join(WI.UIString(", "));
}
_formatPositionValue(property)
{
return this._formatSimpleFeatureValues(property, [
{
tag: WI.unlocalizedString("subs"),
name: WI.unlocalizedString("sub"),
result: WI.UIString("Subscript", "Subscript @ Font Details Sidebar Property Value", "Property value for `font-variant-position: sub`."),
group: "position",
},
{
tag: WI.unlocalizedString("sups"),
name: WI.unlocalizedString("super"),
result: WI.UIString("Superscript", "Superscript @ Font Details Sidebar Property Value", "Property value for `font-variant-position: super`."),
group: "position",
},
], WI.UIString("Normal", "Normal @ Font Details Sidebar Property Value", "Property value for any `normal` CSS value."));
}
_formatCapitalsValue(property)
{
return this._formatSimpleFeatureValues(property, [
{
tag: WI.unlocalizedString("c2sc"),
name: WI.unlocalizedString("all-small-caps"),
result: WI.UIString("All Small Capitals", "All Small Capitals @ Font Details Sidebar Property Value", "Property value for `font-variant-capitals: all-small-caps`."),
group: "capitals",
},
{
tag: WI.unlocalizedString("smcp"),
name: WI.unlocalizedString("small-caps"),
result: WI.UIString("Small Capitals", "Small Capitals @ Font Details Sidebar Property Value", "Property value for `font-variant-capitals: small-caps`."),
group: "capitals",
},
{
tag: WI.unlocalizedString("c2pc"),
name: WI.unlocalizedString("all-petite-caps"),
result: WI.UIString("All Petite Capitals", "All Petite Capitals @ Font Details Sidebar Property Value", "Property value for `font-variant-capitals: all-petite-caps`."),
group: "capitals",
},
{
tag: WI.unlocalizedString("pcap"),
name: WI.unlocalizedString("petite-caps"),
result: WI.UIString("Petite Capitals", "Petite Capitals @ Font Details Sidebar Property Value", "Property value for `font-variant-capitals: petite-caps`."),
group: "capitals",
},
{
tag: WI.unlocalizedString("unic"),
name: WI.unlocalizedString("unicase"),
result: WI.UIString("Unicase", "Unicase @ Font Details Sidebar Property Value", "Property value for `font-variant-capitals: unicase`."),
group: "capitals",
},
{
tag: WI.unlocalizedString("titl"),
name: WI.unlocalizedString("titling-caps"),
result: WI.UIString("Titling Capitals", "Titling Capitals @ Font Details Sidebar Property Value", "Property value for `font-variant-capitals: titling-caps`."),
group: "capitals",
},
], WI.UIString("Normal", "Normal @ Font Details Sidebar Property Value", "Property value for any `normal` CSS value."));
}
_formatNumericValue(property)
{
return this._formatSimpleFeatureValues(property, [
{
tag: WI.unlocalizedString("lnum"),
name: WI.unlocalizedString("lining-nums"),
result: WI.UIString("Lining Numerals", "Lining Numerals @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: lining-nums`."),
group: "figures",
},
{
tag: WI.unlocalizedString("onum"),
name: WI.unlocalizedString("oldstyle-nums"),
result: WI.UIString("Old-Style Numerals", "Old-Style Numerals @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: oldstyle-nums`."),
group: "figures",
},
{
tag: WI.unlocalizedString("pnum"),
name: WI.unlocalizedString("proportional-nums"),
result: WI.UIString("Proportional Numerals", "Proportional Numerals @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: proportional-nums`."),
group: "spacing",
},
{
tag: WI.unlocalizedString("tnum"),
name: WI.unlocalizedString("tabular-nums"),
result: WI.UIString("Tabular Numerals", "Tabular Numerals @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: tabular-nums`."),
group: "spacing",
},
{
tag: WI.unlocalizedString("frac"),
name: WI.unlocalizedString("diagonal-fractions"),
result: WI.UIString("Diagonal Fractions", "Diagonal Fractions @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: diagonal-fractions`."),
group: "fractions",
},
{
tag: WI.unlocalizedString("afrc"),
name: WI.unlocalizedString("stacked-fractions"),
result: WI.UIString("Stacked Fractions", "Stacked Fractions @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: stacked-fractions`."),
group: "fractions",
},
{
tag: WI.unlocalizedString("ordn"),
name: WI.unlocalizedString("ordinal"),
result: WI.UIString("Ordinal Letter Forms", "Ordinal Letter Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: ordinal`."),
},
{
tag: WI.unlocalizedString("zero"),
name: WI.unlocalizedString("slashed-zero"),
result: WI.UIString("Slashed Zeros", "Slashed Zeros @ Font Details Sidebar Property Value", "Property value for `font-variant-numeric: slashed-zero`."),
},
], WI.UIString("Normal", "Normal @ Font Details Sidebar Property Value", "Property value for any `normal` CSS value."));
}
_formatAlternatesValue(property)
{
return this._formatSimpleFeatureValues(property, [
{
tag: WI.unlocalizedString("hist"),
name: WI.unlocalizedString("historical-forms"),
result: WI.UIString("Historical Forms", "Historical Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: historical-forms`."),
},
], WI.UIString("Normal", "Normal @ Font Details Sidebar Property Value", "Property value for any `normal` CSS value."));
}
_formatEastAsianValue(property)
{
return this._formatSimpleFeatureValues(property, [
{
tag: WI.unlocalizedString("jp78"),
name: WI.unlocalizedString("jis78"),
result: WI.UIString("JIS78 Forms", "JIS78 Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: jis78`."),
group: "forms",
},
{
tag: WI.unlocalizedString("jp83"),
name: WI.unlocalizedString("jis83"),
result: WI.UIString("JIS83 Forms", "JIS83 Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: jis83`."),
group: "forms",
},
{
tag: WI.unlocalizedString("jp90"),
name: WI.unlocalizedString("jis90"),
result: WI.UIString("JIS90 Forms", "JIS90 Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: jis90`."),
group: "forms",
},
{
tag: WI.unlocalizedString("jp04"),
name: WI.unlocalizedString("jis04"),
result: WI.UIString("JIS2004 Forms", "JIS2004 Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: jis04`."),
group: "forms",
},
{
tag: WI.unlocalizedString("smpl"),
name: WI.unlocalizedString("simplified"),
result: WI.UIString("Simplified Forms", "Simplified Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: simplified`."),
group: "forms",
},
{
tag: WI.unlocalizedString("trad"),
name: WI.unlocalizedString("traditional"),
result: WI.UIString("Traditional Forms", "Traditional Forms @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: traditional`."),
group: "forms",
},
{
tag: WI.unlocalizedString("fwid"),
name: WI.unlocalizedString("full-width"),
result: WI.UIString("Full-Width Variants", "Full-Width Variants @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: full-width`."),
group: "width",
},
{
tag: WI.unlocalizedString("pwid"),
name: WI.unlocalizedString("proportional-width"),
result: WI.UIString("Proportional-Width Variants", "Proportional-Width Variants @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: proportional-width`."),
group: "width",
},
{
tag: WI.unlocalizedString("ruby"),
name: WI.unlocalizedString("ruby"),
result: WI.UIString("Ruby Glyphs", "Ruby Glyphs @ Font Details Sidebar Property Value", "Property value for `font-variant-alternates: ruby`."),
},
], WI.UIString("Normal", "Normal @ Font Details Sidebar Property Value", "Property value for any `normal` CSS value."));
}
_featureIsEnabled(property, featureTag, tagNotPresentCondition)
{
let featureValue = property.features?.get(featureTag);
if (featureValue || featureValue === 0)
return !!featureValue;
return tagNotPresentCondition;
}
_hasVariationValue(property, variationTag, {optional} = {})
{
if (property.variations?.has(variationTag))
return property.variations.get(variationTag).value || optional;
return false;
}
};