Bug 549861. Implement gfx support for font-variant-alternates. r=jkew

This commit is contained in:
John Daggett 2013-05-13 18:45:37 +09:00
Родитель d664a50735
Коммит be11778d6b
9 изменённых файлов: 341 добавлений и 3 удалений

Просмотреть файл

@ -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