/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsFont.h" #include "gfxFont.h" // for gfxFontStyle #include "gfxFontConstants.h" // for NS_FONT_KERNING_AUTO, etc #include "gfxFontFeatures.h" // for gfxFontFeature, etc #include "gfxFontUtils.h" // for TRUETYPE_TAG #include "nsCRT.h" // for nsCRT #include "nsDebug.h" // for NS_ASSERTION #include "nsISupports.h" #include "nsUnicharUtils.h" #include "nscore.h" // for char16_t #include "mozilla/ArrayUtils.h" #include "mozilla/gfx/2D.h" using namespace mozilla; nsFont::nsFont(const FontFamilyList& aFontlist, nscoord aSize) : fontlist(aFontlist) { Init(); size = aSize; } nsFont::nsFont(FontFamilyType aGenericType, nscoord aSize) : fontlist(aGenericType) { Init(); size = aSize; } void nsFont::Init() { style = NS_FONT_STYLE_NORMAL; weight = NS_FONT_WEIGHT_NORMAL; stretch = NS_FONT_STRETCH_NORMAL; systemFont = false; smoothing = NS_FONT_SMOOTHING_AUTO; sizeAdjust = -1.0f; kerning = NS_FONT_KERNING_AUTO; synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE; variantAlternates = 0; variantCaps = NS_FONT_VARIANT_CAPS_NORMAL; variantEastAsian = 0; variantLigatures = 0; variantNumeric = 0; variantPosition = NS_FONT_VARIANT_POSITION_NORMAL; variantWidth = NS_FONT_VARIANT_WIDTH_NORMAL; } nsFont::nsFont(const nsFont& aOther) = default; nsFont::nsFont() { } nsFont::~nsFont() { } bool nsFont::Equals(const nsFont& aOther) const { if ((style == aOther.style) && (systemFont == aOther.systemFont) && (weight == aOther.weight) && (stretch == aOther.stretch) && (size == aOther.size) && (sizeAdjust == aOther.sizeAdjust) && (fontlist == aOther.fontlist) && (kerning == aOther.kerning) && (synthesis == aOther.synthesis) && (fontFeatureSettings == aOther.fontFeatureSettings) && (languageOverride == aOther.languageOverride) && (variantAlternates == aOther.variantAlternates) && (variantCaps == aOther.variantCaps) && (variantEastAsian == aOther.variantEastAsian) && (variantLigatures == aOther.variantLigatures) && (variantNumeric == aOther.variantNumeric) && (variantPosition == aOther.variantPosition) && (variantWidth == aOther.variantWidth) && (alternateValues == aOther.alternateValues) && (featureValueLookup == aOther.featureValueLookup) && (smoothing == aOther.smoothing)) { return true; } return false; } nsFont& nsFont::operator=(const nsFont& aOther) = default; void nsFont::CopyAlternates(const nsFont& aOther) { variantAlternates = aOther.variantAlternates; alternateValues = aOther.alternateValues; featureValueLookup = aOther.featureValueLookup; } // mapping from bitflag to font feature tag/value pair // // these need to be kept in sync with the constants listed // in gfxFontConstants.h (e.g. NS_FONT_VARIANT_EAST_ASIAN_JIS78) // NS_FONT_VARIANT_EAST_ASIAN_xxx values const gfxFontFeature eastAsianDefaults[] = { { TRUETYPE_TAG('j','p','7','8'), 1 }, { TRUETYPE_TAG('j','p','8','3'), 1 }, { TRUETYPE_TAG('j','p','9','0'), 1 }, { TRUETYPE_TAG('j','p','0','4'), 1 }, { TRUETYPE_TAG('s','m','p','l'), 1 }, { TRUETYPE_TAG('t','r','a','d'), 1 }, { TRUETYPE_TAG('f','w','i','d'), 1 }, { TRUETYPE_TAG('p','w','i','d'), 1 }, { TRUETYPE_TAG('r','u','b','y'), 1 } }; static_assert(MOZ_ARRAY_LENGTH(eastAsianDefaults) == eFeatureEastAsian_numFeatures, "eFeatureEastAsian_numFeatures should be correct"); // NS_FONT_VARIANT_LIGATURES_xxx values const gfxFontFeature ligDefaults[] = { { TRUETYPE_TAG('l','i','g','a'), 0 }, // none value means all off { TRUETYPE_TAG('l','i','g','a'), 1 }, { TRUETYPE_TAG('l','i','g','a'), 0 }, { TRUETYPE_TAG('d','l','i','g'), 1 }, { TRUETYPE_TAG('d','l','i','g'), 0 }, { TRUETYPE_TAG('h','l','i','g'), 1 }, { TRUETYPE_TAG('h','l','i','g'), 0 }, { TRUETYPE_TAG('c','a','l','t'), 1 }, { TRUETYPE_TAG('c','a','l','t'), 0 } }; static_assert(MOZ_ARRAY_LENGTH(ligDefaults) == eFeatureLigatures_numFeatures, "eFeatureLigatures_numFeatures should be correct"); // NS_FONT_VARIANT_NUMERIC_xxx values const gfxFontFeature numericDefaults[] = { { TRUETYPE_TAG('l','n','u','m'), 1 }, { TRUETYPE_TAG('o','n','u','m'), 1 }, { TRUETYPE_TAG('p','n','u','m'), 1 }, { TRUETYPE_TAG('t','n','u','m'), 1 }, { TRUETYPE_TAG('f','r','a','c'), 1 }, { TRUETYPE_TAG('a','f','r','c'), 1 }, { TRUETYPE_TAG('z','e','r','o'), 1 }, { TRUETYPE_TAG('o','r','d','n'), 1 } }; static_assert(MOZ_ARRAY_LENGTH(numericDefaults) == eFeatureNumeric_numFeatures, "eFeatureNumeric_numFeatures should be correct"); static void AddFontFeaturesBitmask(uint32_t aValue, uint32_t aMin, uint32_t aMax, const gfxFontFeature aFeatureDefaults[], nsTArray<gfxFontFeature>& aFeaturesOut) { uint32_t i, m; for (i = 0, m = aMin; m <= aMax; i++, m <<= 1) { if (m & aValue) { const gfxFontFeature& feature = aFeatureDefaults[i]; aFeaturesOut.AppendElement(feature); } } } static uint32_t FontFeatureTagForVariantWidth(uint32_t aVariantWidth) { switch (aVariantWidth) { case NS_FONT_VARIANT_WIDTH_FULL: return TRUETYPE_TAG('f','w','i','d'); case NS_FONT_VARIANT_WIDTH_HALF: return TRUETYPE_TAG('h','w','i','d'); case NS_FONT_VARIANT_WIDTH_THIRD: return TRUETYPE_TAG('t','w','i','d'); case NS_FONT_VARIANT_WIDTH_QUARTER: return TRUETYPE_TAG('q','w','i','d'); default: return 0; } } void nsFont::AddFontFeaturesToStyle(gfxFontStyle *aStyle) const { // add in font-variant features gfxFontFeature setting; // -- kerning setting.mTag = TRUETYPE_TAG('k','e','r','n'); switch (kerning) { case NS_FONT_KERNING_NONE: setting.mValue = 0; aStyle->featureSettings.AppendElement(setting); break; case NS_FONT_KERNING_NORMAL: setting.mValue = 1; aStyle->featureSettings.AppendElement(setting); break; default: // auto case implies use user agent default break; } // -- alternates if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_HISTORICAL) { setting.mValue = 1; setting.mTag = TRUETYPE_TAG('h','i','s','t'); aStyle->featureSettings.AppendElement(setting); } // -- copy font-specific alternate info into style // (this will be resolved after font-matching occurs) aStyle->alternateValues.AppendElements(alternateValues); aStyle->featureValueLookup = featureValueLookup; // -- caps aStyle->variantCaps = variantCaps; // -- east-asian if (variantEastAsian) { AddFontFeaturesBitmask(variantEastAsian, NS_FONT_VARIANT_EAST_ASIAN_JIS78, NS_FONT_VARIANT_EAST_ASIAN_RUBY, eastAsianDefaults, aStyle->featureSettings); } // -- ligatures if (variantLigatures) { AddFontFeaturesBitmask(variantLigatures, NS_FONT_VARIANT_LIGATURES_NONE, NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, ligDefaults, aStyle->featureSettings); if (variantLigatures & NS_FONT_VARIANT_LIGATURES_COMMON) { // liga already enabled, need to enable clig also setting.mTag = TRUETYPE_TAG('c','l','i','g'); setting.mValue = 1; aStyle->featureSettings.AppendElement(setting); } else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NO_COMMON) { // liga already disabled, need to disable clig also setting.mTag = TRUETYPE_TAG('c','l','i','g'); setting.mValue = 0; aStyle->featureSettings.AppendElement(setting); } else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NONE) { // liga already disabled, need to disable dlig, hlig, calt, clig setting.mValue = 0; setting.mTag = TRUETYPE_TAG('d','l','i','g'); aStyle->featureSettings.AppendElement(setting); setting.mTag = TRUETYPE_TAG('h','l','i','g'); aStyle->featureSettings.AppendElement(setting); setting.mTag = TRUETYPE_TAG('c','a','l','t'); aStyle->featureSettings.AppendElement(setting); setting.mTag = TRUETYPE_TAG('c','l','i','g'); aStyle->featureSettings.AppendElement(setting); } } // -- numeric if (variantNumeric) { AddFontFeaturesBitmask(variantNumeric, NS_FONT_VARIANT_NUMERIC_LINING, NS_FONT_VARIANT_NUMERIC_ORDINAL, numericDefaults, aStyle->featureSettings); } // -- position aStyle->variantSubSuper = variantPosition; // -- width setting.mTag = FontFeatureTagForVariantWidth(variantWidth); if (setting.mTag) { setting.mValue = 1; aStyle->featureSettings.AppendElement(setting); } // indicate common-path case when neither variantCaps or variantSubSuper are set aStyle->noFallbackVariantFeatures = (aStyle->variantCaps == NS_FONT_VARIANT_CAPS_NORMAL) && (variantPosition == NS_FONT_VARIANT_POSITION_NORMAL); // add in features from font-feature-settings aStyle->featureSettings.AppendElements(fontFeatureSettings); // enable grayscale antialiasing for text if (smoothing == NS_FONT_SMOOTHING_GRAYSCALE) { aStyle->useGrayscaleAntialiasing = true; } }