From 4b93f4c2f20545469536530c3abab8d538ef8c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 23 Apr 2014 06:57:42 -0700 Subject: [PATCH] Bug 407059 - Part 2: Make nsMathMLChar use the MATH table. r=karlt --- layout/mathml/nsMathMLChar.cpp | 525 +++++++++++++++++++++++++++------ layout/mathml/nsMathMLChar.h | 2 + 2 files changed, 429 insertions(+), 98 deletions(-) diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 606b649851e..7ea753a9527 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -28,10 +28,15 @@ #include "nsMathMLOperators.h" #include +#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); + 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 + { + return ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, + aChar, aVertical, 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()); + 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()); } - gfxTextRun* MakeTextRun(gfxContext* aThebesContext, - int32_t aAppUnitsPerDevPixel, - gfxFontGroup* aFontGroup, - const nsGlyphCode& aGlyph); + 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 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, - int32_t aAppUnitsPerDevPixel, - gfxFontGroup* aFontGroup, - const nsGlyphCode& aGlyph) +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 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 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(¶ms, 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 mTableList; + nsTArray 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* aFontGroup, + const nsAString& aFamily); + bool TryParts(nsGlyphTable* aGlyphTable, + nsRefPtr* aFontGroup, + const nsAString& aFamily); nsMathMLChar* mChar; nsPresContext* mPresContext; @@ -957,14 +1220,18 @@ 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, - const nsAString& aFamily) +nsMathMLChar:: +StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, + nsRefPtr* aFontGroup, + const nsAString& aFamily) { // Use our stretchy style context now that stretching is in progress nsStyleContext *sc = mChar->mStyleContext; 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 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 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 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; } @@ -1052,14 +1368,10 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, // Returns true if the size is OK, false to keep searching. // Always updates the char if a better match is found. bool -nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, +nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, + nsRefPtr* 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 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(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 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); + } + } - // Only try this table once. - context->mTablesTried.AppendElement(glyphTable); + 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)) { diff --git a/layout/mathml/nsMathMLChar.h b/layout/mathml/nsMathMLChar.h index d1944b2d671..1358a326150 100644 --- a/layout/mathml/nsMathMLChar.h +++ b/layout/mathml/nsMathMLChar.h @@ -199,6 +199,8 @@ public: protected: friend class nsGlyphTable; + friend class nsPropertiesTable; + friend class nsOpenTypeTable; nsString mData; private: