Attachment #8361060: 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 (+113 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 MathGlyphInfo {
61
  Offset mMathItalicsCorrectionInfo;
62
  Offset mMathTopAccentAttachment;
63
  Offset mExtendedShapeCoverage;
64
  Offset mMathKernInfo;
65
};
66
67
struct MathItalicsCorrectionInfo {
68
  Offset  mCoverage;
69
  Count16 mItalicsCorrectionCount;
70
  // MathValueRecord mItalicsCorrection[mItalicsCorrectionCount]
71
};
72
73
struct MathVariants {
74
  mozilla::AutoSwap_PRUint16 mMinConnectorOverlap;
75
  Offset                     mVertGlyphCoverage;
76
  Offset                     mHorizGlyphCoverage;
77
  Count16                    mVertGlyphCount;
78
  Count16                    mHorizGlyphCount;
79
  // Offset                  mVertGlyphConstruction[mVertGlyphCount];
80
  // Offset                  mHorizGlyphConstruction[mHorizGlyphCount];
81
};
82
83
struct MathGlyphVariantRecord {
84
  GlyphID                    mVariantGlyph;
85
  mozilla::AutoSwap_PRUint16 mAdvanceMeasurement;
86
};
87
88
struct MathGlyphConstruction {
89
  Offset                    mGlyphAssembly;
90
  Count16                   mVariantCount;
91
  // MathGlyphVariantRecord mMathGlyphVariantRecord[mVariantCount]
92
};
93
94
struct GlyphPartRecord {
95
  GlyphID	              mGlyph;
96
  mozilla::AutoSwap_PRUint16 mStartConnectorLength;
97
  mozilla::AutoSwap_PRUint16 mEndConnectorLength;
98
  mozilla::AutoSwap_PRUint16 mFullAdvance;
99
  mozilla::AutoSwap_PRUint16 mPartFlags;
100
};
101
102
// PartFlags enumeration currently uses only one bit:
103
// 0x0001 If set, the part can be skipped or repeated.
104
// 0xFFFE Reserved.
105
enum {
106
  PART_FLAG_EXTENDER = 0x01
107
};
108
109
struct GlyphAssembly {
110
  MathValueRecord    mItalicsCorrection;
111
  Count16            mPartCount;
112
  // GlyphPartRecord mPartRecords[mPartCount]
113
};
(-)a/gfx/thebes/gfxFont.cpp (+68 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
bool gfxFontEntry::GetMathItalicCorrection(uint32_t aGlyphID,
418
                                           gfxFloat* aItalicCorrection)
419
{
420
    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
421
    uint16_t italicCorrection;
422
    if (!mMathTable->GetMathItalicCorrection(aGlyphID, &italicCorrection)) {
423
        return false;
424
    }
425
    *aItalicCorrection = gfxFloat(italicCorrection) / mUnitsPerEm;
426
    return true;
427
}
428
429
uint32_t
430
gfxFontEntry::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
431
                                  uint16_t aSize)
432
{
433
    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
434
    return mMathTable->GetMathVariantsSize(aGlyphID, aVertical, aSize);
435
}
436
437
bool
438
gfxFontEntry::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
439
                                   uint32_t* aGlyphs)
440
{
441
    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
442
    return mMathTable->GetMathVariantsParts(aGlyphID, aVertical, aGlyphs);
443
}
444
377
/**
445
/**
378
 * FontTableBlobData
446
 * FontTableBlobData
379
 *
447
 *
380
 * See FontTableHashEntry for the general strategy.
448
 * See FontTableHashEntry for the general strategy.
381
 */
449
 */
382
450
383
class gfxFontEntry::FontTableBlobData {
451
class gfxFontEntry::FontTableBlobData {
384
public:
452
public:
(-)a/gfx/thebes/gfxFont.h (+75 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
    bool     GetMathItalicCorrection(uint32_t aGlyphID,
381
                                     gfxFloat* aItalicCorrection);
382
    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
383
                                 uint16_t aSize);
384
    bool     GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
385
                                  uint32_t* aGlyphs);
386
314
    virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
387
    virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
315
        return true;
388
        return true;
316
    }
389
    }
317
    virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
390
    virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
