Bug 407059 - Part 1: Add a gfxMathTable class to read the MATH table. r=jfkthame

This commit is contained in:
Frédéric Wang 2014-04-23 06:57:42 -07:00
Родитель 94bbbf60fd
Коммит e9daefe35d
6 изменённых файлов: 855 добавлений и 0 удалений

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

@ -0,0 +1,121 @@
/* 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/. */
// This file contains the structures described in Microsoft's document
// "The MATH table and OpenType Features for Math Processing" (not yet public).
//
// Arrays of varying size are indicated in comments. Typically, gfxMathTable
// will read the header of the structure first, verify that there is enough
// space for the specified arrays and then use a pointer to browse these arrays.
#ifndef MATH_TABLE_STRUCTURE_H
#define MATH_TABLE_STRUCTURE_H
#include "gfxFontUtils.h"
typedef mozilla::AutoSwap_PRUint16 Count16;
typedef mozilla::AutoSwap_PRUint16 GlyphID;
typedef mozilla::AutoSwap_PRUint16 Offset;
struct MathValueRecord {
mozilla::AutoSwap_PRInt16 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;
Count16 mGlyphCount;
// GlyphID mGlyphArray[mGlyphCount]
};
struct CoverageFormat2 {
mozilla::AutoSwap_PRUint16 mFormat;
Count16 mRangeCount;
// RangeRecord mRangeArray[mRangeCount];
};
struct MATHTableHeader {
mozilla::AutoSwap_PRUint32 mVersion;
Offset mMathConstants;
Offset mMathGlyphInfo;
Offset mMathVariants;
};
struct MathConstants {
mozilla::AutoSwap_PRInt16 mInt16[gfxFontEntry::ScriptScriptPercentScaleDown -
gfxFontEntry::ScriptPercentScaleDown + 1];
mozilla::AutoSwap_PRUint16 mUint16[gfxFontEntry::DisplayOperatorMinHeight -
gfxFontEntry::
DelimitedSubFormulaMinHeight + 1];
MathValueRecord mMathValues[gfxFontEntry::RadicalKernAfterDegree -
gfxFontEntry::MathLeading + 1];
mozilla::AutoSwap_PRUint16 mRadicalDegreeBottomRaisePercent;
};
struct MathGlyphInfo {
Offset mMathItalicsCorrectionInfo;
Offset mMathTopAccentAttachment;
Offset mExtendedShapeCoverage;
Offset mMathKernInfo;
};
struct MathItalicsCorrectionInfo {
Offset mCoverage;
Count16 mItalicsCorrectionCount;
// MathValueRecord mItalicsCorrection[mItalicsCorrectionCount]
};
struct MathVariants {
mozilla::AutoSwap_PRUint16 mMinConnectorOverlap;
Offset mVertGlyphCoverage;
Offset mHorizGlyphCoverage;
Count16 mVertGlyphCount;
Count16 mHorizGlyphCount;
// Offset mVertGlyphConstruction[mVertGlyphCount];
// Offset mHorizGlyphConstruction[mHorizGlyphCount];
};
struct MathGlyphVariantRecord {
GlyphID mVariantGlyph;
mozilla::AutoSwap_PRUint16 mAdvanceMeasurement;
};
struct MathGlyphConstruction {
Offset mGlyphAssembly;
Count16 mVariantCount;
// MathGlyphVariantRecord mMathGlyphVariantRecord[mVariantCount]
};
struct GlyphPartRecord {
GlyphID mGlyph;
mozilla::AutoSwap_PRUint16 mStartConnectorLength;
mozilla::AutoSwap_PRUint16 mEndConnectorLength;
mozilla::AutoSwap_PRUint16 mFullAdvance;
mozilla::AutoSwap_PRUint16 mPartFlags;
};
// PartFlags enumeration currently uses only one bit:
// 0x0001 If set, the part can be skipped or repeated.
// 0xFFFE Reserved.
enum {
PART_FLAG_EXTENDER = 0x01
};
struct GlyphAssembly {
MathValueRecord mItalicsCorrection;
Count16 mPartCount;
// GlyphPartRecord mPartRecords[mPartCount]
};
#endif

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

@ -38,6 +38,7 @@
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "gfxSVGGlyphs.h"
#include "gfxMathTable.h"
#include "gfx2DGlue.h"
#if defined(XP_MACOSX)
@ -112,6 +113,7 @@ gfxFontEntry::gfxFontEntry() :
mIgnoreGDEF(false),
mIgnoreGSUB(false),
mSVGInitialized(false),
mMathInitialized(false),
mHasSpaceFeaturesInitialized(false),
mHasSpaceFeatures(false),
mHasSpaceFeaturesKerning(false),
@ -141,6 +143,7 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
mIgnoreGDEF(false),
mIgnoreGSUB(false),
mSVGInitialized(false),
mMathInitialized(false),
mHasSpaceFeaturesInitialized(false),
mHasSpaceFeatures(false),
mHasSpaceFeaturesKerning(false),
@ -389,6 +392,78 @@ gfxFontEntry::NotifyGlyphsChanged()
}
}
bool
gfxFontEntry::TryGetMathTable(gfxFont* aFont)
{
if (!mMathInitialized) {
mMathInitialized = true;
// If UnitsPerEm is not known/valid, we can't use MATH table
if (UnitsPerEm() == kInvalidUPEM) {
return false;
}
// 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 false;
}
// gfxMathTable will hb_blob_destroy() the table when it is finished
// with it.
mMathTable = new gfxMathTable(mathTable);
if (!mMathTable->HasValidHeaders()) {
mMathTable = nullptr;
return false;
}
}
return !!mMathTable;
}
gfxFloat
gfxFontEntry::GetMathConstant(gfxFontEntry::MathConstant aConstant)
{
NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
gfxFloat value = mMathTable->GetMathConstant(aConstant);
if (aConstant == gfxFontEntry::ScriptPercentScaleDown ||
aConstant == gfxFontEntry::ScriptScriptPercentScaleDown ||
aConstant == gfxFontEntry::RadicalDegreeBottomRaisePercent) {
return value / 100.0;
}
return value / mUnitsPerEm;
}
bool
gfxFontEntry::GetMathItalicsCorrection(uint32_t aGlyphID,
gfxFloat* aItalicCorrection)
{
NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
int16_t italicCorrection;
if (!mMathTable->GetMathItalicsCorrection(aGlyphID, &italicCorrection)) {
return false;
}
*aItalicCorrection = gfxFloat(italicCorrection) / mUnitsPerEm;
return true;
}
uint32_t
gfxFontEntry::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
uint16_t aSize)
{
NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
return mMathTable->GetMathVariantsSize(aGlyphID, aVertical, aSize);
}
bool
gfxFontEntry::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
uint32_t aGlyphs[4])
{
NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
return mMathTable->GetMathVariantsParts(aGlyphID, aVertical, aGlyphs);
}
/**
* FontTableBlobData
*

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

@ -48,6 +48,7 @@ class gfxUserFontData;
class gfxShapedText;
class gfxShapedWord;
class gfxSVGGlyphs;
class gfxMathTable;
class gfxTextContextPaint;
class FontInfoData;
@ -311,6 +312,79 @@ public:
// (e.g. animated SVG glyphs)
void NotifyGlyphsChanged();
enum MathConstant {
// The order of the constants must match the order of the fields
// defined in the MATH table.
ScriptPercentScaleDown,
ScriptScriptPercentScaleDown,
DelimitedSubFormulaMinHeight,
DisplayOperatorMinHeight,
MathLeading,
AxisHeight,
AccentBaseHeight,
FlattenedAccentBaseHeight,
SubscriptShiftDown,
SubscriptTopMax,
SubscriptBaselineDropMin,
SuperscriptShiftUp,
SuperscriptShiftUpCramped,
SuperscriptBottomMin,
SuperscriptBaselineDropMax,
SubSuperscriptGapMin,
SuperscriptBottomMaxWithSubscript,
SpaceAfterScript,
UpperLimitGapMin,
UpperLimitBaselineRiseMin,
LowerLimitGapMin,
LowerLimitBaselineDropMin,
StackTopShiftUp,
StackTopDisplayStyleShiftUp,
StackBottomShiftDown,
StackBottomDisplayStyleShiftDown,
StackGapMin,
StackDisplayStyleGapMin,
StretchStackTopShiftUp,
StretchStackBottomShiftDown,
StretchStackGapAboveMin,
StretchStackGapBelowMin,
FractionNumeratorShiftUp,
FractionNumeratorDisplayStyleShiftUp,
FractionDenominatorShiftDown,
FractionDenominatorDisplayStyleShiftDown,
FractionNumeratorGapMin,
FractionNumDisplayStyleGapMin,
FractionRuleThickness,
FractionDenominatorGapMin,
FractionDenomDisplayStyleGapMin,
SkewedFractionHorizontalGap,
SkewedFractionVerticalGap,
OverbarVerticalGap,
OverbarRuleThickness,
OverbarExtraAscender,
UnderbarVerticalGap,
UnderbarRuleThickness,
UnderbarExtraDescender,
RadicalVerticalGap,
RadicalDisplayStyleVerticalGap,
RadicalRuleThickness,
RadicalExtraAscender,
RadicalKernBeforeDegree,
RadicalKernAfterDegree,
RadicalDegreeBottomRaisePercent
};
// Call TryGetMathTable to try to load the Open Type MATH table. The other
// functions forward the call to the gfxMathTable class. The GetMath...()
// functions MUST NOT be called unless TryGetMathTable() has returned true.
bool TryGetMathTable(gfxFont* aFont);
gfxFloat GetMathConstant(MathConstant aConstant);
bool GetMathItalicsCorrection(uint32_t aGlyphID,
gfxFloat* aItalicCorrection);
uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
uint16_t aSize);
bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
uint32_t aGlyphs[4]);
virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
return true;
}
@ -433,6 +507,7 @@ public:
bool mIgnoreGDEF : 1;
bool mIgnoreGSUB : 1;
bool mSVGInitialized : 1;
bool mMathInitialized : 1;
bool mHasSpaceFeaturesInitialized : 1;
bool mHasSpaceFeatures : 1;
bool mHasSpaceFeaturesKerning : 1;
@ -458,6 +533,7 @@ public:
nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
// list of gfxFonts that are using SVG glyphs
nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
nsAutoPtr<gfxMathTable> mMathTable;
nsTArray<gfxFontFeature> mFeatureSettings;
uint32_t mLanguageOverride;

459
gfx/thebes/gfxMathTable.cpp Normal file
Просмотреть файл

@ -0,0 +1,459 @@
/* 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 "MathTableStructures.h"
#include "harfbuzz/hb.h"
#include <algorithm>
using namespace mozilla;
gfxMathTable::gfxMathTable(hb_blob_t* aMathTable)
: mMathTable(aMathTable)
, mGlyphConstruction(nullptr)
, mGlyphID(-1)
, mVertical(false)
{
}
gfxMathTable::~gfxMathTable()
{
hb_blob_destroy(mMathTable);
}
bool
gfxMathTable::HasValidHeaders()
{
const char* mathData = hb_blob_get_data(mMathTable, nullptr);
// Verify the MATH table header.
if (!ValidStructure(mathData, sizeof(MATHTableHeader))) {
return false;
}
const MATHTableHeader* header = GetMATHTableHeader();
if (uint32_t(header->mVersion) != 0x00010000 ||
!ValidOffset(mathData, uint16_t(header->mMathConstants)) ||
!ValidOffset(mathData, uint16_t(header->mMathGlyphInfo)) ||
!ValidOffset(mathData, uint16_t(header->mMathVariants))) {
return false;
}
// Verify the MathConstants header.
const MathConstants* mathconstants = GetMathConstants();
const char* start = reinterpret_cast<const char*>(mathconstants);
if (!ValidStructure(start, sizeof(MathConstants))) {
return false;
}
// Verify the MathGlyphInfo header.
const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo();
start = reinterpret_cast<const char*>(mathglyphinfo);
if (!ValidStructure(start, sizeof(MathGlyphInfo))) {
return false;
}
// Verify the MathVariants header.
const MathVariants* mathvariants = GetMathVariants();
start = reinterpret_cast<const char*>(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;
}
int32_t
gfxMathTable::GetMathConstant(gfxFontEntry::MathConstant aConstant)
{
const MathConstants* mathconstants = GetMathConstants();
if (aConstant <= gfxFontEntry::ScriptScriptPercentScaleDown) {
return int16_t(mathconstants->mInt16[aConstant]);
}
if (aConstant <= gfxFontEntry::DisplayOperatorMinHeight) {
return
uint16_t(mathconstants->
mUint16[aConstant - gfxFontEntry::DelimitedSubFormulaMinHeight]);
}
if (aConstant <= gfxFontEntry::RadicalKernAfterDegree) {
return int16_t(mathconstants->
mMathValues[aConstant - gfxFontEntry::MathLeading].mValue);
}
return uint16_t(mathconstants->mRadicalDegreeBottomRaisePercent);
}
bool
gfxMathTable::GetMathItalicsCorrection(uint32_t aGlyphID,
int16_t* aItalicCorrection)
{
const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo();
// Get the offset of the italic correction and verify whether it is valid.
const char* start = reinterpret_cast<const char*>(mathglyphinfo);
uint16_t offset = mathglyphinfo->mMathItalicsCorrectionInfo;
if (offset == 0 || !ValidOffset(start, offset)) {
return false;
}
start += offset;
// Verify the validity of the MathItalicsCorrectionInfo and retrieve it.
if (!ValidStructure(start, sizeof(MathItalicsCorrectionInfo))) {
return false;
}
const MathItalicsCorrectionInfo* italicsCorrectionInfo =
reinterpret_cast<const MathItalicsCorrectionInfo*>(start);
// Get the coverage index for the glyph.
offset = italicsCorrectionInfo->mCoverage;
const Coverage* coverage =
reinterpret_cast<const Coverage*>(start + offset);
int32_t i = GetCoverageIndex(coverage, aGlyphID);
// Get the ItalicsCorrection.
uint16_t count = italicsCorrectionInfo->mItalicsCorrectionCount;
if (i < 0 || i >= count) {
return false;
}
start = reinterpret_cast<const char*>(italicsCorrectionInfo + 1);
if (!ValidStructure(start, count * sizeof(MathValueRecord))) {
return false;
}
const MathValueRecord* mathValueRecordArray =
reinterpret_cast<const MathValueRecord*>(start);
*aItalicCorrection = int16_t(mathValueRecordArray[i].mValue);
return true;
}
uint32_t
gfxMathTable::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
uint16_t aSize)
{
// Select the glyph construction.
SelectGlyphConstruction(aGlyphID, aVertical);
if (!mGlyphConstruction) {
return 0;
}
// Verify the validity of the array of the MathGlyphVariantRecord's and
// whether there is a variant of the requested size.
uint16_t count = mGlyphConstruction->mVariantCount;
const char* start = reinterpret_cast<const char*>(mGlyphConstruction + 1);
if (aSize >= count ||
!ValidStructure(start, count * sizeof(MathGlyphVariantRecord))) {
return 0;
}
// Return the glyph index of the requested size variant.
const MathGlyphVariantRecord* recordArray =
reinterpret_cast<const MathGlyphVariantRecord*>(start);
return uint32_t(recordArray[aSize].mVariantGlyph);
}
bool
gfxMathTable::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
uint32_t aGlyphs[4])
{
// Get the glyph assembly corresponding to that (aGlyphID, aVertical) pair.
const GlyphAssembly* glyphAssembly = GetGlyphAssembly(aGlyphID, aVertical);
if (!glyphAssembly) {
return false;
}
// Verify the validity of the array of GlyphPartRecord's and retrieve it.
uint16_t count = glyphAssembly->mPartCount;
const char* start = reinterpret_cast<const char*>(glyphAssembly + 1);
if (!ValidStructure(start, count * sizeof(GlyphPartRecord))) {
return false;
}
const GlyphPartRecord* recordArray =
reinterpret_cast<const GlyphPartRecord*>(start);
// XXXfredw The structure of the Open Type Math table is a bit more general
// than the one currently used by the nsMathMLChar code, so we try to fallback
// in reasonable way. We use the approach of the copyComponents function in
// github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py
//
// The nsMathMLChar code can use at most 3 non extender pieces (aGlyphs[0],
// aGlyphs[1] and aGlyphs[2]) and the extenders between these pieces should
// all be the same (aGlyphs[4]). Also, the parts of vertical assembly are
// stored from bottom to top in the Open Type MATH table while they are
// stored from top to bottom in nsMathMLChar.
// 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) & PART_FLAG_EXTENDER)) {
nonExtenderCount++;
}
}
if (nonExtenderCount > 3) {
// Not supported: too many pieces
return false;
}
// Now browse the list of pieces
// 0 = look for a left/bottom glyph
// 1 = look for an extender between left/bottom and mid
// 2 = look for a middle glyph
// 3 = look for an extender between middle 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.
memset(aGlyphs, 0, sizeof(uint32_t) * 4);
for (uint16_t i = 0; i < count; i++) {
bool isExtender = uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER;
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/bottom piece and multiple successive extenders
state = 1;
} else if (state == 2) { // or state == 3
// ignore middle 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;
}
bool
gfxMathTable::ValidStructure(const char* aStart, uint16_t aSize)
{
unsigned int mathDataLength;
const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
return (mathData <= aStart &&
aStart + aSize <= mathData + mathDataLength);
}
bool
gfxMathTable::ValidOffset(const char* aStart, uint16_t aOffset)
{
unsigned int mathDataLength;
const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
return (mathData <= aStart + aOffset &&
aStart + aOffset < mathData + mathDataLength);
}
const MATHTableHeader*
gfxMathTable::GetMATHTableHeader()
{
const char* mathData = hb_blob_get_data(mMathTable, nullptr);
return reinterpret_cast<const MATHTableHeader*>(mathData);
}
const MathConstants*
gfxMathTable::GetMathConstants()
{
const char* mathData = hb_blob_get_data(mMathTable, nullptr);
return
reinterpret_cast<const MathConstants*>(mathData +
uint16_t(GetMATHTableHeader()->
mMathConstants));
}
const MathGlyphInfo*
gfxMathTable::GetMathGlyphInfo()
{
const char* mathData = hb_blob_get_data(mMathTable, nullptr);
return
reinterpret_cast<const MathGlyphInfo*>(mathData +
uint16_t(GetMATHTableHeader()->
mMathGlyphInfo));
}
const MathVariants*
gfxMathTable::GetMathVariants()
{
const char* mathData = hb_blob_get_data(mMathTable, nullptr);
return
reinterpret_cast<const MathVariants*>(mathData +
uint16_t(GetMATHTableHeader()->
mMathVariants));
}
const GlyphAssembly*
gfxMathTable::GetGlyphAssembly(uint32_t aGlyphID, bool aVertical)
{
// Select the glyph construction.
SelectGlyphConstruction(aGlyphID, aVertical);
if (!mGlyphConstruction) {
return nullptr;
}
// Get the offset of the glyph assembly and verify whether it is valid.
const char* start = reinterpret_cast<const char*>(mGlyphConstruction);
uint16_t offset = mGlyphConstruction->mGlyphAssembly;
if (offset == 0 || !ValidOffset(start, offset)) {
return nullptr;
}
start += offset;
// Verify the validity of the GlyphAssembly and return it.
if (!ValidStructure(start, sizeof(GlyphAssembly))) {
return nullptr;
}
return reinterpret_cast<const GlyphAssembly*>(start);
}
int32_t
gfxMathTable::GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph)
{
if (uint16_t(aCoverage->mFormat) == 1) {
// Coverage Format 1: list of individual glyph indices in the glyph set.
const CoverageFormat1* table =
reinterpret_cast<const CoverageFormat1*>(aCoverage);
uint16_t count = table->mGlyphCount;
const char* start = reinterpret_cast<const char*>(table + 1);
if (ValidStructure(start, count * sizeof(GlyphID))) {
const GlyphID* glyphArray =
reinterpret_cast<const GlyphID*>(start);
uint32_t imin = 0, imax = count;
while (imin < imax) {
uint32_t imid = (imin + imax) >> 1;
uint16_t glyphMid = glyphArray[imid];
if (glyphMid == aGlyph) {
return imid;
}
if (glyphMid < aGlyph) {
imin = imid + 1;
} else {
imax = imid;
}
}
}
} else if (uint16_t(aCoverage->mFormat) == 2) {
// Coverage Format 2: ranges of consecutive indices.
const CoverageFormat2* table =
reinterpret_cast<const CoverageFormat2*>(aCoverage);
uint16_t count = table->mRangeCount;
const char* start = reinterpret_cast<const char*>(table + 1);
if (ValidStructure(start, count * sizeof(RangeRecord))) {
const RangeRecord* rangeArray =
reinterpret_cast<const RangeRecord*>(start);
uint32_t imin = 0, imax = count;
while (imin < imax) {
uint32_t imid = (imin + imax) >> 1;
uint16_t rStart = rangeArray[imid].mStart;
uint16_t rEnd = rangeArray[imid].mEnd;
if (rEnd < aGlyph) {
imin = imid + 1;
} else if (aGlyph < rStart) {
imax = imid;
} else {
return (uint16_t(rangeArray[imid].mStartCoverageIndex) +
aGlyph - rStart);
}
}
}
}
return -1;
}
void
gfxMathTable::SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical)
{
if (mGlyphID == aGlyphID && mVertical == aVertical) {
// The (glyph, direction) pair is already selected: nothing to do.
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<const char*>(mathvariants);
uint16_t offset = (aVertical ?
mathvariants->mVertGlyphCoverage :
mathvariants->mHorizGlyphCoverage);
const Coverage* coverage =
reinterpret_cast<const Coverage*>(start + offset);
int32_t i = GetCoverageIndex(coverage, aGlyphID);
// Get the offset to the glyph construction.
uint16_t count = (aVertical ?
mathvariants->mVertGlyphCount :
mathvariants->mHorizGlyphCount);
start = reinterpret_cast<const char*>(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<const Offset*>(start);
offset = uint16_t(offsetArray[i]);
// Make mGlyphConstruction point to the desired glyph construction.
start = reinterpret_cast<const char*>(mathvariants);
if (!ValidStructure(start + offset, sizeof(MathGlyphConstruction))) {
return;
}
mGlyphConstruction =
reinterpret_cast<const MathGlyphConstruction*>(start + offset);
}

122
gfx/thebes/gfxMathTable.h Normal file
Просмотреть файл

@ -0,0 +1,122 @@
/* 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_H
#define GFX_MATH_TABLE_H
#include "gfxFont.h"
struct Coverage;
struct GlyphAssembly;
struct MATHTableHeader;
struct MathConstants;
struct MathGlyphConstruction;
struct MathGlyphInfo;
struct MathVariants;
/**
* 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 this reference.
*/
gfxMathTable(hb_blob_t* aMathTable);
/**
* Releases our reference to the MATH table and cleans up everything else.
*/
~gfxMathTable();
/**
* Returns the value of the specified constant from the MATH table.
*/
int32_t GetMathConstant(gfxFontEntry::MathConstant aConstant);
/**
* If the MATH table contains an italic correction for that glyph, this
* function gets the value and returns true. Otherwise it returns false.
*/
bool
GetMathItalicsCorrection(uint32_t aGlyphID, int16_t* aItalicCorrection);
/**
* @param aGlyphID glyph index of the character we want to stretch
* @param aVertical direction of the stretching (vertical/horizontal)
* @param aSize the desired size variant
*
* Returns the glyph index of the desired size variant or 0 if there is not
* any such size variant.
*/
uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
uint16_t aSize);
/**
* @param aGlyphID glyph index of the character we want to stretch
* @param aVertical direction of the stretching (vertical/horizontal)
* @param aGlyphs pre-allocated buffer of 4 elements where the glyph
* indexes (or 0 for absent parts) will be stored. The parts are stored in
* the order expected by the nsMathMLChar: Top (or Left), Middle, Bottom
* (or Right), Glue.
*
* Tries to fill-in aGlyphs with the relevant glyph indexes and returns
* whether the operation was successful. The function returns false if
* there is not any assembly for the character we want to stretch or if
* the format is not supported by the nsMathMLChar code.
*
*/
bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
uint32_t aGlyphs[4]);
protected:
friend class gfxFontEntry;
// This allows gfxFontEntry to verify the validity of the main headers
// before starting to use the MATH table.
bool HasValidHeaders();
private:
// HarfBuzz blob where the MATH table is stored.
hb_blob_t* mMathTable;
// Cached values for the latest (mGlyphID, mVertical) pair that has been
// accessed and the corresponding glyph construction. These are verified
// by SelectGlyphConstruction and updated if necessary.
// mGlyphConstruction will be set to nullptr if no construction is defined
// for the glyph. If non-null, its mGlyphAssembly and mVariantCount fields
// may be safely read, but no further validation will have been done.
const MathGlyphConstruction* mGlyphConstruction;
uint32_t mGlyphID;
bool mVertical;
void SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical);
// Access to some structures of the MATH table.
// These accessors just return a pointer, but do NOT themselves check the
// validity of anything. Until we've checked that HasValidHeaders (which
// does validate them) returns true, they might return pointers that cannot
// even safely be dereferenced. GetGlyphAssembly may return nullptr if the
// given glyph has no assembly defined.
const MATHTableHeader* GetMATHTableHeader();
const MathConstants* GetMathConstants();
const MathGlyphInfo* GetMathGlyphInfo();
const MathVariants* GetMathVariants();
const GlyphAssembly* GetGlyphAssembly(uint32_t aGlyphID, bool aVertical);
// Verify whether a structure or an offset belongs to the math data and can
// be read safely.
bool ValidStructure(const char* aStructStart, uint16_t aStructSize);
bool ValidOffset(const char* aOffsetStart, uint16_t aOffset);
// Get the coverage index of a glyph index from an Open Type coverage table
// or -1 if the glyph index is not found.
int32_t GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph);
};
#endif

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

@ -26,6 +26,7 @@ EXPORTS += [
'gfxGradientCache.h',
'gfxImageSurface.h',
'gfxLineSegment.h',
'gfxMathTable.h',
'gfxMatrix.h',
'gfxPath.h',
'gfxPattern.h',
@ -235,6 +236,7 @@ UNIFIED_SOURCES += [
'gfxGraphiteShaper.cpp',
'gfxHarfBuzzShaper.cpp',
'gfxImageSurface.cpp',
'gfxMathTable.cpp',
'gfxMatrix.cpp',
'gfxPath.cpp',
'gfxPattern.cpp',