# HG changeset patch # Parent 9e16d5789ab6aa77d31dfe683716dc9c0e344615 # User Frédéric Wang Bug 407059 - read OpenType MATH table for variants and parts of stretchy characters diff --git a/gfx/thebes/MathTableStructures.h b/gfx/thebes/MathTableStructures.h new file mode 100644 --- /dev/null +++ b/gfx/thebes/MathTableStructures.h @@ -0,0 +1,75 @@ +/* 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/. */ + +typedef mozilla::AutoSwap_PRUint16 Offset; +typedef mozilla::AutoSwap_PRUint16 GlyphID; + +struct MathValueRecord { + mozilla::AutoSwap_PRUint16 mValue; + Offset mDeviceTable; +}; + +struct RangeRecord { + GlyphID mStart; + GlyphID mEnd; + mozilla::AutoSwap_PRUint16 mStartCoverageIndex; +}; + +struct Coverage { + mozilla::AutoSwap_PRUint16 mFormat; +}; + +struct CoverageFormat1 { + mozilla::AutoSwap_PRUint16 mFormat; + mozilla::AutoSwap_PRUint16 mGlyphCount; + // GlyphID mGlyphArray[mGlyphCount] +}; + +struct CoverageFormat2 { + mozilla::AutoSwap_PRUint16 mFormat; + mozilla::AutoSwap_PRUint16 mRangeCount; + // RangeRecord mRangeArray[mRangeCount]; +}; + +struct Header { + mozilla::AutoSwap_PRUint32 mVersion; + Offset mMathConstants; + Offset mMathGlyphInfo; + Offset mMathVariants; +}; + +struct MathVariants { + mozilla::AutoSwap_PRUint16 mMinConnectorOverlap; + Offset mVertGlyphCoverage; + Offset mHorizGlyphCoverage; + mozilla::AutoSwap_PRUint16 mVertGlyphCount; + mozilla::AutoSwap_PRUint16 mHorizGlyphCount; + // Offset mVertGlyphConstruction[mVertGlyphCount]; + // Offset mHorizGlyphConstruction[mHorizGlyphCount]; +}; + +struct MathGlyphVariantRecord { + GlyphID mVariantGlyph; + mozilla::AutoSwap_PRUint16 mAdvanceMeasurement; +}; + +struct MathGlyphConstruction { + Offset mGlyphAssembly; + mozilla::AutoSwap_PRUint16 mVariantCount; + // MathGlyphVariantRecord mMathGlyphVariantRecord[mVariantCount] +}; + +struct GlyphPartRecord { + GlyphID mGlyph; + mozilla::AutoSwap_PRUint16 mStartConnectorLength; + mozilla::AutoSwap_PRUint16 mEndConnectorLength; + mozilla::AutoSwap_PRUint16 mFullAdvance; + mozilla::AutoSwap_PRUint16 mPartFlags; +}; + +struct GlyphAssembly { + MathValueRecord mItalicsCorrection; + mozilla::AutoSwap_PRUint16 mPartCount; + // GlyphPartRecord mPartRecords[mPartCount] +}; diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -33,16 +33,17 @@ #include "nsStyleConsts.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Likely.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" #include "gfxSVGGlyphs.h" +#include "gfxMathTable.h" #include "gfx2DGlue.h" #include "cairo.h" #include "gfxFontTest.h" #include "harfbuzz/hb.h" #include "harfbuzz/hb-ot.h" #include "graphite2/Font.h" @@ -95,16 +96,17 @@ gfxFontEntry::gfxFontEntry() : mIsBadUnderlineFont(false), mIsUserFont(false), mIsLocalUserFont(false), mStandardFace(false), mSymbolFont(false), mIgnoreGDEF(false), mIgnoreGSUB(false), mSVGInitialized(false), + mMathInitialized(false), mHasSpaceFeaturesInitialized(false), mHasSpaceFeatures(false), mHasSpaceFeaturesKerning(false), mHasSpaceFeaturesNonKerning(false), mHasSpaceFeaturesSubDefault(false), mCheckedForGraphiteTables(false), mHasCmapTable(false), mGrFaceInitialized(false), @@ -122,16 +124,17 @@ gfxFontEntry::gfxFontEntry(const nsAStri mName(aName), mItalic(false), mFixedPitch(false), mIsProxy(false), mIsValid(true), mIsBadUnderlineFont(false), mIsUserFont(false), mIsLocalUserFont(false), mStandardFace(aIsStandardFace), mSymbolFont(false), mIgnoreGDEF(false), mIgnoreGSUB(false), mSVGInitialized(false), + mMathInitialized(false), mHasSpaceFeaturesInitialized(false), mHasSpaceFeatures(false), mHasSpaceFeaturesKerning(false), mHasSpaceFeaturesNonKerning(false), mHasSpaceFeaturesSubDefault(false), mCheckedForGraphiteTables(false), mHasCmapTable(false), mGrFaceInitialized(false), @@ -354,20 +357,50 @@ gfxFontEntry::TryGetSVGData(gfxFont* aFo if (!mFontsUsingSVGGlyphs.Contains(aFont)) { mFontsUsingSVGGlyphs.AppendElement(aFont); } return !!mSVGGlyphs; } +gfxMathTable* +gfxFontEntry::TryGetMathTable(gfxFont* aFont) +{ + if (!mMathInitialized) { + mMathInitialized = true; + + // We don't use AutoTable here because we'll pass ownership of this + // blob to the gfxMathTable, once we've confirmed the table exists + hb_blob_t *mathTable = GetFontTable(TRUETYPE_TAG('M','A','T','H')); + if (!mathTable) { + return nullptr; + } + + // gfxMathTable will hb_blob_destroy() the table when it is finished + // with it. + mMathTable = new gfxMathTable(mathTable, this); + if (!mMathTable->Init()) { + mMathTable = nullptr; + return nullptr; + } + } + + if (!mFontsUsingMathTable.Contains(aFont)) { + mFontsUsingMathTable.AppendElement(aFont); + } + + return mMathTable; +} + void gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont) { mFontsUsingSVGGlyphs.RemoveElement(aFont); + mFontsUsingMathTable.RemoveElement(aFont); } void gfxFontEntry::NotifyGlyphsChanged() { for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) { gfxFont* font = mFontsUsingSVGGlyphs[i]; font->NotifyGlyphsChanged(); @@ -693,16 +726,25 @@ gfxFontEntry::DisconnectSVG() { if (mSVGInitialized && mSVGGlyphs) { mSVGGlyphs = nullptr; mSVGInitialized = false; } } void +gfxFontEntry::DisconnectMath() +{ + if (mMathInitialized && mMathTable) { + mMathTable = nullptr; + mMathInitialized = false; + } +} + +void gfxFontEntry::CheckForGraphiteTables() { AutoTable silfTable(this, TRUETYPE_TAG('S','i','l','f')); mHasGraphiteTables = silfTable && hb_blob_get_length(silfTable) > 0; } /* static */ size_t gfxFontEntry::FontTableHashEntry::SizeOfEntryExcludingThis diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -42,16 +42,17 @@ class gfxTextRun; class gfxFont; class gfxFontFamily; class gfxFontGroup; class gfxUserFontSet; class gfxUserFontData; class gfxShapedText; class gfxShapedWord; class gfxSVGGlyphs; +class gfxMathTable; class gfxTextContextPaint; class nsILanguageAtomService; #define FONT_MAX_SIZE 2000.0 #define NO_FONT_LANGUAGE_OVERRIDE 0 @@ -305,16 +306,18 @@ public: bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId, gfxRect *aResult); bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode, gfxTextContextPaint *aContextPaint); // Call this when glyph geometry or rendering has changed // (e.g. animated SVG glyphs) void NotifyGlyphsChanged(); + gfxMathTable* TryGetMathTable(gfxFont* aFont); + virtual bool MatchesGenericFamily(const nsACString& aGeneric) const { return true; } virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const { return true; } // Access to raw font table data (needed for Harfbuzz): @@ -402,16 +405,19 @@ public: // Get Graphite face corresponding to this font file. // Caller must call gfxFontEntry::ReleaseGrFace when finished with it. gr_face* GetGrFace(); virtual void ReleaseGrFace(gr_face* aFace); // Release any SVG-glyphs document this font may have loaded. void DisconnectSVG(); + // Release any Math table this font may have loaded. + void DisconnectMath(); + // Called to notify that aFont is being destroyed. Needed when we're tracking // the fonts belonging to this font entry. void NotifyFontDestroyed(gfxFont* aFont); // For memory reporting virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, @@ -427,16 +433,17 @@ public: bool mIsBadUnderlineFont : 1; bool mIsUserFont : 1; bool mIsLocalUserFont : 1; bool mStandardFace : 1; bool mSymbolFont : 1; bool mIgnoreGDEF : 1; bool mIgnoreGSUB : 1; bool mSVGInitialized : 1; + bool mMathInitialized : 1; bool mHasSpaceFeaturesInitialized : 1; bool mHasSpaceFeatures : 1; bool mHasSpaceFeaturesKerning : 1; bool mHasSpaceFeaturesNonKerning : 1; bool mHasSpaceFeaturesSubDefault : 1; bool mHasGraphiteTables : 1; bool mCheckedForGraphiteTables : 1; bool mHasCmapTable : 1; @@ -450,16 +457,18 @@ public: nsRefPtr mCharacterMap; uint32_t mUVSOffset; nsAutoArrayPtr mUVSData; nsAutoPtr mUserFontData; nsAutoPtr mSVGGlyphs; // list of gfxFonts that are using SVG glyphs nsTArray mFontsUsingSVGGlyphs; + nsAutoPtr mMathTable; + nsTArray mFontsUsingMathTable; nsTArray mFeatureSettings; uint32_t mLanguageOverride; protected: friend class gfxPlatformFontList; friend class gfxMacPlatformFontList; friend class gfxUserFcFontEntry; friend class gfxFontFamily; diff --git a/gfx/thebes/gfxMathTable.cpp b/gfx/thebes/gfxMathTable.cpp new file mode 100644 --- /dev/null +++ b/gfx/thebes/gfxMathTable.cpp @@ -0,0 +1,346 @@ +/* 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 "gfxMathTable.h" + +#include "gfxFont.h" +#include "harfbuzz/hb.h" + +#include "MathTableStructures.h" + +#define fExtender 0x1 + +using namespace mozilla; + +gfxMathTable::gfxMathTable(hb_blob_t* aMathTable, gfxFontEntry* aFontEntry) + : mMathTable(aMathTable) + , mFontEntry(aFontEntry) + , mMathData(nullptr) + , mMathDataLength(0) + , mGlyphConstruction(nullptr) + , mGlyphID(0) + , mVertical(false) +{ +} + +gfxMathTable::~gfxMathTable() +{ + hb_blob_destroy(mMathTable); +} + +bool +gfxMathTable::Init() +{ + mMathData = hb_blob_get_data(mMathTable, &mMathDataLength); + + // Verify the MATH table header. + if (!ValidStructure(mMathData, sizeof(Header)) || + !ValidOffset(mMathData, uint16_t(GetHeader()->mMathVariants))) { + return false; + } + + // Verify the MathVariants header. + const MathVariants* mathvariants = GetMathVariants(); + const char *start = reinterpret_cast(mathvariants); + if (!ValidStructure(start, sizeof(MathVariants)) || + !ValidStructure(start, + sizeof(MathVariants) + sizeof(Offset) * + (uint16_t(mathvariants->mVertGlyphCount) + + uint16_t(mathvariants->mHorizGlyphCount))) || + !ValidOffset(start, uint16_t(mathvariants->mVertGlyphCoverage)) || + !ValidOffset(start, uint16_t(mathvariants->mHorizGlyphCoverage))) { + return false; + } + + return true; +} + +bool +gfxMathTable::ValidStructure(const char* aStart, uint16_t aSize) +{ + return (mMathData <= aStart && + aStart + aSize <= mMathData + mMathDataLength); +} + +bool +gfxMathTable::ValidOffset(const char* aStart, uint16_t aOffset) +{ + return (mMathData <= aStart + aOffset && + aStart + aOffset < mMathData + mMathDataLength); +} + +const Header* +gfxMathTable::GetHeader() +{ + return reinterpret_cast(mMathData); +}; + +const MathVariants* +gfxMathTable::GetMathVariants() +{ + return + reinterpret_cast(mMathData + + uint16_t(GetHeader()->mMathVariants)); +} + +int32_t +gfxMathTable::FindIndex(const Coverage* aCoverage, uint32_t aGlyph) +{ + if (uint16_t(aCoverage->mFormat) == 1) { + const CoverageFormat1* table = + reinterpret_cast(aCoverage); + uint16_t count = table->mGlyphCount; + const char* start = reinterpret_cast(table + 1); + if (ValidStructure(start, count * sizeof(GlyphID))) { + const GlyphID* glyphArray = + reinterpret_cast(start); + for (uint16_t i = 0; i < count; i++) { + if (uint16_t(glyphArray[i]) == aGlyph) { + return i; + } + } + } + } else if (uint16_t(aCoverage->mFormat) == 2) { + const CoverageFormat2* table = + reinterpret_cast(aCoverage); + uint16_t count = table->mRangeCount; + const char* start = reinterpret_cast(table + 1); + if (ValidStructure(start, count * sizeof(RangeRecord))) { + const RangeRecord* rangeArray = + reinterpret_cast(start); + for (uint16_t i = 0; i < count; i++) { + uint16_t rStart = rangeArray[i].mStart; + uint16_t rEnd = rangeArray[i].mEnd; + if (rStart <= aGlyph && aGlyph <= rEnd) { + return uint16_t(rangeArray[i].mStartCoverageIndex) + aGlyph - rStart; + } + } + } + } + return -1; +} + +void +gfxMathTable::SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical) +{ + if (mGlyphID == aGlyphID && mVertical == aVertical) { + // The (glyph, direction) is already selected. + return; + } + + // Update our cached values. + mVertical = aVertical; + mGlyphID = aGlyphID; + mGlyphConstruction = nullptr; + + // Get the coverage index for the new values. + const MathVariants* mathvariants = GetMathVariants(); + const char *start = reinterpret_cast(mathvariants); + uint16_t offset = (aVertical ? + mathvariants->mVertGlyphCoverage : + mathvariants->mHorizGlyphCoverage); + const Coverage* coverage = + reinterpret_cast(start + offset); + int32_t i = FindIndex(coverage, aGlyphID ); + + // Get the offset to the glyph construction. + uint16_t count = (aVertical ? + mathvariants->mVertGlyphCount : + mathvariants->mHorizGlyphCount); + start = reinterpret_cast(mathvariants + 1); + if (i < 0 || i >= count) { + return; + } + if (!aVertical) { + start += uint16_t(mathvariants->mVertGlyphCount) * sizeof(Offset); + } + if (!ValidStructure(start, count * sizeof(Offset))) { + return; + } + const Offset* offsetArray = reinterpret_cast(start); + offset = uint16_t(offsetArray[i]); + + // Make mGlyphConstruction point to the desired glyph construction. + start = reinterpret_cast(mathvariants); + if (!ValidOffset(start, offset)) { + return; + } + mGlyphConstruction = + reinterpret_cast(start + offset); +} + +bool +gfxMathTable::HasMathVariants() +{ + return !!mGlyphConstruction; +} + +uint16_t +gfxMathTable::MathVariantsSizesCount() +{ + if (!mGlyphConstruction) { + return 0; + } + return uint16_t(mGlyphConstruction->mVariantCount); +} + +uint32_t +gfxMathTable::GetMathVariantsSizes(uint16_t aIndex) +{ + if (!mGlyphConstruction) { + return 0; + } + + uint16_t count = mGlyphConstruction->mVariantCount; + const char *start = reinterpret_cast(mGlyphConstruction + 1); + if (aIndex >= count || + !ValidStructure(start, count * sizeof(MathGlyphVariantRecord))) { + return 0; + } + + const MathGlyphVariantRecord* recordArray = + reinterpret_cast(start); + + return uint32_t(recordArray[aIndex].mVariantGlyph); +} + +const GlyphAssembly* +gfxMathTable::GetGlyphAssembly() +{ + if (!mGlyphConstruction) { + return nullptr; + } + + const char* start = reinterpret_cast(mGlyphConstruction); + uint16_t offset = mGlyphConstruction->mGlyphAssembly; + if (offset == 0 || !ValidOffset(start, offset)) { + return nullptr; + } + start += offset; + + if (!ValidStructure(start, sizeof(GlyphAssembly))) { + return nullptr; + } + + return reinterpret_cast(start); +} + +uint16_t +gfxMathTable::MathVariantsPartsCount() +{ + const GlyphAssembly* glyphAssembly = GetGlyphAssembly(); + if (!glyphAssembly) { + return 0; + } + return uint16_t(glyphAssembly->mPartCount); +} + +bool +gfxMathTable::GetMathVariantsParts(uint32_t* aGlyphs) +{ + const GlyphAssembly* glyphAssembly = GetGlyphAssembly(); + if (!glyphAssembly) { + return false; + } + + uint16_t count = glyphAssembly->mPartCount; + const char* start = reinterpret_cast(glyphAssembly + 1); + if (!ValidStructure(start, count * sizeof(GlyphPartRecord))) { + return false; + } + + const GlyphPartRecord* recordArray = + reinterpret_cast(start); + + // XXXfredw The structure of the Open Type Math table is a bit more general + // than the TeX format, so try to fallback in reasonable way. nsMathMLChar + // should be adapted to handle the most general format. + // We use the approach of the copyComponents function in + // github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py + + // Count the number of non extender pieces + uint16_t nonExtenderCount = 0; + for (uint16_t i = 0; i < count; i++) { + if (!(uint16_t(recordArray[i].mPartFlags) & fExtender)) { + nonExtenderCount++; + } + } + if (nonExtenderCount > 3) { + // Not supported: too many pieces + return false; + } + + // Now browse the list of pieces + + // 0 = look for a left/bot glyph + // 1 = look for an extender between left/bot and mid + // 2 = look for a mid glyph + // 3 = look for an extender between mid and right/top + // 4 = look for a right/top glyph + // 5 = no more piece expected + uint8_t state = 0; + + // First extender char found. + uint32_t extenderChar = 0; + + // Clear the aGlyphs table. + aGlyphs[0] = aGlyphs[1] = aGlyphs[2] = aGlyphs[3] = 0; + + for (uint16_t i = 0; i < count; i++) { + + bool isExtender = uint16_t(recordArray[i].mPartFlags) & fExtender; + uint32_t glyph = recordArray[i].mGlyph; + + if ((state == 1 || state == 2) && nonExtenderCount < 3) { + // do not try to find a middle glyph + state += 2; + } + + if (isExtender) { + if (!extenderChar) { + extenderChar = glyph; + aGlyphs[3] = extenderChar; + } else if (extenderChar != glyph) { + // Not supported: different extenders + return false; + } + + if (state == 0) { // or state == 1 + // ignore left/bot piece and multiple successive extenders + state = 1; + } else if (state == 2) { // or state == 3 + // ignore mid piece and multiple successive extenders + state = 3; + } else if (state >= 4) { + // Not supported: unexpected extender + return false; + } + + continue; + } + + if (state == 0) { + // copy left/bottom part + aGlyphs[mVertical ? 2 : 0] = glyph; + state = 1; + continue; + } + + if (state == 1 || state == 2) { + // copy middle part + aGlyphs[1] = glyph; + state = 3; + continue; + } + + if (state == 3 || state == 4) { + // copy right/top part + aGlyphs[mVertical ? 0 : 2] = glyph; + state = 5; + } + + } + + return true; +} diff --git a/gfx/thebes/gfxMathTable.h b/gfx/thebes/gfxMathTable.h new file mode 100644 --- /dev/null +++ b/gfx/thebes/gfxMathTable.h @@ -0,0 +1,69 @@ +/* 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/. */ + +#ifndef GFX_MATH_TABLE_WRAPPER_H +#define GFX_MATH_TABLE_WRAPPER_H + +#include "gfxFontUtils.h" + +struct Coverage; +struct Header; +struct MathGlyphConstruction; +struct MathVariants; +struct GlyphAssembly; + +/** + * Used by |gfxFontEntry| to represent the MATH table of an OpenType font. + * Each |gfxFontEntry| owns at most one |gfxMathTable| instance. + */ +class gfxMathTable +{ +public: + /** + * @param aMathTable The MATH table from the OpenType font + * + * The gfxMathTable object takes over ownership of the blob references + * that are passed in, and will hb_blob_destroy() them when finished; + * the caller should -not- destroy these references. + */ + gfxMathTable(hb_blob_t* aMathTable, gfxFontEntry* aFontEntry); + + /** + * Releases our references to the Math table and cleans up everything else. + */ + ~gfxMathTable(); + + void SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical); + bool HasMathVariants(); + uint16_t MathVariantsSizesCount(); + uint32_t GetMathVariantsSizes(uint16_t aIndex); + uint16_t MathVariantsPartsCount(); + bool GetMathVariantsParts(uint32_t* aGlyphs); + +protected: + friend class gfxFontEntry; + bool Init(); + +private: + hb_blob_t* mMathTable; + gfxFontEntry* mFontEntry; + + const char* mMathData; + unsigned int mMathDataLength; + + const MathGlyphConstruction* mGlyphConstruction; + uint32_t mGlyphID; + bool mVertical; + + bool ValidStructure(const char* aStructStart, uint16_t aStructSize); + bool ValidOffset(const char* aOffsetStart, uint16_t aOffset); + + int32_t FindIndex(const Coverage* aCoverage, uint32_t aGlyph); + + const Header* GetHeader(); + const MathVariants* GetMathVariants(); + const GlyphAssembly* GetGlyphAssembly(); +}; + +#endif diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -20,16 +20,17 @@ EXPORTS += [ 'gfxFont.h', 'gfxFontConstants.h', 'gfxFontFeatures.h', 'gfxFontTest.h', 'gfxFontUtils.h', 'gfxGradientCache.h', 'gfxImageSurface.h', 'gfxLineSegment.h', + 'gfxMathTable.h', 'gfxMatrix.h', 'gfxPath.h', 'gfxPattern.h', 'gfxPlatform.h', 'gfxPoint.h', 'gfxPoint3D.h', 'gfxPointH3D.h', 'gfxQuad.h', @@ -261,16 +262,17 @@ UNIFIED_SOURCES += [ 'gfxContext.cpp', 'gfxFontFeatures.cpp', 'gfxFontMissingGlyphs.cpp', 'gfxFontTest.cpp', 'gfxGradientCache.cpp', 'gfxGraphiteShaper.cpp', 'gfxHarfBuzzShaper.cpp', 'gfxImageSurface.cpp', + 'gfxMathTable.cpp', 'gfxMatrix.cpp', 'gfxPath.cpp', 'gfxPattern.cpp', 'gfxRect.cpp', 'gfxReusableImageSurfaceWrapper.cpp', 'gfxReusableSharedImageSurfaceWrapper.cpp', 'gfxScriptItemizer.cpp', 'gfxSkipChars.cpp', diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -23,16 +23,18 @@ #include "nsCSSRendering.h" #include "prprf.h" // For PR_snprintf() #include "nsDisplayList.h" #include "nsMathMLOperators.h" #include +#include "gfxMathTable.h" + using namespace mozilla; //#define NOISY_SEARCH 1 // ----------------------------------------------------------------------------- static const nsGlyphCode kNullGlyph = {{0, 0}, 0}; typedef enum {eExtension_base, eExtension_variants, eExtension_parts} nsMathfontPrefExtension; @@ -64,19 +66,16 @@ typedef enum {eExtension_base, eExtensio // font using larger and/or partial glyphs. The entry of each stretchy character // in the mathfont property file gives, in that order, the 4 partial glyphs: // Top (or Left), Middle, Bottom (or Right), Glue; and the variants of bigger // sizes (if any). // A position that is not relevant to a particular character is indicated there // 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 // helper to trim off comments from data in a MathFont Property File static void Clean(nsString& aValue) { @@ -99,93 +98,113 @@ LoadProperties(const nsString& aName, return NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(aProperties), NS_ConvertUTF16toUTF8(uriStr)); } // ----------------------------------------------------------------------------- class nsGlyphTable { public: - explicit nsGlyphTable(const nsString& aPrimaryFontName) - : mFontName(1), // ensure space for primary font name. - mState(NS_TABLE_STATE_EMPTY), - mCharCache(0) - { + explicit nsGlyphTable() + : mCharCache(0), + mState(NS_TABLE_STATE_EMPTY) { MOZ_COUNT_CTOR(nsGlyphTable); - mFontName.AppendElement(aPrimaryFontName); } - - // not a virtual destructor: this class is not intended to be subclassed - ~nsGlyphTable() - { + virtual ~nsGlyphTable() { MOZ_COUNT_DTOR(nsGlyphTable); } - const nsAString& PrimaryFontName() const - { - return mFontName[0]; - } - - const nsAString& FontNameFor(const nsGlyphCode& aGlyphCode) const - { - NS_ASSERTION(!aGlyphCode.IsGlyphID(), - "nsGlyphTable can only access glyphs by Unicode code point"); - return mFontName[aGlyphCode.font]; - } - // True if this table contains some glyphs (variants and/or parts) // or contains child chars that can be used to render this char - bool Has(nsPresContext* aPresContext, nsMathMLChar* aChar); + virtual bool Has(gfxContext* aThebesContext, nsMathMLChar* aChar) = 0; // True if this table contains variants of larger sizes to render this char - bool HasVariantsOf(nsPresContext* aPresContext, nsMathMLChar* aChar); + virtual bool HasVariantsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) = 0; // True if this table contains parts to render this char - bool HasPartsOf(nsPresContext* aPresContext, nsMathMLChar* aChar); + virtual bool HasPartsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) = 0; + + // Getter for size variants + virtual nsGlyphCode BigOf(gfxContext* aThebesContext, + nsMathMLChar* aChar, + int32_t aSize) = 0; // Getters for the parts - nsGlyphCode TopOf(nsPresContext* aPresContext, nsMathMLChar* aChar) { - return ElementAt(aPresContext, aChar, 0); + nsGlyphCode TopOf(gfxContext* aThebesContext, nsMathMLChar* aChar) { + return ElementAt(aThebesContext, aChar, 0); } - nsGlyphCode MiddleOf(nsPresContext* aPresContext, nsMathMLChar* aChar) { - return ElementAt(aPresContext, aChar, 1); + nsGlyphCode MiddleOf(gfxContext* aThebesContext, nsMathMLChar* aChar) { + return ElementAt(aThebesContext, aChar, 1); } - nsGlyphCode BottomOf(nsPresContext* aPresContext, nsMathMLChar* aChar) { - return ElementAt(aPresContext, aChar, 2); + nsGlyphCode BottomOf(gfxContext* aThebesContext, nsMathMLChar* aChar) { + return ElementAt(aThebesContext, aChar, 2); } - nsGlyphCode GlueOf(nsPresContext* aPresContext, nsMathMLChar* aChar) { - return ElementAt(aPresContext, aChar, 3); + nsGlyphCode GlueOf(gfxContext* aThebesContext, nsMathMLChar* aChar) { + return ElementAt(aThebesContext, aChar, 3); } - nsGlyphCode BigOf(nsPresContext* aPresContext, nsMathMLChar* aChar, - int32_t aSize) { - return ElementAt(aPresContext, aChar, 4 + aSize); + nsGlyphCode LeftOf(gfxContext* aThebesContext, nsMathMLChar* aChar) { + return ElementAt(aThebesContext, aChar, 0); } - nsGlyphCode LeftOf(nsPresContext* aPresContext, nsMathMLChar* aChar) { - return ElementAt(aPresContext, aChar, 0); - } - nsGlyphCode RightOf(nsPresContext* aPresContext, nsMathMLChar* aChar) { - return ElementAt(aPresContext, aChar, 2); + nsGlyphCode RightOf(gfxContext* aThebesContext, nsMathMLChar* aChar) { + return ElementAt(aThebesContext, aChar, 2); } + virtual const nsAString& + FontNameFor(const nsGlyphCode& aGlyphCode) const = 0; + +protected: + PRUnichar mCharCache; + + // Tri-state variable for error/empty/ready + int32_t mState; + + virtual nsGlyphCode ElementAt(gfxContext* aThebesContext, + nsMathMLChar* aChar, + uint32_t aPosition) = 0; +}; + +class nsPropertiesTable MOZ_FINAL : public nsGlyphTable { +public: + explicit nsPropertiesTable(const nsString& aPrimaryFontName) + : nsGlyphTable() + , mFontName(1) { // ensure space for primary font name. + MOZ_COUNT_CTOR(nsPropertiesTable); + mFontName.AppendElement(aPrimaryFontName); + } + + ~nsPropertiesTable() { + MOZ_COUNT_DTOR(nsPropertiesTable); + } + + virtual bool Has(gfxContext* aThebesContext, + nsMathMLChar* aChar) MOZ_OVERRIDE; + virtual bool HasVariantsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) MOZ_OVERRIDE; + virtual bool HasPartsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) MOZ_OVERRIDE; + + const nsAString& PrimaryFontName() const { + return mFontName[0]; + } + + const nsAString& + FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE; + private: - nsGlyphCode ElementAt(nsPresContext* aPresContext, nsMathMLChar* aChar, - uint32_t aPosition); + // The set of glyph data in this table, as provided by the MathFont Property + // File + nsCOMPtr mGlyphProperties; // mFontName[0] is the primary font associated to this table. The others // are possible "external" fonts for glyphs not in the primary font // but which are needed to stretch certain characters in the table nsTArray mFontName; - // Tri-state variable for error/empty/ready - int32_t mState; - - // The set of glyph data in this table, as provided by the MathFont Property - // 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, // 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 // which 'code@0' can be specified @@ -195,22 +214,73 @@ private: // k-th glyph is characterized by : // 1) mGlyphCache[3*k],mGlyphCache[3*k+1] : its Unicode point // 2) mGlyphCache[3*k+2] : the numeric identifier of the font where it comes // from. // A font identifier of '0' means the default primary font associated to this // table. Other digits map to the "external" fonts that may have been // specified in the MathFont Property File. nsString mGlyphCache; - PRUnichar mCharCache; + + virtual nsGlyphCode BigOf(gfxContext* aThebesContext, nsMathMLChar* aChar, + int32_t aSize) MOZ_OVERRIDE; + + virtual nsGlyphCode ElementAt(gfxContext* aThebesContext, + nsMathMLChar* aChar, + uint32_t aPosition) MOZ_OVERRIDE; }; +/* virtual */ +bool +nsPropertiesTable::Has(gfxContext* aThebesContext, nsMathMLChar* aChar) +{ + return (HasVariantsOf(aThebesContext, aChar) || + HasPartsOf(aThebesContext, aChar)); +} + +/* virtual */ +bool +nsPropertiesTable::HasVariantsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) +{ + //XXXkt all variants must be in the same file as size 1 + return BigOf(aThebesContext, aChar, 1).Exists(); +} + +/* virtual */ +bool +nsPropertiesTable::HasPartsOf(gfxContext* aThebesContext, nsMathMLChar* aChar) +{ + return GlueOf(aThebesContext, aChar).Exists() || + TopOf(aThebesContext, aChar).Exists() || + BottomOf(aThebesContext, aChar).Exists() || + MiddleOf(aThebesContext, aChar).Exists(); +} + +/* virtual */ nsGlyphCode -nsGlyphTable::ElementAt(nsPresContext* aPresContext, nsMathMLChar* aChar, - uint32_t aPosition) +nsPropertiesTable::BigOf(gfxContext* aThebesContext, nsMathMLChar* aChar, + int32_t aSize) +{ + return ElementAt(aThebesContext, aChar, 4 + aSize); +} + +/* virtual */ +const nsAString& +nsPropertiesTable::FontNameFor(const nsGlyphCode& aGlyphCode) const +{ + NS_ASSERTION(!aGlyphCode.IsGlyphID(), + "nsPropertiesTable can only access glyphs by code point"); + return mFontName[aGlyphCode.font]; +} + +/* virtual */ +nsGlyphCode +nsPropertiesTable::ElementAt(gfxContext* aThebesContext, nsMathMLChar* aChar, + uint32_t aPosition) { if (mState == NS_TABLE_STATE_ERROR) return kNullGlyph; // Load glyph properties if this is the first time we have been here if (mState == NS_TABLE_STATE_EMPTY) { nsresult rv = LoadProperties(mFontName[0], mGlyphProperties); #ifdef DEBUG nsAutoCString uriStr; uriStr.AssignLiteral("resource://gre/res/fonts/mathfont"); @@ -305,52 +375,200 @@ nsGlyphTable::ElementAt(nsPresContext* a if (index+2 >= mGlyphCache.Length()) return kNullGlyph; nsGlyphCode ch; ch.code[0] = mGlyphCache.CharAt(index); ch.code[1] = mGlyphCache.CharAt(index + 1); ch.font = mGlyphCache.CharAt(index + 2); return ch.code[0] == PRUnichar(0xFFFD) ? kNullGlyph : ch; } +class nsOpenTypeTable MOZ_FINAL : public nsGlyphTable { +public: + explicit nsOpenTypeTable(gfxFont* aFont) + : nsGlyphTable(), + mFont(aFont) { + MOZ_COUNT_CTOR(nsOpenTypeTable); + } + + ~nsOpenTypeTable() { + MOZ_COUNT_DTOR(nsOpenTypeTable); + } + + bool LoadMathTable(gfxFont *aFont); + virtual bool Has(gfxContext* aThebesContext, + nsMathMLChar* aChar) MOZ_OVERRIDE; + virtual bool HasVariantsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) MOZ_OVERRIDE; + virtual bool HasPartsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) MOZ_OVERRIDE; + virtual nsGlyphCode BigOf(gfxContext* aThebesContext, + nsMathMLChar* aChar, + int32_t aSize) MOZ_OVERRIDE; + + const nsAString& + FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE; + + const gfxFontEntry* GetFontEntry() const { + return mFont->GetFontEntry(); + } + +private: + nsRefPtr mFont; + gfxMathTable* mMathTable; + uint32_t mGlyphID; + + bool SelectGlyphConstruction(gfxContext* aThebesContext, nsMathMLChar* aChar); + virtual nsGlyphCode ElementAt(gfxContext* aThebesContext, + nsMathMLChar* aChar, + uint32_t aPosition) MOZ_OVERRIDE; +}; + bool -nsGlyphTable::Has(nsPresContext* aPresContext, nsMathMLChar* aChar) +nsOpenTypeTable::SelectGlyphConstruction(gfxContext* aThebesContext, + nsMathMLChar* aChar) { - return HasVariantsOf(aPresContext, aChar) || HasPartsOf(aPresContext, aChar); + // Load the Math Table if this is the first time we have been here + if (mState == NS_TABLE_STATE_EMPTY) { + mMathTable = mFont->GetFontEntry()->TryGetMathTable(mFont); + NS_ASSERTION(mMathTable, "This font should have an Open Type MATH table!"); + mState = NS_TABLE_STATE_READY; + } + + PRUnichar uchar = aChar->mData[0]; + if (mCharCache != uchar) { + // XXXfred: use gfxFont::GetGlyph() to get rid of aThebesContext? + nsGlyphCode glyph = { {uchar, 0}, 0}; + nsAutoPtr textRun; + textRun = aChar->MakeTextRun(aThebesContext, glyph); + 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; + return false; + } + mCharCache = uchar; + } + + NS_ASSERTION(aChar->mDirection == NS_STRETCH_DIRECTION_VERTICAL || + aChar->mDirection == NS_STRETCH_DIRECTION_HORIZONTAL, + "Bad stretch direction"); + mMathTable->SelectGlyphConstruction(mGlyphID, + aChar->mDirection == + NS_STRETCH_DIRECTION_VERTICAL); + + return true; } +/* virtual */ bool -nsGlyphTable::HasVariantsOf(nsPresContext* aPresContext, nsMathMLChar* aChar) +nsOpenTypeTable::Has(gfxContext* aThebesContext, nsMathMLChar* aChar) { - //XXXkt all variants must be in the same file as size 1 - return BigOf(aPresContext, aChar, 1).Exists(); + if (!SelectGlyphConstruction(aThebesContext, aChar)) { + return false; + } + return mMathTable->HasMathVariants(); } +/* virtual */ bool -nsGlyphTable::HasPartsOf(nsPresContext* aPresContext, nsMathMLChar* aChar) +nsOpenTypeTable::HasVariantsOf(gfxContext* aThebesContext, + nsMathMLChar* aChar) { - return GlueOf(aPresContext, aChar).Exists() || - TopOf(aPresContext, aChar).Exists() || - BottomOf(aPresContext, aChar).Exists() || - MiddleOf(aPresContext, aChar).Exists(); + if (!SelectGlyphConstruction(aThebesContext, aChar)) { + return false; + } + return mMathTable->MathVariantsSizesCount() > 1; } +/* virtual */ +bool +nsOpenTypeTable::HasPartsOf(gfxContext* aThebesContext, nsMathMLChar* aChar) +{ + if (!SelectGlyphConstruction(aThebesContext, aChar)) { + return false; + } + + uint32_t parts[4]; + if (!mMathTable->GetMathVariantsParts(parts)) { + return false; + } + + return parts[0] != 0 || parts[1] != 0 || parts[2] != 0 || parts[3] != 0; +} + +/* virtual */ +nsGlyphCode +nsOpenTypeTable::BigOf(gfxContext* aThebesContext, nsMathMLChar* aChar, + int32_t aSize) +{ + if (!SelectGlyphConstruction(aThebesContext, aChar)) { + return kNullGlyph; + } + uint32_t glyphID = mMathTable->GetMathVariantsSizes(aSize); + if (!glyphID) { + return kNullGlyph; + } + nsGlyphCode glyph; + glyph.glyphID = glyphID; + glyph.font = -1; + return glyph; +} + +/* virtual */ +const nsAString& +nsOpenTypeTable::FontNameFor(const nsGlyphCode& aGlyphCode) const +{ + NS_ASSERTION(aGlyphCode.IsGlyphID(), + "nsPropertiesTable can only access glyphs by id"); + return mFont->GetFontEntry()->FamilyName(); +} + +/* virtual */ +nsGlyphCode +nsOpenTypeTable::ElementAt(gfxContext* aThebesContext, + nsMathMLChar* aChar, + uint32_t aPosition) +{ + if (!SelectGlyphConstruction(aThebesContext, aChar)) { + return kNullGlyph; + } + + uint32_t parts[4]; + if (!mMathTable->GetMathVariantsParts(parts)) { + return kNullGlyph; + } + + uint32_t glyphID = parts[aPosition]; + if (!glyphID) { + return kNullGlyph; + } + nsGlyphCode glyph; + glyph.glyphID = glyphID; + glyph.font = -1; + return glyph; +} + + // ----------------------------------------------------------------------------- // This is the list of all the applicable glyph tables. // We will maintain a single global instance that will only reveal those // glyph tables that are associated to fonts currently installed on the // user' system. The class is an XPCOM shutdown observer to allow us to // free its allocated data at shutdown class nsGlyphTableList : public nsIObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER - nsGlyphTable mUnicodeTable; + nsPropertiesTable mUnicodeTable; nsGlyphTableList() : mUnicodeTable(NS_LITERAL_STRING("Unicode")) { MOZ_COUNT_CTOR(nsGlyphTableList); } virtual ~nsGlyphTableList() @@ -362,33 +580,43 @@ public: nsresult Finalize(); // Add a glyph table in the list, return the new table that was added nsGlyphTable* AddGlyphTable(const nsString& aPrimaryFontName); // Find a glyph table in the list that has a glyph for the given char nsGlyphTable* - GetGlyphTableFor(nsPresContext* aPresContext, - nsMathMLChar* aChar); + GetGlyphTableFor(nsMathMLChar* aChar); // Find the glyph table in the list corresponding to the given font family. nsGlyphTable* GetGlyphTableFor(const nsAString& aFamily); + // Find the glyph table in the list corresponding to the given gfxFont. + nsGlyphTable* + GetGlyphTableFor(gfxFont* aFont); + 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(); + } + nsOpenTypeTable* OpenTypeTableAt(int32_t aIndex) { + return &mOpenTypeTableList.ElementAt(aIndex); + } + int32_t OpenTypeTableCount() { + return mOpenTypeTableList.Length(); } // List of glyph tables; - nsTArray mTableList; + nsTArray mPropertiesTableList; + nsTArray mOpenTypeTableList; }; NS_IMPL_ISUPPORTS1(nsGlyphTableList, nsIObserver) // ----------------------------------------------------------------------------- // Here is the global list of applicable glyph tables that we will be using static nsGlyphTableList* gGlyphTableList = nullptr; @@ -439,52 +667,73 @@ nsGlyphTable* nsGlyphTableList::AddGlyphTable(const nsString& aPrimaryFontName) { // See if there is already a special table for this family. nsGlyphTable* glyphTable = GetGlyphTableFor(aPrimaryFontName); if (glyphTable != &mUnicodeTable) return glyphTable; // allocate a table - glyphTable = mTableList.AppendElement(aPrimaryFontName); + glyphTable = mPropertiesTableList.AppendElement(aPrimaryFontName); return glyphTable; } nsGlyphTable* -nsGlyphTableList::GetGlyphTableFor(nsPresContext* aPresContext, - nsMathMLChar* aChar) +nsGlyphTableList::GetGlyphTableFor(nsMathMLChar* aChar) { - if (mUnicodeTable.Has(aPresContext, aChar)) + if (mUnicodeTable.Has(nullptr, aChar)) return &mUnicodeTable; int32_t i; - for (i = 0; i < Count(); i++) { - nsGlyphTable* glyphTable = TableAt(i); - if (glyphTable->Has(aPresContext, aChar)) { + for (i = 0; i < PropertiesTableCount(); i++) { + nsPropertiesTable* glyphTable = PropertiesTableAt(i); + if (glyphTable->Has(nullptr, aChar)) { return glyphTable; } } return nullptr; } 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())) { return glyphTable; } } // Fall back to default Unicode table return &mUnicodeTable; } +nsGlyphTable* +nsGlyphTableList::GetGlyphTableFor(gfxFont* aFont) +{ + gfxMathTable* mathTable = aFont->GetFontEntry()->TryGetMathTable(aFont); + if (!mathTable) { + return nullptr; + } + + nsOpenTypeTable* glyphTable; + for (int32_t i = 0; i < OpenTypeTableCount(); i++) { + glyphTable = OpenTypeTableAt(i); + if (aFont->GetFontEntry() == glyphTable->GetFontEntry()) { + return glyphTable; + } + } + + // allocate a table + glyphTable = mOpenTypeTableList.AppendElement(aFont); + return glyphTable; +} + + // ----------------------------------------------------------------------------- // Lookup the preferences: // "font.mathfont-family.\uNNNN.base" -- fonts for the base size // "font.mathfont-family.\uNNNN.variants" -- fonts for larger glyphs // "font.mathfont-family.\uNNNN.parts" -- fonts for partial glyphs // Given the char code and mode of stretch, retrieve the preferred extension // font families. @@ -648,17 +897,17 @@ nsMathMLChar::SetData(nsPresContext* aPr mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; mBoundingMetrics = nsBoundingMetrics(); mGlyphTable = nullptr; // check if stretching is applicable ... if (gGlyphTableList && (1 == mData.Length())) { mDirection = nsMathMLOperators::GetStretchyDirection(mData); // default tentative table (not the one that is necessarily going // to be used) - mGlyphTable = gGlyphTableList->GetGlyphTableFor(aPresContext, this); + mGlyphTable = gGlyphTableList->GetGlyphTableFor(this); } } // ----------------------------------------------------------------------------- /* The Stretch: @param aContainerSize - suggested size for the stretched char @param aDesiredStretchSize - OUT parameter. The desired size @@ -963,20 +1212,39 @@ public: NS_ERROR("This shouldn't be called because we never enable spacing"); } }; gfxTextRun* nsMathMLChar::MakeTextRun(gfxContext* aThebesContext, const nsGlyphCode& aGlyph) { - NS_ASSERTION(!aGlyph.IsGlyphID(), "not yet implemented"); - return mFontMetrics->GetThebesFontGroup()-> - MakeTextRun(aGlyph.code, aGlyph.Length(), aThebesContext, - mFontMetrics->AppUnitsPerDevPixel(), 0); + if (!aGlyph.IsGlyphID()) { + return mFontMetrics->GetThebesFontGroup()-> + MakeTextRun(aGlyph.code, aGlyph.Length(), aThebesContext, + mFontMetrics->AppUnitsPerDevPixel(), 0); + } + + gfxTextRunFactory::Parameters params = { + aThebesContext, nullptr, nullptr, nullptr, 0, + mFontMetrics->AppUnitsPerDevPixel() + }; + gfxTextRun* textRun = gfxTextRun::Create(¶ms, 1, mFontMetrics-> + GetThebesFontGroup(), 0); + textRun->AddGlyphRun(mFontMetrics->GetThebesFontGroup()->GetFontAt(0), + gfxTextRange::kFontGroup, 0, false); + gfxTextRun::DetailedGlyph detailedGlyph; + detailedGlyph.mGlyphID = aGlyph.glyphID; + detailedGlyph.mAdvance = 0; + detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0; + gfxShapedText::CompressedGlyph g; + g.SetComplex(true, true, 1); + textRun->SetGlyphs(0, g, &detailedGlyph); + + return textRun; } nsBoundingMetrics nsMathMLChar::MeasureGlyph(gfxContext* aThebesContext, const nsGlyphCode& aGlyph) { nsAutoPtr textRun; textRun = MakeTextRun(aThebesContext, aGlyph); @@ -988,28 +1256,29 @@ nsMathMLChar::MeasureGlyph(gfxContext* aThebesContext, &provider); nsBoundingMetrics bm; bm.leftBearing = NSToCoordFloor(metrics.mBoundingBox.X()); bm.rightBearing = NSToCoordCeil(metrics.mBoundingBox.XMost()); bm.ascent = NSToCoordCeil(-metrics.mBoundingBox.Y()); bm.descent = NSToCoordCeil(metrics.mBoundingBox.YMost()); bm.width = NSToCoordRound(metrics.mAdvanceWidth); + if (aGlyph.IsGlyphID()) { + bm.width = bm.rightBearing - std::max(0, bm.leftBearing); + } return bm; } void nsMathMLChar::DrawGlyph(gfxContext* aThebesContext, const nsGlyphCode& aGlyph, nscoord dx, nscoord dy) { - NS_ASSERTION(!aGlyph.IsGlyphID(), "not yet implemented"); - nsAutoPtr textRun; textRun = MakeTextRun(aThebesContext, aGlyph); StubPropertyProvider provider; gfxPoint pt(dx, dy); textRun->Draw(aThebesContext, pt, DrawMode::GLYPH_FILL, 0, aGlyph.Length(), &provider, nullptr, nullptr); } @@ -1092,17 +1361,17 @@ nsMathMLChar::StretchEnumContext::TryVar // start at size = 1 (size = 0 is the char at its normal size) int32_t size = 1; #ifdef NOISY_SEARCH printf(" searching in %s ...\n", NS_LossyConvertUTF16toASCII(aFamily).get()); #endif nsGlyphCode ch; - while ((ch = aGlyphTable->BigOf(mPresContext, mChar, size)).Exists()) { + while ((ch = aGlyphTable->BigOf(mThebesContext, mChar, size)).Exists()) { if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font)) { // if largeopOnly is set, break now if (largeopOnly) break; ++size; continue; } @@ -1165,17 +1434,17 @@ nsMathMLChar::StretchEnumContext::TryVar // 3. Build by parts. // 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, const nsAString& aFamily) { - if (!aGlyphTable->HasPartsOf(mPresContext, mChar)) + if (!aGlyphTable->HasPartsOf(mThebesContext, mChar)) 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; // Ensure SetFontFamily will set the font font.name.Truncate(); @@ -1186,20 +1455,20 @@ nsMathMLChar::StretchEnumContext::TryPar nscoord sizedata[4]; bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL); bool maxWidth = (NS_STRETCH_MAXWIDTH & mStretchHint) != 0; for (int32_t i = 0; i < 4; i++) { nsGlyphCode ch; switch (i) { - case 0: ch = aGlyphTable->TopOf(mPresContext, mChar); break; - case 1: ch = aGlyphTable->MiddleOf(mPresContext, mChar); break; - case 2: ch = aGlyphTable->BottomOf(mPresContext, mChar); break; - case 3: ch = aGlyphTable->GlueOf(mPresContext, mChar); break; + case 0: ch = aGlyphTable->TopOf(mThebesContext, mChar); break; + case 1: ch = aGlyphTable->MiddleOf(mThebesContext, mChar); break; + case 2: ch = aGlyphTable->BottomOf(mThebesContext, mChar); break; + case 3: ch = aGlyphTable->GlueOf(mThebesContext, mChar); break; } chdata[i] = ch; if (ch.Exists()) { if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font)) return false; nsBoundingMetrics bm = mChar->MeasureGlyph(mThebesContext, chdata[i]); @@ -1317,33 +1586,41 @@ nsMathMLChar::StretchEnumContext::TryPar // This is called for each family, whether it exists or not bool nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily, bool aGeneric, void *aData) { 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; nsFont font = sc->StyleFont()->mFont; if (!aGeneric && !context->mChar->SetFontFamily(context->mPresContext, nullptr, kNullGlyph, aFamily, font)) - return true; // Could not set the family + return true; // Could not set the family + + // See if there is a special table for the family, but always use the + // Unicode table for generic fonts. + nsGlyphTable* glyphTable; + if (aGeneric) { + glyphTable = &gGlyphTableList->mUnicodeTable; + } else { + glyphTable = gGlyphTableList-> + GetGlyphTableFor(context->mChar->mFontMetrics-> + GetThebesFontGroup()->GetFontAt(0)); + if (!glyphTable) { + glyphTable = gGlyphTableList->GetGlyphTableFor(aFamily); + } + } + + if (context->mTablesTried.Contains(glyphTable)) + return true; // already tried this one context->mGlyphTable = glyphTable; // Now see if the table has a glyph that matches the container // Only try this table once. context->mTablesTried.AppendElement(glyphTable); @@ -2090,27 +2367,27 @@ nsMathMLChar::PaintVertically(nsPresCont // Get the device pixel size in the vertical direction. // (This makes no effort to optimize for non-translation transformations.) nscoord oneDevPixel = aPresContext->AppUnitsPerDevPixel(); // get metrics data to be re-used later int32_t i = 0; nsGlyphCode ch, chdata[4]; int32_t glue, bottom; - nsGlyphCode chGlue = aGlyphTable->GlueOf(aPresContext, this); + nsGlyphCode chGlue = aGlyphTable->GlueOf(aThebesContext, this); for (i = 0; i < 4; ++i) { switch (i) { case 0: - ch = aGlyphTable->TopOf(aPresContext, this); + ch = aGlyphTable->TopOf(aThebesContext, this); break; case 1: - ch = aGlyphTable->MiddleOf(aPresContext, this); + ch = aGlyphTable->MiddleOf(aThebesContext, this); break; case 2: - ch = aGlyphTable->BottomOf(aPresContext, this); + ch = aGlyphTable->BottomOf(aThebesContext, this); bottom = i; break; case 3: ch = chGlue; glue = i; break; } // empty slots are filled with the glue if it is not null @@ -2284,27 +2561,27 @@ nsMathMLChar::PaintHorizontally(nsPresCo // Get the device pixel size in the horizontal direction. // (This makes no effort to optimize for non-translation transformations.) nscoord oneDevPixel = aPresContext->AppUnitsPerDevPixel(); // get metrics data to be re-used later int32_t i = 0; nsGlyphCode ch, chdata[4]; int32_t glue, right; - nsGlyphCode chGlue = aGlyphTable->GlueOf(aPresContext, this); + nsGlyphCode chGlue = aGlyphTable->GlueOf(aThebesContext, this); for (int32_t i = 0; i < 4; ++i) { switch (i) { case 0: - ch = aGlyphTable->LeftOf(aPresContext, this); + ch = aGlyphTable->LeftOf(aThebesContext, this); break; case 1: - ch = aGlyphTable->MiddleOf(aPresContext, this); + ch = aGlyphTable->MiddleOf(aThebesContext, this); break; case 2: - ch = aGlyphTable->RightOf(aPresContext, this); + ch = aGlyphTable->RightOf(aThebesContext, this); right = i; break; case 3: ch = chGlue; glue = i; break; } // empty slots are filled with the glue if it is not null diff --git a/layout/mathml/nsMathMLChar.h b/layout/mathml/nsMathMLChar.h --- a/layout/mathml/nsMathMLChar.h +++ b/layout/mathml/nsMathMLChar.h @@ -191,17 +191,18 @@ public: // They provide an interface to make them accessible to the Style System via // the Get/Set AdditionalStyleContext() APIs. Owners of MathMLChars // should honor these APIs. nsStyleContext* GetStyleContext() const; void SetStyleContext(nsStyleContext* aStyleContext); protected: - friend class nsGlyphTable; + friend class nsPropertiesTable; + friend class nsOpenTypeTable; nsString mData; private: nsRect mRect; nsStretchDirection mDirection; nsBoundingMetrics mBoundingMetrics; nsStyleContext* mStyleContext;