Attachment #8346699: Part 1: add a gfxMathTable class to read the MATH table for bug #407059

View | Details | Raw Unified | Return to bug 407059
Collapse All | Expand All

(-)a/gfx/thebes/MathTableStructures.h (+100 lines)
Line     Link Here 
Line 0    Link Here 
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
// This file contains the structures described in Microsoft's document
6
// "The MATH table and OpenType Features for Math Processing" (not yet public).
7
//
8
// Arrays of varying size are indicated in comments. Typically, gfxMathTable
9
// will read the header of the structure first, verify that there is enough
10
// space for the specified arrays and then use a pointer to browse these arrays.
11
12
typedef mozilla::AutoSwap_PRUint16 Count16;
13
typedef mozilla::AutoSwap_PRUint16 GlyphID;
14
typedef mozilla::AutoSwap_PRUint16 Offset;
15
16
struct MathValueRecord {
17
  mozilla::AutoSwap_PRUint16 mValue;
18
  Offset                     mDeviceTable;
19
};
20
21
struct RangeRecord {
22
  GlyphID                    mStart;
23
  GlyphID                    mEnd;
24
  mozilla::AutoSwap_PRUint16 mStartCoverageIndex;
25
};
26
27
struct Coverage {
28
  mozilla::AutoSwap_PRUint16 mFormat;
29
};
30
31
struct CoverageFormat1 {
32
  mozilla::AutoSwap_PRUint16 mFormat;
33
  Count16                    mGlyphCount;
34
  // GlyphID                 mGlyphArray[mGlyphCount]
35
};
36
37
struct CoverageFormat2 {
38
  mozilla::AutoSwap_PRUint16 mFormat;
39
  Count16                    mRangeCount;
40
  // RangeRecord             mRangeArray[mRangeCount];
41
};
42
43
struct MATHTableHeader {
44
  mozilla::AutoSwap_PRUint32 mVersion;
45
  Offset                     mMathConstants;
46
  Offset                     mMathGlyphInfo;
47
  Offset                     mMathVariants;
48
};
49
50
struct MathConstants {
51
  mozilla::AutoSwap_PRUint16 mSingleValues[gfxFontEntry::
52
                                           DisplayOperatorMinHeight -
53
                                           gfxFontEntry::
54
                                           ScriptPercentScaleDown + 1];
55
  MathValueRecord            mMathValues[gfxFontEntry::RadicalKernAfterDegree -
56
                                         gfxFontEntry::MathLeading + 1];
57
  mozilla::AutoSwap_PRUint16 mRadicalDegreeBottomRaisePercent;
58
};
59
60
struct MathVariants {
61
  mozilla::AutoSwap_PRUint16 mMinConnectorOverlap;
62
  Offset                     mVertGlyphCoverage;
63
  Offset                     mHorizGlyphCoverage;
64
  Count16                    mVertGlyphCount;
65
  Count16                    mHorizGlyphCount;
66
  // Offset                  mVertGlyphConstruction[mVertGlyphCount];
67
  // Offset                  mHorizGlyphConstruction[mHorizGlyphCount];
68
};
69
70
struct MathGlyphVariantRecord {
71
  GlyphID                    mVariantGlyph;
72
  mozilla::AutoSwap_PRUint16 mAdvanceMeasurement;
73
};
74
75
struct MathGlyphConstruction {
76
  Offset                    mGlyphAssembly;
77
  Count16                   mVariantCount;
78
  // MathGlyphVariantRecord mMathGlyphVariantRecord[mVariantCount]
79
};
80
81
struct GlyphPartRecord {
82
  GlyphID	              mGlyph;
83
  mozilla::AutoSwap_PRUint16 mStartConnectorLength;
84
  mozilla::AutoSwap_PRUint16 mEndConnectorLength;
85
  mozilla::AutoSwap_PRUint16 mFullAdvance;
86
  mozilla::AutoSwap_PRUint16 mPartFlags;
87
};
88
89
// PartFlags enumeration currently uses only one bit:
90
// 0x0001 If set, the part can be skipped or repeated.
91
// 0xFFFE Reserved.
92
enum {
93
  PART_FLAG_EXTENDER = 0x01
94
};
95
96
struct GlyphAssembly {
97
  MathValueRecord    mItalicsCorrection;
98
  Count16            mPartCount;
99
  // GlyphPartRecord mPartRecords[mPartCount]
100
};
(-)a/gfx/thebes/gfxFont.cpp (+56 lines)
Line     Link Here 
 Lines 33-48    Link Here 
33
#include "nsStyleConsts.h"
33
#include "nsStyleConsts.h"
34
#include "mozilla/FloatingPoint.h"
34
#include "mozilla/FloatingPoint.h"
35
#include "mozilla/Likely.h"
35
#include "mozilla/Likely.h"
36
#include "mozilla/MemoryReporting.h"
36
#include "mozilla/MemoryReporting.h"
37
#include "mozilla/Preferences.h"
37
#include "mozilla/Preferences.h"
38
#include "mozilla/Services.h"
38
#include "mozilla/Services.h"
39
#include "mozilla/Telemetry.h"
39
#include "mozilla/Telemetry.h"
40
#include "gfxSVGGlyphs.h"
40
#include "gfxSVGGlyphs.h"
41
#include "gfxMathTable.h"
41
#include "gfx2DGlue.h"
42
#include "gfx2DGlue.h"
42
43
43
#include "cairo.h"
44
#include "cairo.h"
44
#include "gfxFontTest.h"
45
#include "gfxFontTest.h"
45
46
46
#include "harfbuzz/hb.h"
47
#include "harfbuzz/hb.h"
47
#include "harfbuzz/hb-ot.h"
48
#include "harfbuzz/hb-ot.h"
48
#include "graphite2/Font.h"
49
#include "graphite2/Font.h"
 Lines 95-110   gfxFontEntry::gfxFontEntry() : Link Here 
95
    mIsBadUnderlineFont(false),
96
    mIsBadUnderlineFont(false),
96
    mIsUserFont(false),
97
    mIsUserFont(false),
97
    mIsLocalUserFont(false),
98
    mIsLocalUserFont(false),
98
    mStandardFace(false),
99
    mStandardFace(false),
99
    mSymbolFont(false),
100
    mSymbolFont(false),
100
    mIgnoreGDEF(false),
101
    mIgnoreGDEF(false),
101
    mIgnoreGSUB(false),
102
    mIgnoreGSUB(false),
102
    mSVGInitialized(false),
103
    mSVGInitialized(false),
104
    mMathInitialized(false),
103
    mHasSpaceFeaturesInitialized(false),
105
    mHasSpaceFeaturesInitialized(false),
104
    mHasSpaceFeatures(false),
106
    mHasSpaceFeatures(false),
105
    mHasSpaceFeaturesKerning(false),
107
    mHasSpaceFeaturesKerning(false),
106
    mHasSpaceFeaturesNonKerning(false),
108
    mHasSpaceFeaturesNonKerning(false),
107
    mHasSpaceFeaturesSubDefault(false),
109
    mHasSpaceFeaturesSubDefault(false),
108
    mCheckedForGraphiteTables(false),
110
    mCheckedForGraphiteTables(false),
109
    mHasCmapTable(false),
111
    mHasCmapTable(false),
110
    mGrFaceInitialized(false),
112
    mGrFaceInitialized(false),
 Lines 122-137   gfxFontEntry::gfxFontEntry(const nsAStri Link Here 
122
    mName(aName), mItalic(false), mFixedPitch(false),
124
    mName(aName), mItalic(false), mFixedPitch(false),
123
    mIsProxy(false), mIsValid(true),
125
    mIsProxy(false), mIsValid(true),
124
    mIsBadUnderlineFont(false), mIsUserFont(false),
126
    mIsBadUnderlineFont(false), mIsUserFont(false),
125
    mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
127
    mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
126
    mSymbolFont(false),
128
    mSymbolFont(false),
127
    mIgnoreGDEF(false),
129
    mIgnoreGDEF(false),
128
    mIgnoreGSUB(false),
130
    mIgnoreGSUB(false),
129
    mSVGInitialized(false),
131
    mSVGInitialized(false),
132
    mMathInitialized(false),
130
    mHasSpaceFeaturesInitialized(false),
133
    mHasSpaceFeaturesInitialized(false),
131
    mHasSpaceFeatures(false),
134
    mHasSpaceFeatures(false),
132
    mHasSpaceFeaturesKerning(false),
135
    mHasSpaceFeaturesKerning(false),
133
    mHasSpaceFeaturesNonKerning(false),
136
    mHasSpaceFeaturesNonKerning(false),
134
    mHasSpaceFeaturesSubDefault(false),
137
    mHasSpaceFeaturesSubDefault(false),
135
    mCheckedForGraphiteTables(false),
138
    mCheckedForGraphiteTables(false),
136
    mHasCmapTable(false),
139
    mHasCmapTable(false),
137
    mGrFaceInitialized(false),
140
    mGrFaceInitialized(false),
 Lines 369-384   void Link Here 
369
gfxFontEntry::NotifyGlyphsChanged()
372
gfxFontEntry::NotifyGlyphsChanged()
370
{
373
{
371
    for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
374
    for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
372
        gfxFont* font = mFontsUsingSVGGlyphs[i];
375
        gfxFont* font = mFontsUsingSVGGlyphs[i];
373
        font->NotifyGlyphsChanged();
376
        font->NotifyGlyphsChanged();
374
    }
377
    }
375
}
378
}
376
379
380
bool
381
gfxFontEntry::TryGetMathTable(gfxFont* aFont)
382
{
383
    if (!mMathInitialized) {
384
        mMathInitialized = true;
385
386
        // If UnitsPerEm is not known/valid, we can't use MATH table
387
        if (UnitsPerEm() == kInvalidUPEM) {
388
            return false;
389
        }
390
391
        // We don't use AutoTable here because we'll pass ownership of this
392
        // blob to the gfxMathTable, once we've confirmed the table exists
393
        hb_blob_t *mathTable = GetFontTable(TRUETYPE_TAG('M','A','T','H'));
394
        if (!mathTable) {
395
            return false;
396
        }
397
398
        // gfxMathTable will hb_blob_destroy() the table when it is finished
399
        // with it.
400
        mMathTable = new gfxMathTable(mathTable);
401
        if (!mMathTable->HasValidHeaders()) {
402
            mMathTable = nullptr;
403
            return false;
404
        }
405
    }
406
407
    return !!mMathTable;
408
}
409
410
gfxFloat
411
gfxFontEntry::GetMathConstant(gfxFontEntry::MathConstant aConstant)
412
{
413
    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
414
    return gfxFloat(mMathTable->GetMathConstant(aConstant)) / mUnitsPerEm;
415
}
416
417
uint32_t
418
gfxFontEntry::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
419
                                  uint16_t aSize)
420
{
421
    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
422
    return mMathTable->GetMathVariantsSize(aGlyphID, aVertical, aSize);
423
}
424
425
bool
426
gfxFontEntry::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
427
                                   uint32_t* aGlyphs)
428
{
429
    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
430
    return mMathTable->GetMathVariantsParts(aGlyphID, aVertical, aGlyphs);
431
}
432
377
/**
433
/**
378
 * FontTableBlobData
434
 * FontTableBlobData
379
 *
435
 *
380
 * See FontTableHashEntry for the general strategy.
436
 * See FontTableHashEntry for the general strategy.
381
 */
437
 */
382
438
383
class gfxFontEntry::FontTableBlobData {
439
class gfxFontEntry::FontTableBlobData {
384
public:
440
public:
(-)a/gfx/thebes/gfxFont.h (+73 lines)
Line     Link Here 
 Lines 43-58   class gfxTextRun; Link Here 
43
class gfxFont;
43
class gfxFont;
44
class gfxFontFamily;
44
class gfxFontFamily;
45
class gfxFontGroup;
45
class gfxFontGroup;
46
class gfxUserFontSet;
46
class gfxUserFontSet;
47
class gfxUserFontData;
47
class gfxUserFontData;
48
class gfxShapedText;
48
class gfxShapedText;
49
class gfxShapedWord;
49
class gfxShapedWord;
50
class gfxSVGGlyphs;
50
class gfxSVGGlyphs;
51
class gfxMathTable;
51
class gfxTextContextPaint;
52
class gfxTextContextPaint;
52
53
53
class nsILanguageAtomService;
54
class nsILanguageAtomService;
54
55
55
#define FONT_MAX_SIZE                  2000.0
56
#define FONT_MAX_SIZE                  2000.0
56
57
57
#define NO_FONT_LANGUAGE_OVERRIDE      0
58
#define NO_FONT_LANGUAGE_OVERRIDE      0
58
59
 Lines 306-321   public: Link Here 
306
    bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
307
    bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
307
                            gfxRect *aResult);
308
                            gfxRect *aResult);
308
    bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode,
309
    bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode,
309
                        gfxTextContextPaint *aContextPaint);
310
                        gfxTextContextPaint *aContextPaint);
310
    // Call this when glyph geometry or rendering has changed
311
    // Call this when glyph geometry or rendering has changed
311
    // (e.g. animated SVG glyphs)
312
    // (e.g. animated SVG glyphs)
312
    void NotifyGlyphsChanged();
313
    void NotifyGlyphsChanged();
313
314
315
    // Call TryGetMathTable to try to load the Open Type MATH table. The other
316
    // functions forward the call to the gfxMathTable class. The GetMath...()
317
    // functions MUST NOT be called unless TryGetMathTable() has returned true.
318
    bool     TryGetMathTable(gfxFont* aFont);
319
    enum MathConstant {
320
        // The order of the constants must match the order of the fields
321
        // defined in the MATH table.
322
        ScriptPercentScaleDown,
323
        ScriptScriptPercentScaleDown,
324
        DelimitedSubFormulaMinHeight,
325
        DisplayOperatorMinHeight,
326
        MathLeading,
327
        AxisHeight,
328
        AccentBaseHeight,
329
        FlattenedAccentBaseHeight,
330
        SubscriptShiftDown,
331
        SubscriptTopMax,
332
        SubscriptBaselineDropMin,
333
        SuperscriptShiftUp,
334
        SuperscriptShiftUpCramped,
335
        SuperscriptBottomMin,
336
        SuperscriptBaselineDropMax,
337
        SubSuperscriptGapMin,
338
        SuperscriptBottomMaxWithSubscript,
339
        SpaceAfterScript,
340
        UpperLimitGapMin,
341
        UpperLimitBaselineRiseMin,
342
        LowerLimitGapMin,
343
        LowerLimitBaselineDropMin,
344
        StackTopShiftUp,
345
        StackTopDisplayStyleShiftUp,
346
        StackBottomShiftDown,
347
        StackBottomDisplayStyleShiftDown,
348
        StackGapMin,
349
        StackDisplayStyleGapMin,
350
        StretchStackTopShiftUp,
351
        StretchStackBottomShiftDown,
352
        StretchStackGapAboveMin,
353
        StretchStackGapBelowMin,
354
        FractionNumeratorShiftUp,
355
        FractionNumeratorDisplayStyleShiftUp,
356
        FractionDenominatorShiftDown,
357
        FractionDenominatorDisplayStyleShiftDown,
358
        FractionNumeratorGapMin,
359
        FractionNumDisplayStyleGapMin,
360
        FractionRuleThickness,
361
        FractionDenominatorGapMin,
362
        FractionDenomDisplayStyleGapMin,
363
        SkewedFractionHorizontalGap,
364
        SkewedFractionVerticalGap,
365
        OverbarVerticalGap,
366
        OverbarRuleThickness,
367
        OverbarExtraAscender,
368
        UnderbarVerticalGap,
369
        UnderbarRuleThickness,
370
        UnderbarExtraDescender,
371
        RadicalVerticalGap,
372
        RadicalDisplayStyleVerticalGap,
373
        RadicalRuleThickness,
374
        RadicalExtraAscender,
375
        RadicalKernBeforeDegree,
376
        RadicalKernAfterDegree,
377
        RadicalDegreeBottomRaisePercent
378
    };
379
    gfxFloat GetMathConstant(MathConstant aConstant);
380
    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
381
                                 uint16_t aSize);
382
    bool     GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
383
                                  uint32_t* aGlyphs);
384
314
    virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
385
    virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
315
        return true;
386
        return true;
316
    }
387
    }
317
    virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
388
    virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
318
        return true;
389
        return true;
319
    }
390
    }
320
391
321
    // Access to raw font table data (needed for Harfbuzz):
392
    // Access to raw font table data (needed for Harfbuzz):
 Lines 428-443   public: Link Here 
428
    bool             mIsBadUnderlineFont : 1;
499
    bool             mIsBadUnderlineFont : 1;
429
    bool             mIsUserFont  : 1;
500
    bool             mIsUserFont  : 1;
430
    bool             mIsLocalUserFont  : 1;
501
    bool             mIsLocalUserFont  : 1;
431
    bool             mStandardFace : 1;
502
    bool             mStandardFace : 1;
432
    bool             mSymbolFont  : 1;
503
    bool             mSymbolFont  : 1;
433
    bool             mIgnoreGDEF  : 1;
504
    bool             mIgnoreGDEF  : 1;
434
    bool             mIgnoreGSUB  : 1;
505
    bool             mIgnoreGSUB  : 1;
435
    bool             mSVGInitialized : 1;
506
    bool             mSVGInitialized : 1;
507
    bool             mMathInitialized : 1;
436
    bool             mHasSpaceFeaturesInitialized : 1;
508
    bool             mHasSpaceFeaturesInitialized : 1;
437
    bool             mHasSpaceFeatures : 1;
509
    bool             mHasSpaceFeatures : 1;
438
    bool             mHasSpaceFeaturesKerning : 1;
510
    bool             mHasSpaceFeaturesKerning : 1;
439
    bool             mHasSpaceFeaturesNonKerning : 1;
511
    bool             mHasSpaceFeaturesNonKerning : 1;
440
    bool             mHasSpaceFeaturesSubDefault : 1;
512
    bool             mHasSpaceFeaturesSubDefault : 1;
441
    bool             mHasGraphiteTables : 1;
513
    bool             mHasGraphiteTables : 1;
442
    bool             mCheckedForGraphiteTables : 1;
514
    bool             mCheckedForGraphiteTables : 1;
443
    bool             mHasCmapTable : 1;
515
    bool             mHasCmapTable : 1;
 Lines 451-466   public: Link Here 
451
523
452
    nsRefPtr<gfxCharacterMap> mCharacterMap;
524
    nsRefPtr<gfxCharacterMap> mCharacterMap;
453
    uint32_t         mUVSOffset;
525
    uint32_t         mUVSOffset;
454
    nsAutoArrayPtr<uint8_t> mUVSData;
526
    nsAutoArrayPtr<uint8_t> mUVSData;
455
    nsAutoPtr<gfxUserFontData> mUserFontData;
527
    nsAutoPtr<gfxUserFontData> mUserFontData;
456
    nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
528
    nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
457
    // list of gfxFonts that are using SVG glyphs
529
    // list of gfxFonts that are using SVG glyphs
458
    nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
530
    nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
531
    nsAutoPtr<gfxMathTable> mMathTable;
459
    nsTArray<gfxFontFeature> mFeatureSettings;
532
    nsTArray<gfxFontFeature> mFeatureSettings;
460
    uint32_t         mLanguageOverride;
533
    uint32_t         mLanguageOverride;
461
534
462
protected:
535
protected:
463
    friend class gfxPlatformFontList;
536
    friend class gfxPlatformFontList;
464
    friend class gfxMacPlatformFontList;
537
    friend class gfxMacPlatformFontList;
465
    friend class gfxUserFcFontEntry;
538
    friend class gfxUserFcFontEntry;
466
    friend class gfxFontFamily;
539
    friend class gfxFontFamily;
(-)a/gfx/thebes/gfxMathTable.cpp (+394 lines)
Line     Link Here 
Line 0    Link Here 
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "gfxMathTable.h"
6
7
#include "MathTableStructures.h"
8
#include "gfxFont.h"
9
#include "harfbuzz/hb.h"
10
#include <algorithm>
11
12
using namespace mozilla;
13
14
gfxMathTable::gfxMathTable(hb_blob_t* aMathTable)
15
  : mMathTable(aMathTable)
16
  , mGlyphConstruction(nullptr)
17
  , mGlyphID(0)
18
  , mVertical(false)
19
{
20
}
21
22
gfxMathTable::~gfxMathTable()
23
{
24
  hb_blob_destroy(mMathTable);
25
}
26
27
bool
28
gfxMathTable::HasValidHeaders()
29
{
30
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
31
  // Verify the MATH table header.
32
  if (!ValidStructure(mathData, sizeof(MATHTableHeader))) {
33
    return false;
34
  }
35
  const MATHTableHeader* header = GetMATHTableHeader();
36
  if (uint32_t(header->mVersion) != 0x00010000 ||
37
      !ValidOffset(mathData, uint16_t(header->mMathConstants)) ||
38
      !ValidOffset(mathData, uint16_t(header->mMathGlyphInfo)) ||
39
      !ValidOffset(mathData, uint16_t(header->mMathVariants))) {
40
    return false;
41
  }
42
43
  // Verify the MathConstants header.
44
  const MathConstants* mathconstants = GetMathConstants();
45
  const char *start = reinterpret_cast<const char*>(mathconstants);
46
  if (!ValidStructure(start, sizeof(MathConstants))) {
47
    return false;
48
  }
49
50
  // Verify the MathVariants header.
51
  const MathVariants* mathvariants = GetMathVariants();
52
  start = reinterpret_cast<const char*>(mathvariants);
53
  if (!ValidStructure(start, sizeof(MathVariants)) ||
54
      !ValidStructure(start,
55
                      sizeof(MathVariants) + sizeof(Offset) *
56
                      (uint16_t(mathvariants->mVertGlyphCount) +
57
                       uint16_t(mathvariants->mHorizGlyphCount))) ||
58
      !ValidOffset(start, uint16_t(mathvariants->mVertGlyphCoverage)) ||
59
      !ValidOffset(start, uint16_t(mathvariants->mHorizGlyphCoverage))) {
60
    return false;
61
  }
62
63
  return true;
64
}
65
66
uint16_t
67
gfxMathTable::GetMathConstant(gfxFontEntry::MathConstant aConstant)
68
{
69
  const MathConstants* mathconstants = GetMathConstants();
70
71
  if (aConstant <= gfxFontEntry::DisplayOperatorMinHeight) {
72
    return uint16_t(mathconstants->mSingleValues[aConstant]);
73
  }
74
75
  if (aConstant <= gfxFontEntry::RadicalKernAfterDegree) {
76
    return uint16_t(mathconstants->
77
                    mMathValues[aConstant - gfxFontEntry::MathLeading].mValue);
78
  }
79
80
  return uint16_t(mathconstants->mRadicalDegreeBottomRaisePercent);
81
}
82
83
uint32_t
84
gfxMathTable::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
85
                                  uint16_t aSize)
86
{
87
  // Select the glyph construction.
88
  SelectGlyphConstruction(aGlyphID, aVertical);
89
  if (!mGlyphConstruction) {
90
    return 0;
91
  }
92
93
  // Verify the validity of the array of the MathGlyphVariantRecord's and
94
  // whether there is a variant of the requested size.
95
  uint16_t count = mGlyphConstruction->mVariantCount;
96
  const char *start = reinterpret_cast<const char*>(mGlyphConstruction + 1);
97
  if (aSize >= count ||
98
      !ValidStructure(start, count * sizeof(MathGlyphVariantRecord))) {
99
    return 0;
100
  }
101
102
  // Return the glyph index of the requested size variant.
103
  const MathGlyphVariantRecord* recordArray =
104
    reinterpret_cast<const MathGlyphVariantRecord*>(start);
105
  return uint32_t(recordArray[aSize].mVariantGlyph);
106
}
107
108
bool
109
gfxMathTable::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
110
                                   uint32_t* aGlyphs)
111
{
112
  // Get the glyph assembly corresponding to that (aGlyphID, aVertical) pair.
113
  const GlyphAssembly* glyphAssembly = GetGlyphAssembly(aGlyphID, aVertical);
114
  if (!glyphAssembly) {
115
    return false;
116
  }
117
118
  // Verify the validity of the array of GlyphPartRecord's and retrieve it.
119
  uint16_t count = glyphAssembly->mPartCount;
120
  const char* start = reinterpret_cast<const char*>(glyphAssembly + 1);
121
  if (!ValidStructure(start, count * sizeof(GlyphPartRecord))) {
122
    return false;
123
  }
124
  const GlyphPartRecord* recordArray =
125
    reinterpret_cast<const GlyphPartRecord*>(start);
126
127
  // XXXfredw The structure of the Open Type Math table is a bit more general
128
  // than the one currently used by the nsMathMLChar code, so we try to fallback
129
  // in reasonable way. We use the approach of the copyComponents function in
130
  // github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py 
131
  //
132
  // The nsMathMLChar code can use at most 3 non extender pieces (aGlyphs[0],
133
  // aGlyphs[1] and aGlyphs[2]) and the extenders between these pieces should
134
  // all be the same (aGlyphs[4]). Also, the parts of vertical assembly are
135
  // stored from bottom to top in the Open Type MATH table while they are
136
  // stored from top to bottom in nsMathMLChar.
137
  //
138
139
  // Count the number of non extender pieces
140
  uint16_t nonExtenderCount = 0;
141
  for (uint16_t i = 0; i < count; i++) {
142
    if (!(uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER)) {
143
      nonExtenderCount++;
144
    }
145
  }
146
  if (nonExtenderCount > 3) {
147
    // Not supported: too many pieces
148
    return false;
149
  }
150
151
  // Now browse the list of pieces
152
153
  // 0 = look for a left/bottom glyph
154
  // 1 = look for an extender between left/bottom and mid
155
  // 2 = look for a middle glyph
156
  // 3 = look for an extender between middle and right/top
157
  // 4 = look for a right/top glyph
158
  // 5 = no more piece expected
159
  uint8_t state = 0;
160
161
  // First extender char found.
162
  uint32_t extenderChar = 0;
163
164
  // Clear the aGlyphs table.
165
  aGlyphs[0] = aGlyphs[1] = aGlyphs[2] = aGlyphs[3] = 0;
166
167
  for (uint16_t i = 0; i < count; i++) {
168
169
    bool isExtender = uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER;
170
    uint32_t glyph = recordArray[i].mGlyph;
171
172
    if ((state == 1 || state == 2) && nonExtenderCount < 3) {
173
      // do not try to find a middle glyph
174
      state += 2;
175
    }
176
177
    if (isExtender) {
178
      if (!extenderChar) {
179
        extenderChar = glyph;
180
        aGlyphs[3] = extenderChar;
181
      } else if (extenderChar != glyph)  {
182
        // Not supported: different extenders
183
        return false;
184
      }
185
186
      if (state == 0) { // or state == 1
187
        // ignore left/bottom piece and multiple successive extenders
188
        state = 1;
189
      } else if (state == 2) { // or state == 3
190
        // ignore middle piece and multiple successive extenders
191
        state = 3;
192
      } else if (state >= 4) {
193
        // Not supported: unexpected extender
194
        return false;
195
      }
196
197
      continue;
198
    }
199
200
    if (state == 0) {
201
      // copy left/bottom part
202
      aGlyphs[mVertical ? 2 : 0] = glyph;
203
      state = 1;
204
      continue;
205
    }
206
207
    if (state == 1 || state == 2) {
208
      // copy middle part
209
      aGlyphs[1] = glyph;
210
      state = 3;
211
      continue;
212
    }
213
214
    if (state == 3 || state == 4) {
215
      // copy right/top part
216
      aGlyphs[mVertical ? 0 : 2] = glyph;
217
      state = 5;
218
    }
219
220
  }
221
222
  return true;
223
}
224
225
bool
226
gfxMathTable::ValidStructure(const char* aStart, uint16_t aSize)
227
{
228
  unsigned int mathDataLength;
229
  const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
230
  return (mathData <= aStart &&
231
          aStart + aSize <= mathData + mathDataLength);
232
}
233
234
bool
235
gfxMathTable::ValidOffset(const char* aStart, uint16_t aOffset)
236
{
237
  unsigned int mathDataLength;
238
  const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
239
  return (mathData <= aStart + aOffset &&
240
          aStart + aOffset < mathData + mathDataLength);
241
}
242
243
const MATHTableHeader*
244
gfxMathTable::GetMATHTableHeader()
245
{
246
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
247
  return reinterpret_cast<const MATHTableHeader*>(mathData);
248
};
249
250
const MathConstants*
251
gfxMathTable::GetMathConstants()
252
{
253
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
254
  return
255
    reinterpret_cast<const MathConstants*>(mathData +
256
                                           uint16_t(GetMATHTableHeader()->
257
                                                    mMathConstants));
258
}
259
const MathVariants*
260
gfxMathTable::GetMathVariants()
261
{
262
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
263
  return
264
    reinterpret_cast<const MathVariants*>(mathData +
265
                                          uint16_t(GetMATHTableHeader()->
266
                                                   mMathVariants));
267
}
268
269
const GlyphAssembly*
270
gfxMathTable::GetGlyphAssembly(uint32_t aGlyphID, bool aVertical)
271
{
272
  // Select the glyph construction.
273
  SelectGlyphConstruction(aGlyphID, aVertical);
274
  if (!mGlyphConstruction) {
275
    return nullptr;
276
  }
277
278
  // Get the offset of the glyph assembly and verify whether it is valid.
279
  const char* start = reinterpret_cast<const char*>(mGlyphConstruction);
280
  uint16_t offset = mGlyphConstruction->mGlyphAssembly;
281
  if (offset == 0 || !ValidOffset(start, offset)) {
282
    return nullptr;
283
  }
284
  start += offset;
285
286
  // Verify the validy of the GlyphAssembly and return it.
287
  if (!ValidStructure(start, sizeof(GlyphAssembly))) {
288
    return nullptr;
289
  }
290
  return reinterpret_cast<const GlyphAssembly*>(start);
291
}
292
293
int32_t
294
gfxMathTable::GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph)
295
{
296
  if (uint16_t(aCoverage->mFormat) == 1) {
297
    // Coverage Format 1: list of individual glyph indices in the glyph set.
298
    const CoverageFormat1* table =
299
      reinterpret_cast<const CoverageFormat1*>(aCoverage);
300
    uint16_t count = table->mGlyphCount;
301
    const char* start = reinterpret_cast<const char*>(table + 1);
302
    if (ValidStructure(start, count * sizeof(GlyphID))) {
303
      const GlyphID* glyphArray =
304
        reinterpret_cast<const GlyphID*>(start);
305
      uint32_t imin = 0, imax = count;
306
      while (imin < imax) {
307
        uint32_t imid = (imin + imax) >> 1;
308
        uint16_t glyphMid = glyphArray[imid];
309
        if (glyphMid == aGlyph) {
310
          return imid;
311
        }
312
        if (glyphMid < aGlyph) {
313
          imin = imid + 1;
314
        } else {
315
          imax = imid;
316
        }
317
      }
318
    }
319
  } else if (uint16_t(aCoverage->mFormat) == 2) {
320
    // Coverage Format 2: ranges of consecutive indices.
321
    const CoverageFormat2* table =
322
      reinterpret_cast<const CoverageFormat2*>(aCoverage);
323
    uint16_t count = table->mRangeCount;
324
    const char* start = reinterpret_cast<const char*>(table + 1);
325
    if (ValidStructure(start, count * sizeof(RangeRecord))) {
326
      const RangeRecord* rangeArray =
327
        reinterpret_cast<const RangeRecord*>(start);
328
      uint32_t imin = 0, imax = count;
329
      while (imin < imax) {
330
        uint32_t imid = (imin + imax) >> 1;
331
        uint16_t rStart = rangeArray[imid].mStart;
332
        uint16_t rEnd = rangeArray[imid].mEnd;
333
        if (rEnd < aGlyph) {
334
          imin = imid + 1;
335
        } else if (aGlyph < rStart) {
336
          imax = imid;
337
        } else {
338
          return (uint16_t(rangeArray[imid].mStartCoverageIndex) +
339
                  aGlyph - rStart);
340
        }
341
      }
342
    }
343
  }
344
  return -1;
345
}
346
347
void
348
gfxMathTable::SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical)
349
{
350
  if (mGlyphID == aGlyphID && mVertical == aVertical) {
351
    // The (glyph, direction) pair is already selected: nothing to do.
352
    return;
353
  }
354
355
  // Update our cached values.
356
  mVertical = aVertical;
357
  mGlyphID = aGlyphID;
358
  mGlyphConstruction = nullptr;
359
360
  // Get the coverage index for the new values.
361
  const MathVariants* mathvariants = GetMathVariants();
362
  const char *start = reinterpret_cast<const char*>(mathvariants);
363
  uint16_t offset = (aVertical ?
364
                     mathvariants->mVertGlyphCoverage :
365
                     mathvariants->mHorizGlyphCoverage);
366
  const Coverage* coverage =
367
    reinterpret_cast<const Coverage*>(start + offset);
368
  int32_t i = GetCoverageIndex(coverage, aGlyphID);
369
370
  // Get the offset to the glyph construction.
371
  uint16_t count = (aVertical ?
372
                    mathvariants->mVertGlyphCount :
373
                    mathvariants->mHorizGlyphCount);
374
  start = reinterpret_cast<const char*>(mathvariants + 1);
375
  if (i < 0 || i >= count) {
376
    return;
377
  }
378
  if (!aVertical) {
379
    start += uint16_t(mathvariants->mVertGlyphCount) * sizeof(Offset);
380
  }
381
  if (!ValidStructure(start, count * sizeof(Offset))) {
382
    return;
383
  }
384
  const Offset* offsetArray = reinterpret_cast<const Offset*>(start);
385
  offset = uint16_t(offsetArray[i]);
386
387
  // Make mGlyphConstruction point to the desired glyph construction.
388
  start = reinterpret_cast<const char*>(mathvariants);
389
  if (!ValidOffset(start, offset)) {
390
    return;
391
  }
392
  mGlyphConstruction =
393
    reinterpret_cast<const MathGlyphConstruction*>(start + offset);
394
}
(-)a/gfx/thebes/gfxMathTable.h (+106 lines)
Line     Link Here 
Line 0    Link Here 
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#ifndef GFX_MATH_TABLE_WRAPPER_H
6
#define GFX_MATH_TABLE_WRAPPER_H
7
8
#include "gfxFontUtils.h"
9
#include "gfxFont.h"
10
11
struct Coverage;
12
struct GlyphAssembly;
13
struct MATHTableHeader;
14
struct MathConstants;
15
struct MathGlyphConstruction;
16
struct MathVariants;
17
18
/**
19
 * Used by |gfxFontEntry| to represent the MATH table of an OpenType font.
20
 * Each |gfxFontEntry| owns at most one |gfxMathTable| instance.
21
 */
