diff options
Diffstat (limited to 'gfx/src/nsFont.cpp')
-rw-r--r-- | gfx/src/nsFont.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/gfx/src/nsFont.cpp b/gfx/src/nsFont.cpp new file mode 100644 index 000000000..c5b1f09f0 --- /dev/null +++ b/gfx/src/nsFont.cpp @@ -0,0 +1,297 @@ +/* -*- 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; + } +} |