зеркало из https://github.com/mozilla/gecko-dev.git
Bug 549861. Implement gfx support for font-variant-alternates. r=jkew
This commit is contained in:
Родитель
d664a50735
Коммит
be11778d6b
|
@ -80,6 +80,8 @@ nsFont::nsFont(const nsFont& aOther)
|
|||
variantLigatures = aOther.variantLigatures;
|
||||
variantNumeric = aOther.variantNumeric;
|
||||
variantPosition = aOther.variantPosition;
|
||||
alternateValues = aOther.alternateValues;
|
||||
featureValueLookup = aOther.featureValueLookup;
|
||||
}
|
||||
|
||||
nsFont::nsFont()
|
||||
|
@ -108,7 +110,9 @@ bool nsFont::BaseEquals(const nsFont& aOther) const
|
|||
(variantEastAsian == aOther.variantEastAsian) &&
|
||||
(variantLigatures == aOther.variantLigatures) &&
|
||||
(variantNumeric == aOther.variantNumeric) &&
|
||||
(variantPosition == aOther.variantPosition)) {
|
||||
(variantPosition == aOther.variantPosition) &&
|
||||
(alternateValues == aOther.alternateValues) &&
|
||||
(featureValueLookup == aOther.featureValueLookup)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -145,9 +149,19 @@ nsFont& nsFont::operator=(const nsFont& aOther)
|
|||
variantLigatures = aOther.variantLigatures;
|
||||
variantNumeric = aOther.variantNumeric;
|
||||
variantPosition = aOther.variantPosition;
|
||||
alternateValues = aOther.alternateValues;
|
||||
featureValueLookup = aOther.featureValueLookup;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
nsFont::CopyAlternates(const nsFont& aOther)
|
||||
{
|
||||
variantAlternates = aOther.variantAlternates;
|
||||
alternateValues = aOther.alternateValues;
|
||||
featureValueLookup = aOther.featureValueLookup;
|
||||
}
|
||||
|
||||
static bool IsGenericFontFamily(const nsString& aFamily)
|
||||
{
|
||||
uint8_t generic;
|
||||
|
@ -301,6 +315,19 @@ void nsFont::AddFontFeaturesToStyle(gfxFontStyle *aStyle) const
|
|||
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
|
||||
setting.mValue = 1;
|
||||
switch (variantCaps) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsTArray.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "gfxFontFeatures.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
// XXX we need a method to enumerate all of the possible fonts on the
|
||||
// system across family, weight, style, size, etc. But not here!
|
||||
|
@ -86,6 +87,12 @@ struct NS_GFX nsFont {
|
|||
// needs to be done.
|
||||
float sizeAdjust;
|
||||
|
||||
// -- list of value tags for font-specific alternate features
|
||||
nsTArray<gfxAlternateValue> alternateValues;
|
||||
|
||||
// -- object used to look these up once the font is matched
|
||||
nsRefPtr<gfxFontFeatureValueSet> featureValueLookup;
|
||||
|
||||
// Font features from CSS font-feature-settings
|
||||
nsTArray<gfxFontFeature> fontFeatureSettings;
|
||||
|
||||
|
@ -126,6 +133,8 @@ struct NS_GFX nsFont {
|
|||
|
||||
nsFont& operator=(const nsFont& aOther);
|
||||
|
||||
void CopyAlternates(const nsFont& aOther);
|
||||
|
||||
// Add featureSettings into style
|
||||
void AddFontFeaturesToStyle(gfxFontStyle *aStyle) const;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ CPPSRCS = \
|
|||
gfxDrawable.cpp \
|
||||
gfxImageSurface.cpp \
|
||||
gfxFont.cpp \
|
||||
gfxFontFeatures.cpp \
|
||||
gfxFontMissingGlyphs.cpp \
|
||||
gfxFontTest.cpp \
|
||||
gfxFontUtils.cpp \
|
||||
|
|
|
@ -1372,20 +1372,111 @@ gfxFontCache::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
|
|||
SizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||
}
|
||||
|
||||
#define MAX_SSXX_VALUE 99
|
||||
#define MAX_CVXX_VALUE 99
|
||||
|
||||
static void
|
||||
LookupAlternateValues(gfxFontFeatureValueSet *featureLookup,
|
||||
const nsAString& aFamily,
|
||||
const nsTArray<gfxAlternateValue>& altValue,
|
||||
nsTArray<gfxFontFeature>& aFontFeatures)
|
||||
{
|
||||
uint32_t numAlternates = altValue.Length();
|
||||
for (uint32_t i = 0; i < numAlternates; i++) {
|
||||
const gfxAlternateValue& av = altValue.ElementAt(i);
|
||||
nsAutoTArray<uint32_t,4> values;
|
||||
|
||||
// map <family, name, feature> ==> <values>
|
||||
bool found =
|
||||
featureLookup->GetFontFeatureValuesFor(aFamily, av.alternate,
|
||||
av.value, values);
|
||||
uint32_t numValues = values.Length();
|
||||
|
||||
// nothing defined, skip
|
||||
if (!found || numValues == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gfxFontFeature feature;
|
||||
if (av.alternate == NS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT) {
|
||||
NS_ASSERTION(numValues <= 2,
|
||||
"too many values allowed for character-variant");
|
||||
// character-variant(12 3) ==> 'cv12' = 3
|
||||
uint32_t nn = values.ElementAt(0);
|
||||
// ignore values greater than 99
|
||||
if (nn == 0 || nn > MAX_CVXX_VALUE) {
|
||||
continue;
|
||||
}
|
||||
feature.mValue = 1;
|
||||
if (numValues > 1) {
|
||||
feature.mValue = values.ElementAt(1);
|
||||
}
|
||||
feature.mTag = HB_TAG('c','v',('0' + nn / 10), ('0' + nn % 10));
|
||||
aFontFeatures.AppendElement(feature);
|
||||
|
||||
} else if (av.alternate == NS_FONT_VARIANT_ALTERNATES_STYLESET) {
|
||||
// styleset(1 2 7) ==> 'ss01' = 1, 'ss02' = 1, 'ss07' = 1
|
||||
feature.mValue = 1;
|
||||
for (uint32_t v = 0; v < numValues; v++) {
|
||||
uint32_t nn = values.ElementAt(v);
|
||||
if (nn == 0 || nn > MAX_SSXX_VALUE) {
|
||||
continue;
|
||||
}
|
||||
feature.mTag = HB_TAG('s','s',('0' + nn / 10), ('0' + nn % 10));
|
||||
aFontFeatures.AppendElement(feature);
|
||||
}
|
||||
|
||||
} else {
|
||||
NS_ASSERTION(numValues == 1,
|
||||
"too many values for font-specific font-variant-alternates");
|
||||
feature.mValue = values.ElementAt(0);
|
||||
|
||||
switch (av.alternate) {
|
||||
case NS_FONT_VARIANT_ALTERNATES_STYLISTIC: // salt
|
||||
feature.mTag = HB_TAG('s','a','l','t');
|
||||
break;
|
||||
case NS_FONT_VARIANT_ALTERNATES_SWASH: // swsh, cswh
|
||||
feature.mTag = HB_TAG('s','w','s','h');
|
||||
aFontFeatures.AppendElement(feature);
|
||||
feature.mTag = HB_TAG('c','s','w','h');
|
||||
break;
|
||||
case NS_FONT_VARIANT_ALTERNATES_ORNAMENTS: // ornm
|
||||
feature.mTag = HB_TAG('o','r','n','m');
|
||||
break;
|
||||
case NS_FONT_VARIANT_ALTERNATES_ANNOTATION: // nalt
|
||||
feature.mTag = HB_TAG('n','a','l','t');
|
||||
break;
|
||||
default:
|
||||
feature.mTag = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
NS_ASSERTION(feature.mTag, "unsupported alternate type");
|
||||
if (!feature.mTag) {
|
||||
continue;
|
||||
}
|
||||
aFontFeatures.AppendElement(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
gfxFontShaper::MergeFontFeatures(
|
||||
const gfxFontStyle *aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFontFeatures,
|
||||
bool aDisableLigatures,
|
||||
const nsAString& aFamilyName,
|
||||
nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures)
|
||||
{
|
||||
uint32_t numAlts = aStyle->alternateValues.Length();
|
||||
const nsTArray<gfxFontFeature>& styleRuleFeatures =
|
||||
aStyle->featureSettings;
|
||||
|
||||
// bail immediately if nothing to do
|
||||
if (styleRuleFeatures.IsEmpty() &&
|
||||
aFontFeatures.IsEmpty() &&
|
||||
!aDisableLigatures) {
|
||||
!aDisableLigatures &&
|
||||
numAlts == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1407,6 +1498,21 @@ gfxFontShaper::MergeFontFeatures(
|
|||
aMergedFeatures.Put(feature.mTag, feature.mValue);
|
||||
}
|
||||
|
||||
// add font-specific feature values from style rules
|
||||
if (aStyle->featureValueLookup && numAlts > 0) {
|
||||
nsAutoTArray<gfxFontFeature,4> featureList;
|
||||
|
||||
// insert list of alternate feature settings
|
||||
LookupAlternateValues(aStyle->featureValueLookup, aFamilyName,
|
||||
aStyle->alternateValues, featureList);
|
||||
|
||||
count = featureList.Length();
|
||||
for (i = 0; i < count; i++) {
|
||||
const gfxFontFeature& feature = featureList.ElementAt(i);
|
||||
aMergedFeatures.Put(feature.mTag, feature.mValue);
|
||||
}
|
||||
}
|
||||
|
||||
// add feature values from style rules
|
||||
count = styleRuleFeatures.Length();
|
||||
for (i = 0; i < count; i++) {
|
||||
|
@ -4799,6 +4905,7 @@ gfxFontStyle::gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
|
|||
|
||||
gfxFontStyle::gfxFontStyle(const gfxFontStyle& aStyle) :
|
||||
language(aStyle.language),
|
||||
featureValueLookup(aStyle.featureValueLookup),
|
||||
size(aStyle.size), sizeAdjust(aStyle.sizeAdjust),
|
||||
languageOverride(aStyle.languageOverride),
|
||||
weight(aStyle.weight), stretch(aStyle.stretch),
|
||||
|
@ -4806,6 +4913,7 @@ gfxFontStyle::gfxFontStyle(const gfxFontStyle& aStyle) :
|
|||
kerning(aStyle.kerning), style(aStyle.style)
|
||||
{
|
||||
featureSettings.AppendElements(aStyle.featureSettings);
|
||||
alternateValues.AppendElements(aStyle.alternateValues);
|
||||
}
|
||||
|
||||
int8_t
|
||||
|
|
|
@ -80,6 +80,16 @@ struct THEBES_API gfxFontStyle {
|
|||
// custom opentype feature settings
|
||||
nsTArray<gfxFontFeature> featureSettings;
|
||||
|
||||
// Some font-variant property values require font-specific settings
|
||||
// defined via @font-feature-values rules. These are resolved after
|
||||
// font matching occurs.
|
||||
|
||||
// -- list of value tags for specific alternate features
|
||||
nsTArray<gfxAlternateValue> alternateValues;
|
||||
|
||||
// -- object used to look these up once the font is matched
|
||||
nsRefPtr<gfxFontFeatureValueSet> featureValueLookup;
|
||||
|
||||
// The logical size of the font, in pixels
|
||||
gfxFloat size;
|
||||
|
||||
|
@ -152,7 +162,9 @@ struct THEBES_API gfxFontStyle {
|
|||
*reinterpret_cast<const uint32_t*>(&other.sizeAdjust)) &&
|
||||
(kerning == other.kerning) &&
|
||||
(featureSettings == other.featureSettings) &&
|
||||
(languageOverride == other.languageOverride);
|
||||
(languageOverride == other.languageOverride) &&
|
||||
(alternateValues == other.alternateValues) &&
|
||||
(featureValueLookup == other.featureValueLookup);
|
||||
}
|
||||
|
||||
static void ParseFontFeatureSettings(const nsString& aFeatureString,
|
||||
|
@ -1158,6 +1170,7 @@ public:
|
|||
MergeFontFeatures(const gfxFontStyle *aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFontFeatures,
|
||||
bool aDisableLigatures,
|
||||
const nsAString& aFamilyName,
|
||||
nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "gfxFontFeatures.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
gfxFontFeatureValueSet::gfxFontFeatureValueSet()
|
||||
{
|
||||
mFontFeatureValues.Init(10);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFontFeatureValueSet::GetFontFeatureValuesFor(const nsAString& aFamily,
|
||||
uint32_t aVariantProperty,
|
||||
const nsAString& aName,
|
||||
nsTArray<uint32_t>& aValues)
|
||||
{
|
||||
nsAutoString family(aFamily), name(aName);
|
||||
ToLowerCase(family);
|
||||
ToLowerCase(name);
|
||||
FeatureValueHashKey key(family, aVariantProperty, name);
|
||||
|
||||
aValues.Clear();
|
||||
FeatureValueHashEntry *entry = mFontFeatureValues.GetEntry(key);
|
||||
if (entry) {
|
||||
NS_ASSERTION(entry->mValues.Length() > 0,
|
||||
"null array of font feature values");
|
||||
aValues.AppendElements(entry->mValues);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gfxFontFeatureValueSet::AddFontFeatureValues(const nsAString& aFamily,
|
||||
const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aValues)
|
||||
{
|
||||
nsAutoString family(aFamily);
|
||||
ToLowerCase(family);
|
||||
|
||||
uint32_t i, numFeatureValues = aValues.Length();
|
||||
for (i = 0; i < numFeatureValues; i++) {
|
||||
const FeatureValues& fv = aValues.ElementAt(i);
|
||||
uint32_t alternate = fv.alternate;
|
||||
uint32_t j, numValues = fv.valuelist.Length();
|
||||
for (j = 0; j < numValues; j++) {
|
||||
const ValueList& v = fv.valuelist.ElementAt(j);
|
||||
nsAutoString name(v.name);
|
||||
ToLowerCase(name);
|
||||
FeatureValueHashKey key(family, alternate, name);
|
||||
FeatureValueHashEntry *entry = mFontFeatureValues.PutEntry(key);
|
||||
entry->mKey = key;
|
||||
entry->mValues = v.featureSelectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFontFeatureValueSet::FeatureValueHashEntry::KeyEquals(
|
||||
const KeyTypePointer aKey) const
|
||||
{
|
||||
return aKey->mPropVal == mKey.mPropVal &&
|
||||
aKey->mFamily.Equals(mKey.mFamily) &&
|
||||
aKey->mName.Equals(mKey.mName);
|
||||
}
|
||||
|
||||
PLDHashNumber
|
||||
gfxFontFeatureValueSet::FeatureValueHashEntry::HashKey(
|
||||
const KeyTypePointer aKey)
|
||||
{
|
||||
return HashString(aKey->mFamily) + HashString(aKey->mName) +
|
||||
aKey->mPropVal * uint32_t(0xdeadbeef);
|
||||
}
|
||||
|
|
@ -7,6 +7,11 @@
|
|||
#ifndef GFX_FONT_FEATURES_H
|
||||
#define GFX_FONT_FEATURES_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
|
||||
// An OpenType feature tag and value pair
|
||||
struct gfxFontFeature {
|
||||
uint32_t mTag; // see http://www.microsoft.com/typography/otspec/featuretags.htm
|
||||
|
@ -26,4 +31,95 @@ operator==(const gfxFontFeature& a, const gfxFontFeature& b)
|
|||
return (a.mTag == b.mTag) && (a.mValue == b.mValue);
|
||||
}
|
||||
|
||||
struct gfxAlternateValue {
|
||||
uint32_t alternate; // constants in gfxFontConstants.h
|
||||
nsString value; // string value to be looked up
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator<(const gfxAlternateValue& a, const gfxAlternateValue& b)
|
||||
{
|
||||
return (a.alternate < b.alternate) ||
|
||||
((a.alternate == b.alternate) && (a.value < b.value));
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const gfxAlternateValue& a, const gfxAlternateValue& b)
|
||||
{
|
||||
return (a.alternate == b.alternate) && (a.value == b.value);
|
||||
}
|
||||
|
||||
class THEBES_API gfxFontFeatureValueSet {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(gfxFontFeatureValueSet)
|
||||
|
||||
gfxFontFeatureValueSet();
|
||||
virtual ~gfxFontFeatureValueSet() {}
|
||||
|
||||
struct ValueList {
|
||||
ValueList(const nsAString& aName, const nsTArray<uint32_t>& aSelectors)
|
||||
: name(aName), featureSelectors(aSelectors)
|
||||
{}
|
||||
nsString name;
|
||||
nsTArray<uint32_t> featureSelectors;
|
||||
};
|
||||
|
||||
struct FeatureValues {
|
||||
uint32_t alternate;
|
||||
nsTArray<ValueList> valuelist;
|
||||
};
|
||||
|
||||
// returns true if found, false otherwise
|
||||
bool
|
||||
GetFontFeatureValuesFor(const nsAString& aFamily,
|
||||
uint32_t aVariantProperty,
|
||||
const nsAString& aName,
|
||||
nsTArray<uint32_t>& aValues);
|
||||
void
|
||||
AddFontFeatureValues(const nsAString& aFamily,
|
||||
const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aValues);
|
||||
|
||||
protected:
|
||||
struct FeatureValueHashKey {
|
||||
nsString mFamily;
|
||||
uint32_t mPropVal;
|
||||
nsString mName;
|
||||
|
||||
FeatureValueHashKey()
|
||||
: mPropVal(0)
|
||||
{ }
|
||||
FeatureValueHashKey(const nsAString& aFamily,
|
||||
uint32_t aPropVal,
|
||||
const nsAString& aName)
|
||||
: mFamily(aFamily), mPropVal(aPropVal), mName(aName)
|
||||
{ }
|
||||
FeatureValueHashKey(const FeatureValueHashKey& aKey)
|
||||
: mFamily(aKey.mFamily), mPropVal(aKey.mPropVal), mName(aKey.mName)
|
||||
{ }
|
||||
};
|
||||
|
||||
class FeatureValueHashEntry : public PLDHashEntryHdr {
|
||||
public:
|
||||
typedef const FeatureValueHashKey &KeyType;
|
||||
typedef const FeatureValueHashKey *KeyTypePointer;
|
||||
|
||||
FeatureValueHashEntry(KeyTypePointer aKey) { }
|
||||
FeatureValueHashEntry(const FeatureValueHashEntry& toCopy)
|
||||
{
|
||||
NS_ERROR("Should not be called");
|
||||
}
|
||||
~FeatureValueHashEntry() { }
|
||||
|
||||
bool KeyEquals(const KeyTypePointer aKey) const;
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
||||
static PLDHashNumber HashKey(const KeyTypePointer aKey);
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
FeatureValueHashKey mKey;
|
||||
nsTArray<uint32_t> mValues;
|
||||
};
|
||||
|
||||
nsTHashtable<FeatureValueHashEntry> mFontFeatureValues;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -192,9 +192,11 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext,
|
|||
|
||||
nsDataHashtable<nsUint32HashKey,uint32_t> mergedFeatures;
|
||||
|
||||
// if style contains font-specific features
|
||||
if (MergeFontFeatures(style,
|
||||
mFont->GetFontEntry()->mFeatureSettings,
|
||||
aShapedText->DisableLigatures(),
|
||||
mFont->GetFontEntry()->FamilyName(),
|
||||
mergedFeatures))
|
||||
{
|
||||
// enumerate result and insert into Graphite feature list
|
||||
|
|
|
@ -981,6 +981,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
|||
if (MergeFontFeatures(style,
|
||||
mFont->GetFontEntry()->mFeatureSettings,
|
||||
aShapedText->DisableLigatures(),
|
||||
mFont->GetFontEntry()->FamilyName(),
|
||||
mergedFeatures))
|
||||
{
|
||||
// enumerate result and insert into hb_feature array
|
||||
|
|
Загрузка…
Ссылка в новой задаче