318
        return true;
391
        return true;
319
    }
392
    }
320
393
321
    // Access to raw font table data (needed for Harfbuzz):
394
    // Access to raw font table data (needed for Harfbuzz):
 Lines 428-443   public: Link Here 
428
    bool             mIsBadUnderlineFont : 1;
501
    bool             mIsBadUnderlineFont : 1;
429
    bool             mIsUserFont  : 1;
502
    bool             mIsUserFont  : 1;
430
    bool             mIsLocalUserFont  : 1;
503
    bool             mIsLocalUserFont  : 1;
431
    bool             mStandardFace : 1;
504
    bool             mStandardFace : 1;
432
    bool             mSymbolFont  : 1;
505
    bool             mSymbolFont  : 1;
433
    bool             mIgnoreGDEF  : 1;
506
    bool             mIgnoreGDEF  : 1;
434
    bool             mIgnoreGSUB  : 1;
507
    bool             mIgnoreGSUB  : 1;
435
    bool             mSVGInitialized : 1;
508
    bool             mSVGInitialized : 1;
509
    bool             mMathInitialized : 1;
436
    bool             mHasSpaceFeaturesInitialized : 1;
510
    bool             mHasSpaceFeaturesInitialized : 1;
437
    bool             mHasSpaceFeatures : 1;
511
    bool             mHasSpaceFeatures : 1;
438
    bool             mHasSpaceFeaturesKerning : 1;
512
    bool             mHasSpaceFeaturesKerning : 1;
439
    bool             mHasSpaceFeaturesNonKerning : 1;
513
    bool             mHasSpaceFeaturesNonKerning : 1;
440
    bool             mHasSpaceFeaturesSubDefault : 1;
514
    bool             mHasSpaceFeaturesSubDefault : 1;
441
    bool             mHasGraphiteTables : 1;
515
    bool             mHasGraphiteTables : 1;
442
    bool             mCheckedForGraphiteTables : 1;
516
    bool             mCheckedForGraphiteTables : 1;
443
    bool             mHasCmapTable : 1;
517
    bool             mHasCmapTable : 1;
 Lines 451-466   public: Link Here 
451
525
452
    nsRefPtr<gfxCharacterMap> mCharacterMap;
526
    nsRefPtr<gfxCharacterMap> mCharacterMap;
453
    uint32_t         mUVSOffset;
527
    uint32_t         mUVSOffset;
454
    nsAutoArrayPtr<uint8_t> mUVSData;
528
    nsAutoArrayPtr<uint8_t> mUVSData;
455
    nsAutoPtr<gfxUserFontData> mUserFontData;
529
    nsAutoPtr<gfxUserFontData> mUserFontData;
456
    nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
530
    nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
457
    // list of gfxFonts that are using SVG glyphs
531
    // list of gfxFonts that are using SVG glyphs
458
    nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
532
    nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
533
    nsAutoPtr<gfxMathTable> mMathTable;
459
    nsTArray<gfxFontFeature> mFeatureSettings;
534
    nsTArray<gfxFontFeature> mFeatureSettings;
460
    uint32_t         mLanguageOverride;
535
    uint32_t         mLanguageOverride;
461
536
462
protected:
537
protected:
463
    friend class gfxPlatformFontList;
538
    friend class gfxPlatformFontList;
464
    friend class gfxMacPlatformFontList;
539
    friend class gfxMacPlatformFontList;
465
    friend class gfxUserFcFontEntry;
540
    friend class gfxUserFcFontEntry;
466
    friend class gfxFontFamily;
541
    friend class gfxFontFamily;
(-)a/gfx/thebes/gfxMathTable.cpp (+455 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 MathGlyphInfo header.
51
  const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo();
52
  start = reinterpret_cast<const char*>(mathglyphinfo);
53
  if (!ValidStructure(start, sizeof(MathGlyphInfo))) {
54
    return false;
55
  }
56
57
  // Verify the MathVariants header.
58
  const MathVariants* mathvariants = GetMathVariants();
59
  start = reinterpret_cast<const char*>(mathvariants);
60
  if (!ValidStructure(start, sizeof(MathVariants)) ||
61
      !ValidStructure(start,
62
                      sizeof(MathVariants) + sizeof(Offset) *
63
                      (uint16_t(mathvariants->mVertGlyphCount) +
64
                       uint16_t(mathvariants->mHorizGlyphCount))) ||
65
      !ValidOffset(start, uint16_t(mathvariants->mVertGlyphCoverage)) ||
66
      !ValidOffset(start, uint16_t(mathvariants->mHorizGlyphCoverage))) {
67
    return false;
68
  }
69
70
  return true;
71
}
72
73
uint16_t
74
gfxMathTable::GetMathConstant(gfxFontEntry::MathConstant aConstant)
75
{
76
  const MathConstants* mathconstants = GetMathConstants();
77
78
  if (aConstant <= gfxFontEntry::DisplayOperatorMinHeight) {
79
    return uint16_t(mathconstants->mSingleValues[aConstant]);
80
  }
81
82
  if (aConstant <= gfxFontEntry::RadicalKernAfterDegree) {
83
    return uint16_t(mathconstants->
84
                    mMathValues[aConstant - gfxFontEntry::MathLeading].mValue);
85
  }
86
87
  return uint16_t(mathconstants->mRadicalDegreeBottomRaisePercent);
88
}
89
90
bool
91
gfxMathTable::GetMathItalicCorrection(uint32_t aGlyphID,
92
                                      uint16_t* aItalicCorrection)
93
{
94
  const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo();
95
96
  // Get the offset of the italic correction and verify whether it is valid.
97
  const char* start = reinterpret_cast<const char*>(mathglyphinfo);
98
  uint16_t offset = mathglyphinfo->mMathItalicsCorrectionInfo;
99
  if (offset == 0 || !ValidOffset(start, offset)) {
100
    return false;
101
  }
102
  start += offset;
103
104
  // Verify the validy of the MathItalicsCorrectionInfo and retrieve it.
105
  if (!ValidStructure(start, sizeof(MathItalicsCorrectionInfo))) {
106
    return false;
107
  }
108
  const MathItalicsCorrectionInfo* italicsCorrectionInfo =
109
    reinterpret_cast<const MathItalicsCorrectionInfo*>(start);
110
  
111
  // Get the coverage index for the glyph.
112
  offset = italicsCorrectionInfo->mCoverage;
113
  const Coverage* coverage =
114
    reinterpret_cast<const Coverage*>(start + offset);
115
  int32_t i = GetCoverageIndex(coverage, aGlyphID);
116
117
  // Get the ItalicsCorrection.
118
  uint16_t count = italicsCorrectionInfo->mItalicsCorrectionCount;
119
  if (i < 0 || i >= count) {
120
    return false;
121
  }
122
  start = reinterpret_cast<const char*>(italicsCorrectionInfo + 1);
123
  if (!ValidStructure(start, count * sizeof(MathValueRecord))) {
124
    return false;
125
  }
126
  const MathValueRecord* mathValueRecordArray =
127
    reinterpret_cast<const MathValueRecord*>(start);
128
129
  *aItalicCorrection = uint16_t(mathValueRecordArray[i].mValue);
130
  return true;
131
}
132
133
uint32_t
134
gfxMathTable::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
135
                                  uint16_t aSize)
136
{
137
  // Select the glyph construction.
138
  SelectGlyphConstruction(aGlyphID, aVertical);
139
  if (!mGlyphConstruction) {
140
    return 0;
141
  }
142
143
  // Verify the validity of the array of the MathGlyphVariantRecord's and
144
  // whether there is a variant of the requested size.
145
  uint16_t count = mGlyphConstruction->mVariantCount;
146
  const char* start = reinterpret_cast<const char*>(mGlyphConstruction + 1);
147
  if (aSize >= count ||
148
      !ValidStructure(start, count * sizeof(MathGlyphVariantRecord))) {
149
    return 0;
150
  }
151
152
  // Return the glyph index of the requested size variant.
153
  const MathGlyphVariantRecord* recordArray =
154
    reinterpret_cast<const MathGlyphVariantRecord*>(start);
155
  return uint32_t(recordArray[aSize].mVariantGlyph);
156
}
157
158
bool
159
gfxMathTable::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
160
                                   uint32_t* aGlyphs)
161
{
162
  // Get the glyph assembly corresponding to that (aGlyphID, aVertical) pair.
163
  const GlyphAssembly* glyphAssembly = GetGlyphAssembly(aGlyphID, aVertical);
164
  if (!glyphAssembly) {
165
    return false;
166
  }
167
168
  // Verify the validity of the array of GlyphPartRecord's and retrieve it.
169
  uint16_t count = glyphAssembly->mPartCount;
170
  const char* start = reinterpret_cast<const char*>(glyphAssembly + 1);
171
  if (!ValidStructure(start, count * sizeof(GlyphPartRecord))) {
172
    return false;
173
  }
174
  const GlyphPartRecord* recordArray =
175
    reinterpret_cast<const GlyphPartRecord*>(start);
176
177
  // XXXfredw The structure of the Open Type Math table is a bit more general
178
  // than the one currently used by the nsMathMLChar code, so we try to fallback
179
  // in reasonable way. We use the approach of the copyComponents function in
180
  // github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py 
181
  //
182
  // The nsMathMLChar code can use at most 3 non extender pieces (aGlyphs[0],
183
  // aGlyphs[1] and aGlyphs[2]) and the extenders between these pieces should
184
  // all be the same (aGlyphs[4]). Also, the parts of vertical assembly are
185
  // stored from bottom to top in the Open Type MATH table while they are
186
  // stored from top to bottom in nsMathMLChar.
187
  //
188
189
  // Count the number of non extender pieces
190
  uint16_t nonExtenderCount = 0;
191
  for (uint16_t i = 0; i < count; i++) {
192
    if (!(uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER)) {
193
      nonExtenderCount++;
194
    }
195
  }
196
  if (nonExtenderCount > 3) {
197
    // Not supported: too many pieces
198
    return false;
199
  }
200
201
  // Now browse the list of pieces
202
203
  // 0 = look for a left/bottom glyph
204
  // 1 = look for an extender between left/bottom and mid
205
  // 2 = look for a middle glyph
206
  // 3 = look for an extender between middle and right/top
207
  // 4 = look for a right/top glyph
208
  // 5 = no more piece expected
209
  uint8_t state = 0;
210
211
  // First extender char found.
212
  uint32_t extenderChar = 0;
213
214
  // Clear the aGlyphs table.
215
  aGlyphs[0] = aGlyphs[1] = aGlyphs[2] = aGlyphs[3] = 0;
216
217
  for (uint16_t i = 0; i < count; i++) {
218
219
    bool isExtender = uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER;
220
    uint32_t glyph = recordArray[i].mGlyph;
221
222
    if ((state == 1 || state == 2) && nonExtenderCount < 3) {
223
      // do not try to find a middle glyph
224
      state += 2;
225
    }
226
227
    if (isExtender) {
228
      if (!extenderChar) {
229
        extenderChar = glyph;
230
        aGlyphs[3] = extenderChar;
231
      } else if (extenderChar != glyph)  {
232
        // Not supported: different extenders
233
        return false;
234
      }
235
236
      if (state == 0) { // or state == 1
237
        // ignore left/bottom piece and multiple successive extenders
238
        state = 1;
239
      } else if (state == 2) { // or state == 3
240
        // ignore middle piece and multiple successive extenders
241
        state = 3;
242
      } else if (state >= 4) {
243
        // Not supported: unexpected extender
244
        return false;
245
      }
246
247
      continue;
248
    }
249
250
    if (state == 0) {
251
      // copy left/bottom part
252
      aGlyphs[mVertical ? 2 : 0] = glyph;
253
      state = 1;
254
      continue;
255
    }
256
257
    if (state == 1 || state == 2) {
258
      // copy middle part
259
      aGlyphs[1] = glyph;
260
      state = 3;
261
      continue;
262
    }
263
264
    if (state == 3 || state == 4) {
265
      // copy right/top part
266
      aGlyphs[mVertical ? 0 : 2] = glyph;
267
      state = 5;
268
    }
269
270
  }
271
272
  return true;
273
}
274
275
bool
276
gfxMathTable::ValidStructure(const char* aStart, uint16_t aSize)
277
{
278
  unsigned int mathDataLength;
279
  const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
280
  return (mathData <= aStart &&
281
          aStart + aSize <= mathData + mathDataLength);
282
}
283
284
bool
285
gfxMathTable::ValidOffset(const char* aStart, uint16_t aOffset)
286
{
287
  unsigned int mathDataLength;
288
  const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
289
  return (mathData <= aStart + aOffset &&
290
          aStart + aOffset < mathData + mathDataLength);
291
}
292
293
const MATHTableHeader*
294
gfxMathTable::GetMATHTableHeader()
295
{
296
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
297
  return reinterpret_cast<const MATHTableHeader*>(mathData);
298
}
299
300
const MathConstants*
301
gfxMathTable::GetMathConstants()
302
{
303
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
304
  return
305
    reinterpret_cast<const MathConstants*>(mathData +
306
                                           uint16_t(GetMATHTableHeader()->
307
                                                    mMathConstants));
308
}
309
310
const MathGlyphInfo*
311
gfxMathTable::GetMathGlyphInfo()
312
{
313
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
314
  return
315
    reinterpret_cast<const MathGlyphInfo*>(mathData +
316
                                           uint16_t(GetMATHTableHeader()->
317
                                                    mMathGlyphInfo));
318
}
319
320
const MathVariants*
321
gfxMathTable::GetMathVariants()
322
{
323
  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
324
  return
325
    reinterpret_cast<const MathVariants*>(mathData +
326
                                          uint16_t(GetMATHTableHeader()->
327
                                                   mMathVariants));
328
}
329
330
const GlyphAssembly*
331
gfxMathTable::GetGlyphAssembly(uint32_t aGlyphID, bool aVertical)
332
{
333
  // Select the glyph construction.
334
  SelectGlyphConstruction(aGlyphID, aVertical);
335
  if (!mGlyphConstruction) {
336
    return nullptr;
337
  }
338
339
  // Get the offset of the glyph assembly and verify whether it is valid.
340
  const char* start = reinterpret_cast<const char*>(mGlyphConstruction);
341
  uint16_t offset = mGlyphConstruction->mGlyphAssembly;
342
  if (offset == 0 || !ValidOffset(start, offset)) {
343
    return nullptr;
344
  }
345
  start += offset;
346
347
  // Verify the validy of the GlyphAssembly and return it.
348
  if (!ValidStructure(start, sizeof(GlyphAssembly))) {
349
    return nullptr;
350
  }
351
  return reinterpret_cast<const GlyphAssembly*>(start);
352
}
353
354
int32_t
355
gfxMathTable::GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph)
356
{
357
  if (uint16_t(aCoverage->mFormat) == 1) {
358
    // Coverage Format 1: list of individual glyph indices in the glyph set.
359
    const CoverageFormat1* table =
360
      reinterpret_cast<const CoverageFormat1*>(aCoverage);
361
    uint16_t count = table->mGlyphCount;
362
    const char* start = reinterpret_cast<const char*>(table + 1);
363
    if (ValidStructure(start, count * sizeof(GlyphID))) {
364
      const GlyphID* glyphArray =
365
        reinterpret_cast<const GlyphID*>(start);
366
      uint32_t imin = 0, imax = count;
367
      while (imin < imax) {
368
        uint32_t imid = (imin + imax) >> 1;
369
        uint16_t glyphMid = glyphArray[imid];
370
        if (glyphMid == aGlyph) {
371
          return imid;
372
        }
373
        if (glyphMid < aGlyph) {
374
          imin = imid + 1;
375
        } else {
376
          imax = imid;
377
        }
378
      }
379
    }
380
  } else if (uint16_t(aCoverage->mFormat) == 2) {
381
    // Coverage Format 2: ranges of consecutive indices.
382
    const CoverageFormat2* table =
383
      reinterpret_cast<const CoverageFormat2*>(aCoverage);
384
    uint16_t count = table->mRangeCount;
385
    const char* start = reinterpret_cast<const char*>(table + 1);
386
    if (ValidStructure(start, count * sizeof(RangeRecord))) {
387
      const RangeRecord* rangeArray =
388
        reinterpret_cast<const RangeRecord*>(start);
389
      uint32_t imin = 0, imax = count;
390
      while (imin < imax) {
391
        uint32_t imid = (imin + imax) >> 1;
392
        uint16_t rStart = rangeArray[imid].mStart;
393
        uint16_t rEnd = rangeArray[imid].mEnd;
394
        if (rEnd < aGlyph) {
395
          imin = imid + 1;
396
        } else if (aGlyph < rStart) {
397
          imax = imid;
398
        } else {
399
          return (uint16_t(rangeArray[imid].mStartCoverageIndex) +
400
                  aGlyph - rStart);
401
        }
402
      }
403
    }
404
  }
405
  return -1;
406
}
407
408
void
409
gfxMathTable::SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical)
410
{
411
  if (mGlyphID == aGlyphID && mVertical == aVertical) {
412
    // The (glyph, direction) pair is already selected: nothing to do.
413
    return;
414
  }
415
416
  // Update our cached values.
417
  mVertical = aVertical;
418
  mGlyphID = aGlyphID;
419
  mGlyphConstruction = nullptr;
420
421
  // Get the coverage index for the new values.
422
  const MathVariants* mathvariants = GetMathVariants();
423
  const char* start = reinterpret_cast<const char*>(mathvariants);
424
  uint16_t offset = (aVertical ?
425
                     mathvariants->mVertGlyphCoverage :
426
                     mathvariants->mHorizGlyphCoverage);
427
  const Coverage* coverage =
428
    reinterpret_cast<const Coverage*>(start + offset);
429
  int32_t i = GetCoverageIndex(coverage, aGlyphID);
430
431
  // Get the offset to the glyph construction.
432
  uint16_t count = (aVertical ?
433
                    mathvariants->mVertGlyphCount :
434
                    mathvariants->mHorizGlyphCount);
435
  start = reinterpret_cast<const char*>(mathvariants + 1);
436
  if (i < 0 || i >= count) {
437
    return;
438
  }
439
  if (!aVertical) {
440
    start += uint16_t(mathvariants->mVertGlyphCount) * sizeof(Offset);
441
  }
442
  if (!ValidStructure(start, count * sizeof(Offset))) {
443
    return;
444
  }
445
  const Offset* offsetArray = reinterpret_cast<const Offset*>(start);
446
  offset = uint16_t(offsetArray[i]);
447
448
  // Make mGlyphConstruction point to the desired glyph construction.
449
  start = reinterpret_cast<const char*>(mathvariants);
450
  if (!ValidOffset(start, offset)) {
451
    return;
452
  }
453
  mGlyphConstruction =
454
    reinterpret_cast<const MathGlyphConstruction*>(start + offset);
455
}
(-)a/gfx/thebes/gfxMathTable.h (+115 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 MathGlyphInfo;
17
struct MathVariants;
18
19
/**
20
 * Used by |gfxFontEntry| to represent the MATH table of an OpenType font.
21
 * Each |gfxFontEntry| owns at most one |gfxMathTable| instance.
22
 */
23
class gfxMathTable
24
{
25
public:
26
    /**
27
     * @param aMathTable The MATH table from the OpenType font
28
     *
29
     * The gfxMathTable object takes over ownership of the blob references
30
     * that are passed in, and will hb_blob_destroy() them when finished;
31
     * the caller should -not- destroy these references.
32
     */
33
    gfxMathTable(hb_blob_t* aMathTable);
34
35
    /**
36
     * Releases our references to the Math table and cleans up everything else.
37
     */
38
    ~gfxMathTable();
39
40
    /**
41
     * Returns the value of the specified constant from the MATH table.
42
     */
43
    uint16_t GetMathConstant(gfxFontEntry::MathConstant aConstant);
44
45
    /**
46
     *  If the MATH table contains an italic correction for that glyph, this
47
     *  function gets the value and returns true. Otherwise it returns false.
48
     */
49
    bool
50
    GetMathItalicCorrection(uint32_t aGlyphID, uint16_t* aItalicCorrection);
51
52
    /**
53
     * @param aGlyphID  glyph index of the character we want to stretch
54
     * @param aVertical direction of the stretching (vertical/horizontal)
55
     * @param aSize     the desired size variant
56
     *
57
     * Returns the glyph index of the desired size variant or 0 if there is not
58
     * any such size variant.
59
     */
60
    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
61
                                 uint16_t aSize);
62
63
    /**
64
     * @param aGlyphID  glyph index of the character we want to stretch
65
     * @param aVertical direction of the stretching (vertical/horizontal)
66
     * @param aGlyphs   pre-allocated buffer of 4 elements where the glyph
67
     * indexes (or 0 for absent parts) will be stored. The parts are stored in
68
     * the order expected by the nsMathMLChar: Top (or Left), Middle, Bottom
69
     * (or Right), Glue.
70
     *
71
     * Tries to fill-in aGlyphs with the relevant glyph indexes and returns
72
     * whether the operation was successful. The function returns false if
73
     * there is not any assembly for the character we want to stretch or if
74
     * the format is not supported by the nsMathMLChar code.
75
     *
76
     */
77
    bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
78
                              uint32_t* aGlyphs);
79
80
protected:
81
    friend class gfxFontEntry;
82
    // This allows gfxFontEntry to verify the validity of the main headers
83
    // before starting to use the MATH table.
84
    bool HasValidHeaders();
85
86
private:
87
    // HarfBuzz blob where the MATH table is stored.
88
    hb_blob_t*    mMathTable;
89
90
    // Cached values for the latest (mGlyphID, mVertical) pair that has been
91
    // accessed and the corresponding glyph construction. These are verified
92
    // by SelectGlyphConstruction and updated if necessary.
93
    const MathGlyphConstruction* mGlyphConstruction;
94
    uint32_t mGlyphID;
95
    bool     mVertical;
96
    void     SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical);
97
98
    // Access to some structures of the MATH table.
99
    const MATHTableHeader* GetMATHTableHeader();
100
    const MathConstants*   GetMathConstants();
101
    const MathGlyphInfo*   GetMathGlyphInfo();
102
    const MathVariants*    GetMathVariants();
103
    const GlyphAssembly*   GetGlyphAssembly(uint32_t aGlyphID, bool aVertical);
104
105
    // Verify whether a structure or an offset belongs to the math data and can
106
    // be read safely.
107
    bool ValidStructure(const char* aStructStart, uint16_t aStructSize);
108
    bool ValidOffset(const char* aOffsetStart, uint16_t aOffset);
109
110
    // Get the coverage index of a glyph index from an Open Type coverage table
111
    // or -1 if the glyph index is not found.
112
    int32_t GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph);
113
};
114
115
#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 245-260   UNIFIED_SOURCES += [ Link Here 
245
    'gfxContext.cpp',
246
    'gfxContext.cpp',
246
    'gfxFontFeatures.cpp',
247
    'gfxFontFeatures.cpp',
247
    'gfxFontMissingGlyphs.cpp',
248
    'gfxFontMissingGlyphs.cpp',
248
    'gfxFontTest.cpp',
249
    'gfxFontTest.cpp',
249
    'gfxGradientCache.cpp',
250
    'gfxGradientCache.cpp',
250
    'gfxGraphiteShaper.cpp',
251
    'gfxGraphiteShaper.cpp',
251
    'gfxHarfBuzzShaper.cpp',
252
    'gfxHarfBuzzShaper.cpp',
252
    'gfxImageSurface.cpp',
253
    'gfxImageSurface.cpp',
254
    'gfxMathTable.cpp',
253
    'gfxMatrix.cpp',
255
    'gfxMatrix.cpp',
254
    'gfxPath.cpp',
256
    'gfxPath.cpp',
255
    'gfxPattern.cpp',
257
    'gfxPattern.cpp',
256
    'gfxRect.cpp',
258
    'gfxRect.cpp',
257
    'gfxReusableImageSurfaceWrapper.cpp',
259
    'gfxReusableImageSurfaceWrapper.cpp',
258
    'gfxReusableSharedImageSurfaceWrapper.cpp',
260
    'gfxReusableSharedImageSurfaceWrapper.cpp',
259
    'gfxScriptItemizer.cpp',
261
    'gfxScriptItemizer.cpp',
260
    'gfxSkipChars.cpp',
262
    'gfxSkipChars.cpp',

Return to bug 407059