22
class gfxMathTable
23
{
24
public:
25
    /**
26
     * @param aMathTable The MATH table from the OpenType font
27
     *
28
     * The gfxMathTable object takes over ownership of the blob references
29
     * that are passed in, and will hb_blob_destroy() them when finished;
30
     * the caller should -not- destroy these references.
31
     */
32
    gfxMathTable(hb_blob_t* aMathTable);
33
34
    /**
35
     * Releases our references to the Math table and cleans up everything else.
36
     */
37
    ~gfxMathTable();
38
39
    /**
40
     * Returns the value of the specified constant from the MATH table.
41
     */
42
    uint16_t GetMathConstant(gfxFontEntry::MathConstant aConstant);
43
44
    /**
45
     * @param aGlyphID  glyph index of the character we want to stretch
46
     * @param aVertical direction of the stretching (vertical/horizontal)
47
     * @param aSize     the desired size variant
48
     *
49
     * Returns the glyph index of the desired size variant or 0 if there is not
50
     * any such size variant.
51
     */
52
    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
53
                                 uint16_t aSize);
54
55
    /**
56
     * @param aGlyphID  glyph index of the character we want to stretch
57
     * @param aVertical direction of the stretching (vertical/horizontal)
58
     * @param aGlyphs   pre-allocated buffer of 4 elements where the glyph
59
     * indexes (or 0 for absent parts) will be stored. The parts are stored in
60
     * the order expected by the nsMathMLChar: Top (or Left), Middle, Bottom
61
     * (or Right), Glue.
62
     *
63
     * Tries to fill-in aGlyphs with the relevant glyph indexes and returns
64
     * whether the operation was successful. The function returns false if
65
     * there is not any assembly for the character we want to stretch or if
66
     * the format is not supported by the nsMathMLChar code.
67
     *
68
     */
69
    bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
70
                              uint32_t* aGlyphs);
71
72
protected:
73
    friend class gfxFontEntry;
74
    // This allows gfxFontEntry to verify the validity of the main headers
75
    // before starting to use the MATH table.
76
    bool HasValidHeaders();
77
78
private:
79
    // HarfBuzz blob where the MATH table is stored.
80
    hb_blob_t*    mMathTable;
81
82
    // Cached values for the latest (mGlyphID, mVertical) pair that has been
83
    // accessed and the corresponding glyph construction. These are verified
84
    // by SelectGlyphConstruction and updated if necessary.
85
    const MathGlyphConstruction* mGlyphConstruction;
86
    uint32_t mGlyphID;
87
    bool     mVertical;
88
    void     SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical);
89
90
    // Access to some structures of the MATH table.
91
    const MATHTableHeader* GetMATHTableHeader();
92
    const MathConstants*   GetMathConstants();
93
    const MathVariants*    GetMathVariants();
94
    const GlyphAssembly*   GetGlyphAssembly(uint32_t aGlyphID, bool aVertical);
95
96
    // Verify whether a structure or an offset belongs to the math data and can
97
    // be read safely.
98
    bool ValidStructure(const char* aStructStart, uint16_t aStructSize);
99
    bool ValidOffset(const char* aOffsetStart, uint16_t aOffset);
100
101
    // Get the coverage index of a glyph index from an Open Type coverage table
102
    // or -1 if the glyph index is not found.
103
    int32_t GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph);
104
};
105
106
#endif
(-)a/gfx/thebes/moz.build (+2 lines)
Line     Link Here 
 Lines 20-35   EXPORTS += [ Link Here 
20
    'gfxFont.h',
20
    'gfxFont.h',
21
    'gfxFontConstants.h',
21
    'gfxFontConstants.h',
22
    'gfxFontFeatures.h',
22
    'gfxFontFeatures.h',
23
    'gfxFontTest.h',
23
    'gfxFontTest.h',
24
    'gfxFontUtils.h',
24
    'gfxFontUtils.h',
25
    'gfxGradientCache.h',
25
    'gfxGradientCache.h',
26
    'gfxImageSurface.h',
26
    'gfxImageSurface.h',
27
    'gfxLineSegment.h',
27
    'gfxLineSegment.h',
28
    'gfxMathTable.h',
28
    'gfxMatrix.h',
29
    'gfxMatrix.h',
29
    'gfxPath.h',
30
    'gfxPath.h',
30
    'gfxPattern.h',
31
    'gfxPattern.h',
31
    'gfxPlatform.h',
32
    'gfxPlatform.h',
32
    'gfxPoint.h',
33
    'gfxPoint.h',
33
    'gfxPoint3D.h',
34
    'gfxPoint3D.h',
34
    'gfxPointH3D.h',
35
    'gfxPointH3D.h',
35
    'gfxQuad.h',
36
    'gfxQuad.h',
 Lines 261-276   UNIFIED_SOURCES += [ Link Here 
261
    'gfxContext.cpp',
262
    'gfxContext.cpp',
262
    'gfxFontFeatures.cpp',
263
    'gfxFontFeatures.cpp',
263
    'gfxFontMissingGlyphs.cpp',
264
    'gfxFontMissingGlyphs.cpp',
264
    'gfxFontTest.cpp',
265
    'gfxFontTest.cpp',
265
    'gfxGradientCache.cpp',
266
    'gfxGradientCache.cpp',
266
    'gfxGraphiteShaper.cpp',
267
    'gfxGraphiteShaper.cpp',
267
    'gfxHarfBuzzShaper.cpp',
268
    'gfxHarfBuzzShaper.cpp',
268
    'gfxImageSurface.cpp',
269
    'gfxImageSurface.cpp',
270
    'gfxMathTable.cpp',
269
    'gfxMatrix.cpp',
271
    'gfxMatrix.cpp',
270
    'gfxPath.cpp',
272
    'gfxPath.cpp',
271
    'gfxPattern.cpp',
273
    'gfxPattern.cpp',
272
    'gfxRect.cpp',
274
    'gfxRect.cpp',
273
    'gfxReusableImageSurfaceWrapper.cpp',
275
    'gfxReusableImageSurfaceWrapper.cpp',
274
    'gfxReusableSharedImageSurfaceWrapper.cpp',
276
    'gfxReusableSharedImageSurfaceWrapper.cpp',
275
    'gfxScriptItemizer.cpp',
277
    'gfxScriptItemizer.cpp',
276
    'gfxSkipChars.cpp',
278
    'gfxSkipChars.cpp',

Return to bug 407059