Bug 407059 - Part 2: Make nsMathMLChar use the MATH table. r=karlt

This commit is contained in:
Frédéric Wang 2014-04-23 06:57:42 -07:00
parent d33eebd920
commit 4b93f4c2f2
2 changed files with 429 additions and 98 deletions

View File

@ -28,10 +28,15 @@
#include "nsMathMLOperators.h"
#include <algorithm>
#include "gfxMathTable.h"
using namespace mozilla;
//#define NOISY_SEARCH 1
static const float kLargeOpFactor = float(M_SQRT2);
static const float kIntegralFactor = 2.0;
// -----------------------------------------------------------------------------
static const nsGlyphCode kNullGlyph = {{{0, 0}}, 0};
typedef enum {eExtension_base, eExtension_variants, eExtension_parts}
@ -41,16 +46,59 @@ typedef enum {eExtension_base, eExtension_variants, eExtension_parts}
// nsGlyphTable is a class that provides an interface for accessing glyphs
// of stretchy chars. It acts like a table that stores the variants of bigger
// sizes (if any) and the partial glyphs needed to build extensible symbols.
// An instance of nsGlyphTable is associated to one primary font. Extra glyphs
// can be taken in other additional fonts when stretching certain characters.
// These supplementary fonts are referred to as "external" fonts to the table.
//
// Bigger sizes (if any) of the char can then be retrieved with
// BigOf(aSize). Partial glyphs can be retrieved with ElementAt()
// Bigger sizes (if any) of the char can then be retrieved with BigOf(...).
// Partial glyphs can be retrieved with ElementAt(...).
//
// A table consists of "nsGlyphCode"s which are viewed either as Unicode
// points or as direct glyph indices, depending on the type of the table.
// XXX The latter is not yet supported.
// points (for nsPropertiesTable) or as direct glyph indices (for
// nsOpenTypeTable)
// -----------------------------------------------------------------------------
class nsGlyphTable {
public:
virtual ~nsGlyphTable() {}
virtual const nsAString&
FontNameFor(const nsGlyphCode& aGlyphCode) const = 0;
// Getters for the parts
virtual nsGlyphCode ElementAt(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical,
uint32_t aPosition) = 0;
virtual nsGlyphCode BigOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical,
uint32_t aSize) = 0;
// True if this table contains parts to render this char
virtual bool HasPartsOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical) = 0;
virtual gfxTextRun* MakeTextRun(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
const nsGlyphCode& aGlyph) = 0;
protected:
nsGlyphTable() : mCharCache(0) {}
// For speedy re-use, we always cache the last data used in the table.
// mCharCache is the Unicode point of the last char that was queried in this
// table.
char16_t mCharCache;
};
// An instance of nsPropertiesTable is associated with one primary font. Extra
// glyphs can be taken in other additional fonts when stretching certain
// characters.
// These supplementary fonts are referred to as "external" fonts to the table.
// General format of MathFont Property Files from which glyph data are
// retrieved:
@ -67,9 +115,6 @@ typedef enum {eExtension_base, eExtension_variants, eExtension_parts}
// with the UNICODE REPLACEMENT CHARACTER 0xFFFD.
// -----------------------------------------------------------------------------
#define NS_TABLE_TYPE_UNICODE 0
#define NS_TABLE_TYPE_GLYPH_INDEX 1
#define NS_TABLE_STATE_ERROR -1
#define NS_TABLE_STATE_EMPTY 0
#define NS_TABLE_STATE_READY 1
@ -98,23 +143,19 @@ LoadProperties(const nsString& aName,
NS_ConvertUTF16toUTF8(uriStr));
}
// -----------------------------------------------------------------------------
class nsGlyphTable {
class nsPropertiesTable MOZ_FINAL : public nsGlyphTable {
public:
explicit nsGlyphTable(const nsString& aPrimaryFontName)
: mFontName(1), // ensure space for primary font name.
mState(NS_TABLE_STATE_EMPTY),
mCharCache(0)
explicit nsPropertiesTable(const nsString& aPrimaryFontName)
: mFontName(1) // ensure space for primary font name.
, mState(NS_TABLE_STATE_EMPTY)
{
MOZ_COUNT_CTOR(nsGlyphTable);
MOZ_COUNT_CTOR(nsPropertiesTable);
mFontName.AppendElement(aPrimaryFontName);
}
// not a virtual destructor: this class is not intended to be subclassed
~nsGlyphTable()
~nsPropertiesTable()
{
MOZ_COUNT_DTOR(nsGlyphTable);
MOZ_COUNT_DTOR(nsPropertiesTable);
}
const nsAString& PrimaryFontName() const
@ -122,29 +163,52 @@ public:
return mFontName[0];
}
const nsAString& FontNameFor(const nsGlyphCode& aGlyphCode) const
const nsAString&
FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE
{
NS_ASSERTION(!aGlyphCode.IsGlyphID(),
"nsGlyphTable can only access glyphs by Unicode code point");
"nsPropertiesTable can only access glyphs by code point");
return mFontName[aGlyphCode.font];
}
// Getters for the parts
nsGlyphCode ElementAt(char16_t aChar, uint32_t aPosition);
nsGlyphCode BigOf(char16_t aChar, int32_t aSize) {
return ElementAt(aChar, 4 + aSize);
}
// True if this table contains parts to render this char
bool HasPartsOf(char16_t aChar) {
return (ElementAt(aChar, 0).Exists() || ElementAt(aChar, 1).Exists() ||
ElementAt(aChar, 2).Exists() || ElementAt(aChar, 3).Exists());
}
gfxTextRun* MakeTextRun(gfxContext* aThebesContext,
virtual nsGlyphCode ElementAt(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
const nsGlyphCode& aGlyph);
char16_t aChar,
bool aVertical,
uint32_t aPosition) MOZ_OVERRIDE;
virtual nsGlyphCode BigOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical,
uint32_t aSize) MOZ_OVERRIDE
{
return ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup,
aChar, aVertical, 4 + aSize);
}
virtual bool HasPartsOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical) MOZ_OVERRIDE
{
return (ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup,
aChar, aVertical, 0).Exists() ||
ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup,
aChar, aVertical, 1).Exists() ||
ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup,
aChar, aVertical, 2).Exists() ||
ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup,
aChar, aVertical, 3).Exists());
}
virtual gfxTextRun* MakeTextRun(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
const nsGlyphCode& aGlyph) MOZ_OVERRIDE;
private:
// mFontName[0] is the primary font associated to this table. The others
@ -159,10 +223,9 @@ private:
// File
nsCOMPtr<nsIPersistentProperties> mGlyphProperties;
// For speedy re-use, we always cache the last data used in the table.
// mCharCache is the Unicode point of the last char that was queried in this
// table. mGlyphCache is a buffer containing the glyph data associated to
// that char. For a property line 'key = value' in the MathFont Property File,
// mGlyphCache is a buffer containing the glyph data associated with
// mCharCache.
// For a property line 'key = value' in the MathFont Property File,
// mCharCache will retain the 'key' -- which is a Unicode point, while
// mGlyphCache will retain the 'value', which is a consecutive list of
// nsGlyphCodes, i.e., the pairs of 'code@font' needed by the char -- in
@ -178,11 +241,16 @@ private:
// table. Other digits map to the "external" fonts that may have been
// specified in the MathFont Property File.
nsString mGlyphCache;
char16_t mCharCache;
};
/* virtual */
nsGlyphCode
nsGlyphTable::ElementAt(char16_t aChar, uint32_t aPosition)
nsPropertiesTable::ElementAt(gfxContext* /* aThebesContext */,
int32_t /* aAppUnitsPerDevPixel */,
gfxFontGroup* /* aFontGroup */,
char16_t aChar,
bool /* aVertical */,
uint32_t aPosition)
{
if (mState == NS_TABLE_STATE_ERROR) return kNullGlyph;
// Load glyph properties if this is the first time we have been here
@ -286,18 +354,205 @@ nsGlyphTable::ElementAt(char16_t aChar, uint32_t aPosition)
return ch.code[0] == char16_t(0xFFFD) ? kNullGlyph : ch;
}
/* virtual */
gfxTextRun*
nsGlyphTable::MakeTextRun(gfxContext* aThebesContext,
nsPropertiesTable::MakeTextRun(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
const nsGlyphCode& aGlyph)
{
NS_ASSERTION(!aGlyph.IsGlyphID(), "not yet implemented");
NS_ASSERTION(!aGlyph.IsGlyphID(),
"nsPropertiesTable can only access glyphs by code point");
return aFontGroup->
MakeTextRun(aGlyph.code, aGlyph.Length(), aThebesContext,
aAppUnitsPerDevPixel, 0);
}
// An instance of nsOpenTypeTable is associated with one gfxFontEntry that
// corresponds to an Open Type font with a MATH table. All the glyphs come from
// the same font and the calls to access size variants and parts are directly
// forwarded to the gfx code.
class nsOpenTypeTable MOZ_FINAL : public nsGlyphTable {
public:
~nsOpenTypeTable()
{
MOZ_COUNT_DTOR(nsOpenTypeTable);
}
virtual nsGlyphCode ElementAt(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical,
uint32_t aPosition) MOZ_OVERRIDE;
virtual nsGlyphCode BigOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical,
uint32_t aSize) MOZ_OVERRIDE;
virtual bool HasPartsOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical) MOZ_OVERRIDE;
const nsAString&
FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE {
NS_ASSERTION(aGlyphCode.IsGlyphID(),
"nsOpenTypeTable can only access glyphs by id");
return mFontEntry->FamilyName();
}
virtual gfxTextRun* MakeTextRun(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
const nsGlyphCode& aGlyph) MOZ_OVERRIDE;
// This returns a new OpenTypeTable instance to give access to OpenType MATH
// table or nullptr if the font does not have such table. Ownership is passed
// to the caller.
static nsOpenTypeTable* Create(gfxFont* aFont)
{
if (!aFont->GetFontEntry()->TryGetMathTable(aFont)) {
return nullptr;
}
return new nsOpenTypeTable(aFont->GetFontEntry());
}
private:
nsRefPtr<gfxFontEntry> mFontEntry;
uint32_t mGlyphID;
explicit nsOpenTypeTable(gfxFontEntry* aFontEntry)
: mFontEntry(aFontEntry) {
MOZ_COUNT_CTOR(nsOpenTypeTable);
}
void UpdateCache(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar);
};
void
nsOpenTypeTable::UpdateCache(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar)
{
if (mCharCache != aChar) {
nsAutoPtr<gfxTextRun> textRun;
textRun = aFontGroup->
MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0);
const gfxTextRun::CompressedGlyph& data = textRun->GetCharacterGlyphs()[0];
if (data.IsSimpleGlyph()) {
mGlyphID = data.GetSimpleGlyph();
} else if (data.GetGlyphCount() == 1) {
mGlyphID = textRun->GetDetailedGlyphs(0)->mGlyphID;
} else {
mGlyphID = 0;
}
mCharCache = aChar;
}
}
/* virtual */
nsGlyphCode
nsOpenTypeTable::ElementAt(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical,
uint32_t aPosition)
{
UpdateCache(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, aChar);
uint32_t parts[4];
if (!mFontEntry->GetMathVariantsParts(mGlyphID, aVertical, parts)) {
return kNullGlyph;
}
uint32_t glyphID = parts[aPosition];
if (!glyphID) {
return kNullGlyph;
}
nsGlyphCode glyph;
glyph.glyphID = glyphID;
glyph.font = -1;
return glyph;
}
/* virtual */
nsGlyphCode
nsOpenTypeTable::BigOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical,
uint32_t aSize)
{
UpdateCache(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, aChar);
uint32_t glyphID =
mFontEntry->GetMathVariantsSize(mGlyphID, aVertical, aSize);
if (!glyphID) {
return kNullGlyph;
}
nsGlyphCode glyph;
glyph.glyphID = glyphID;
glyph.font = -1;
return glyph;
}
/* virtual */
bool
nsOpenTypeTable::HasPartsOf(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
char16_t aChar,
bool aVertical)
{
UpdateCache(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, aChar);
uint32_t parts[4];
if (!mFontEntry->GetMathVariantsParts(mGlyphID, aVertical, parts)) {
return false;
}
return parts[0] || parts[1] || parts[2] || parts[3];
}
/* virtual */
gfxTextRun*
nsOpenTypeTable::MakeTextRun(gfxContext* aThebesContext,
int32_t aAppUnitsPerDevPixel,
gfxFontGroup* aFontGroup,
const nsGlyphCode& aGlyph)
{
NS_ASSERTION(aGlyph.IsGlyphID(),
"nsOpenTypeTable can only access glyphs by id");
gfxTextRunFactory::Parameters params = {
aThebesContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel
};
gfxTextRun* textRun = gfxTextRun::Create(&params, 1, aFontGroup, 0);
textRun->AddGlyphRun(aFontGroup->GetFontAt(0), gfxTextRange::kFontGroup, 0,
false);
gfxTextRun::DetailedGlyph detailedGlyph;
detailedGlyph.mGlyphID = aGlyph.glyphID;
// We set the advance width to zero and this will be fixed in MeasureTextRun.
// XXXfredw: We should use gfxHarfbuzzShaper::GetGlyphHAdvance()
detailedGlyph.mAdvance = 0;
detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
gfxShapedText::CompressedGlyph g;
g.SetComplex(true, true, 1);
textRun->SetGlyphs(0, g, &detailedGlyph);
return textRun;
}
// -----------------------------------------------------------------------------
// This is the list of all the applicable glyph tables.
// We will maintain a single global instance that will only reveal those
@ -311,7 +566,7 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
nsGlyphTable mUnicodeTable;
nsPropertiesTable mUnicodeTable;
nsGlyphTableList()
: mUnicodeTable(NS_LITERAL_STRING("Unicode"))
@ -336,15 +591,14 @@ public:
GetGlyphTableFor(const nsAString& aFamily);
private:
nsGlyphTable* TableAt(int32_t aIndex) {
return &mTableList.ElementAt(aIndex);
nsPropertiesTable* PropertiesTableAt(int32_t aIndex) {
return &mPropertiesTableList.ElementAt(aIndex);
}
int32_t Count() {
return mTableList.Length();
int32_t PropertiesTableCount() {
return mPropertiesTableList.Length();
}
// List of glyph tables;
nsTArray<nsGlyphTable> mTableList;
nsTArray<nsPropertiesTable> mPropertiesTableList;
};
NS_IMPL_ISUPPORTS1(nsGlyphTableList, nsIObserver)
@ -405,15 +659,15 @@ nsGlyphTableList::AddGlyphTable(const nsString& aPrimaryFontName)
return glyphTable;
// allocate a table
glyphTable = mTableList.AppendElement(aPrimaryFontName);
glyphTable = mPropertiesTableList.AppendElement(aPrimaryFontName);
return glyphTable;
}
nsGlyphTable*
nsGlyphTableList::GetGlyphTableFor(const nsAString& aFamily)
{
for (int32_t i = 0; i < Count(); i++) {
nsGlyphTable* glyphTable = TableAt(i);
for (int32_t i = 0; i < PropertiesTableCount(); i++) {
nsPropertiesTable* glyphTable = PropertiesTableAt(i);
const nsAString& fontName = glyphTable->PrimaryFontName();
// TODO: would be nice to consider StripWhitespace and other aliasing
if (fontName.Equals(aFamily, nsCaseInsensitiveStringComparator())) {
@ -899,6 +1153,11 @@ MeasureTextRun(gfxContext* aThebesContext, gfxTextRun* aTextRun)
bm.ascent = NSToCoordCeil(-metrics.mBoundingBox.Y());
bm.descent = NSToCoordCeil(metrics.mBoundingBox.YMost());
bm.width = NSToCoordRound(metrics.mAdvanceWidth);
if (bm.width == 0) {
// The advance width was not set in nsGlyphTable::MakeTextRun, so we use
// the right bearing instead.
bm.width = bm.rightBearing;
}
return bm;
}
@ -930,8 +1189,12 @@ public:
EnumCallback(const nsString& aFamily, bool aGeneric, void *aData);
private:
bool TryVariants(nsGlyphTable* aGlyphTable, const nsAString& aFamily);
bool TryParts(nsGlyphTable* aGlyphTable, const nsAString& aFamily);
bool TryVariants(nsGlyphTable* aGlyphTable,
nsRefPtr<gfxFontGroup>* aFontGroup,
const nsAString& aFamily);
bool TryParts(nsGlyphTable* aGlyphTable,
nsRefPtr<gfxFontGroup>* aFontGroup,
const nsAString& aFamily);
nsMathMLChar* mChar;
nsPresContext* mPresContext;
@ -957,7 +1220,9 @@ private:
// Returns true if the size is OK, false to keep searching.
// Always updates the char if a better match is found.
bool
nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
nsMathMLChar::
StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
nsRefPtr<gfxFontGroup>* aFontGroup,
const nsAString& aFamily)
{
// Use our stretchy style context now that stretching is in progress
@ -965,6 +1230,8 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
nsFont font = sc->StyleFont()->mFont;
bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL);
nscoord oneDevPixel = mPresContext->AppUnitsPerDevPixel();
char16_t uchar = mChar->mData[0];
bool largeop = (NS_STRETCH_LARGEOP & mStretchHint) != 0;
bool largeopOnly =
largeop && (NS_STRETCH_VARIABLE_MASK & mStretchHint) == 0;
@ -977,17 +1244,45 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
// start at size = 1 (size = 0 is the char at its normal size)
int32_t size = 1;
nsGlyphCode ch;
nscoord displayOperatorMinHeight = 0;
if (largeopOnly) {
NS_ASSERTION(isVertical, "Stretching should be in the vertical direction");
ch = aGlyphTable->BigOf(mThebesContext, oneDevPixel, *aFontGroup, uchar,
isVertical, 0);
if (ch.IsGlyphID()) {
gfxFont* mathFont = aFontGroup->get()->GetFontAt(0);
// For OpenType MATH fonts, we will rely on the DisplayOperatorMinHeight
// to select the right size variant. Note that the value is sometimes too
// small so we use kLargeOpFactor/kIntegralFactor as a minimum value.
displayOperatorMinHeight =
NSToCoordRound(mathFont->GetFontEntry()->
GetMathConstant(gfxFontEntry::DisplayOperatorMinHeight) *
mathFont->GetAdjustedSize() * oneDevPixel);
nsAutoPtr<gfxTextRun> textRun;
textRun = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel,
*aFontGroup, ch);
nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun);
float largeopFactor = kLargeOpFactor;
if (NS_STRETCH_INTEGRAL & mStretchHint) {
// integrals are drawn taller
largeopFactor = kIntegralFactor;
}
nscoord minHeight = largeopFactor * (bm.ascent + bm.descent);
if (displayOperatorMinHeight < minHeight) {
displayOperatorMinHeight = minHeight;
}
}
}
#ifdef NOISY_SEARCH
printf(" searching in %s ...\n",
NS_LossyConvertUTF16toASCII(aFamily).get());
#endif
nsGlyphCode ch;
nsRefPtr<gfxFontGroup> fontGroup;
while ((ch = aGlyphTable->BigOf(mChar->mData[0], size)).Exists()) {
while ((ch = aGlyphTable->BigOf(mThebesContext, oneDevPixel, *aFontGroup,
uchar, isVertical, size)).Exists()) {
if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font,
&fontGroup)) {
aFontGroup)) {
// if largeopOnly is set, break now
if (largeopOnly) break;
++size;
@ -995,10 +1290,29 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
}
nsAutoPtr<gfxTextRun> textRun;
textRun = aGlyphTable->MakeTextRun(mThebesContext,
mPresContext->AppUnitsPerDevPixel(),
fontGroup, ch);
textRun = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel,
*aFontGroup, ch);
nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun);
if (ch.IsGlyphID()) {
gfxFont* mathFont = aFontGroup->get()->GetFontAt(0);
if (mathFont->GetFontEntry()->TryGetMathTable(mathFont)) {
// MeasureTextRun has set the advance width to the right bearing. We now
// subtract the italic correction, so that nsMathMLmmultiscripts will
// place the scripts correctly.
// Note that STIX-Word does not provide italic corrections
// (http://sourceforge.net/p/stixfonts/tracking/50/)
gfxFloat italicCorrection;
if (mathFont->GetFontEntry()->
GetMathItalicsCorrection(ch.glyphID, &italicCorrection)) {
bm.width -=
NSToCoordRound(italicCorrection *
mathFont->GetAdjustedSize() * oneDevPixel);
if (bm.width < 0) {
bm.width = 0;
}
}
}
}
nscoord charSize =
isVertical ? bm.ascent + bm.descent
@ -1038,8 +1352,10 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
break; // Not making an futher progress, stop searching
}
// if largeopOnly is set, break now
if (largeopOnly) break;
// If this a largeop only operator, we stop if the glyph is large enough.
if (largeopOnly && (bm.ascent + bm.descent) >= displayOperatorMinHeight) {
break;
}
++size;
}
@ -1053,13 +1369,9 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
// Always updates the char if a better match is found.
bool
nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable,
nsRefPtr<gfxFontGroup>* aFontGroup,
const nsAString& aFamily)
{
if (!aGlyphTable->HasPartsOf(mChar->mData[0]))
return false; // to next table
// See if the parts of this table fit in the desired space //////////////////
// Use our stretchy style context now that stretching is in progress
nsFont font = mChar->mStyleContext->StyleFont()->mFont;
@ -1070,20 +1382,24 @@ nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable,
nscoord sizedata[4];
bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL);
nscoord oneDevPixel = mPresContext->AppUnitsPerDevPixel();
char16_t uchar = mChar->mData[0];
bool maxWidth = (NS_STRETCH_MAXWIDTH & mStretchHint) != 0;
nsRefPtr<gfxFontGroup> fontGroup;
if (!aGlyphTable->HasPartsOf(mThebesContext, oneDevPixel, *aFontGroup,
uchar, isVertical))
return false; // to next table
for (int32_t i = 0; i < 4; i++) {
nsGlyphCode ch = aGlyphTable->ElementAt(mChar->mData[0], i);
nsGlyphCode ch = aGlyphTable->ElementAt(mThebesContext, oneDevPixel,
*aFontGroup, uchar, isVertical, i);
chdata[i] = ch;
if (ch.Exists()) {
if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font,
&fontGroup))
aFontGroup))
return false;
textRun[i] = aGlyphTable->MakeTextRun(mThebesContext,
mPresContext->AppUnitsPerDevPixel(),
fontGroup, ch);
textRun[i] = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel,
*aFontGroup, ch);
nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun[i]);
// TODO: For the generic Unicode table, ideally we should check that the
@ -1203,15 +1519,6 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily,
{
StretchEnumContext* context = static_cast<StretchEnumContext*>(aData);
// See if there is a special table for the family, but always use the
// Unicode table for generic fonts.
nsGlyphTable* glyphTable = aGeneric ?
&gGlyphTableList->mUnicodeTable :
gGlyphTableList->GetGlyphTableFor(aFamily);
if (context->mTablesTried.Contains(glyphTable))
return true; // already tried this one
// Check font family if it is not a generic one
// We test with the kNullGlyph
nsStyleContext *sc = context->mChar->mStyleContext;
@ -1222,10 +1529,31 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily,
font, &fontGroup))
return true; // Could not set the family
// Now see if the table has a glyph that matches the container
// Determine the glyph table to use for this font.
nsAutoPtr<nsOpenTypeTable> openTypeTable;
nsGlyphTable* glyphTable;
if (aGeneric) {
// This is a generic font, use the Unicode table.
glyphTable = &gGlyphTableList->mUnicodeTable;
} else {
// If the font contains an Open Type MATH table, use it.
openTypeTable = nsOpenTypeTable::Create(fontGroup->GetFontAt(0));
if (openTypeTable) {
glyphTable = openTypeTable;
} else {
// Otherwise try to find a .properties file corresponding to that font
// family or fallback to the Unicode table.
glyphTable = gGlyphTableList->GetGlyphTableFor(aFamily);
}
}
if (!openTypeTable) {
if (context->mTablesTried.Contains(glyphTable))
return true; // already tried this one
// Only try this table once.
context->mTablesTried.AppendElement(glyphTable);
}
// If the unicode table is being used, then search all font families. If a
// special table is being used then the font in this family should have the
@ -1233,8 +1561,9 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily,
const nsAString& family = glyphTable == &gGlyphTableList->mUnicodeTable ?
context->mFamilies : aFamily;
if((context->mTryVariants && context->TryVariants(glyphTable, family)) ||
(context->mTryParts && context->TryParts(glyphTable, family)))
if((context->mTryVariants &&
context->TryVariants(glyphTable, &fontGroup, family)) ||
(context->mTryParts && context->TryParts(glyphTable, &fontGroup, family)))
return false; // no need to continue
return true; // true means continue
@ -1470,7 +1799,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
// apply a scale transform to the base char.
if (!glyphFound && largeop) {
float scale;
float largeopFactor = float(M_SQRT2);
float largeopFactor = kLargeOpFactor;
// increase the width if it is not largeopFactor times larger
// than the initial one.
@ -1491,7 +1820,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
// than the initial one.
if (NS_STRETCH_INTEGRAL & aStretchHint) {
// integrals are drawn taller
largeopFactor = 2.0;
largeopFactor = kIntegralFactor;
}
if ((aDesiredStretchSize.ascent + aDesiredStretchSize.descent) <
largeopFactor * (initialSize.ascent + initialSize.descent)) {

View File

@ -199,6 +199,8 @@ public:
protected:
friend class nsGlyphTable;
friend class nsPropertiesTable;
friend class nsOpenTypeTable;
nsString mData;
private: