Skip to content
Permalink
Browse files
Operator stretching: read the Open Type MATH table
https://bugs.webkit.org/show_bug.cgi?id=130324

Reviewed by Chris Fleizach.

Source/WebCore:

We parse and expose some data from the OpenType MATH table that will be
be relevant for at least the MathML operator stretching (bug 130322):
math constants, italic corrections and size variants / glyph assembly.
This will be tested when the MathML code uses the data.

* WebCore.xcodeproj/project.pbxproj: Add OpenTypeTypes.h to the Mac build.
* platform/graphics/opentype/OpenTypeMathData.cpp: We implement the low-level parsing of the MATH table.
(WebCore::OpenType::MathItalicsCorrectionInfo::getItalicCorrection):
(WebCore::OpenType::MathGlyphInfo::mathItalicsCorrectionInfo):
(WebCore::OpenType::GlyphAssembly::getAssemblyParts):
(WebCore::OpenType::MathGlyphConstruction::getSizeVariants):
(WebCore::OpenType::MathGlyphConstruction::getAssemblyParts):
(WebCore::OpenType::MathVariants::mathGlyphConstruction):
(WebCore::OpenType::MATHTable::mathConstants):
(WebCore::OpenType::MATHTable::mathGlyphInfo):
(WebCore::OpenType::MATHTable::mathVariants):
(WebCore::OpenTypeMathData::OpenTypeMathData): We load the MATH table.
(WebCore::OpenTypeMathData::getMathConstant): We add a function to get values from the MathConstant subtable.
(WebCore::OpenTypeMathData::getItalicCorrection): We add a function to get italic correction from the MathGlyphInfo subtable.
(WebCore::OpenTypeMathData::getMathVariants): We add a function to get size variants / glyph assembly from the MathVariants subtable.
* platform/graphics/opentype/OpenTypeMathData.h: We expose three new functions to get math data.
* platform/graphics/opentype/OpenTypeTypes.h: We share the coverage tables that are common to vertical and math data.
(WebCore::OpenType::TableWithCoverage::getCoverageIndex): We add a function to get the coverage index from a given glyph.
* platform/graphics/opentype/OpenTypeVerticalData.cpp: We move the coverage tables to OpenTypeTypes.h.

Source/WTF:

* wtf/Platform.h: enable OPENTYPE_MATH on platforms that can read OpenType tables.

Canonical link: https://commits.webkit.org/149144@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@166640 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
fred-wang committed Apr 2, 2014
1 parent edc4788 commit 8201c4f3a985f1c0471c26566b09abd42984961e
Showing 8 changed files with 491 additions and 20 deletions.
@@ -1,3 +1,12 @@
2014-04-02 Frédéric Wang <fred.wang@free.fr>

Operator stretching: read the Open Type MATH table
https://bugs.webkit.org/show_bug.cgi?id=130324

Reviewed by Chris Fleizach.

* wtf/Platform.h: enable OPENTYPE_MATH on platforms that can read OpenType tables.

2014-04-02 Alex Christensen <achristensen@webkit.org>

[WinCairo] Build fix with GMainLoopSource.
@@ -1054,4 +1054,9 @@
#define WTF_USE_ASYNC_NSTEXTINPUTCLIENT 1
#endif

#if (OS(DARWIN) && USE(CG)) || USE(FREETYPE) || (PLATFORM(WIN) && (USE(CG) || USE(CAIRO)))
#undef ENABLE_OPENTYPE_MATH
#define ENABLE_OPENTYPE_MATH 1
#endif

#endif /* WTF_Platform_h */
@@ -1,3 +1,35 @@
2014-04-02 Frédéric Wang <fred.wang@free.fr>

Operator stretching: read the Open Type MATH table
https://bugs.webkit.org/show_bug.cgi?id=130324

Reviewed by Chris Fleizach.

We parse and expose some data from the OpenType MATH table that will be
be relevant for at least the MathML operator stretching (bug 130322):
math constants, italic corrections and size variants / glyph assembly.
This will be tested when the MathML code uses the data.

* WebCore.xcodeproj/project.pbxproj: Add OpenTypeTypes.h to the Mac build.
* platform/graphics/opentype/OpenTypeMathData.cpp: We implement the low-level parsing of the MATH table.
(WebCore::OpenType::MathItalicsCorrectionInfo::getItalicCorrection):
(WebCore::OpenType::MathGlyphInfo::mathItalicsCorrectionInfo):
(WebCore::OpenType::GlyphAssembly::getAssemblyParts):
(WebCore::OpenType::MathGlyphConstruction::getSizeVariants):
(WebCore::OpenType::MathGlyphConstruction::getAssemblyParts):
(WebCore::OpenType::MathVariants::mathGlyphConstruction):
(WebCore::OpenType::MATHTable::mathConstants):
(WebCore::OpenType::MATHTable::mathGlyphInfo):
(WebCore::OpenType::MATHTable::mathVariants):
(WebCore::OpenTypeMathData::OpenTypeMathData): We load the MATH table.
(WebCore::OpenTypeMathData::getMathConstant): We add a function to get values from the MathConstant subtable.
(WebCore::OpenTypeMathData::getItalicCorrection): We add a function to get italic correction from the MathGlyphInfo subtable.
(WebCore::OpenTypeMathData::getMathVariants): We add a function to get size variants / glyph assembly from the MathVariants subtable.
* platform/graphics/opentype/OpenTypeMathData.h: We expose three new functions to get math data.
* platform/graphics/opentype/OpenTypeTypes.h: We share the coverage tables that are common to vertical and math data.
(WebCore::OpenType::TableWithCoverage::getCoverageIndex): We add a function to get the coverage index from a given glyph.
* platform/graphics/opentype/OpenTypeVerticalData.cpp: We move the coverage tables to OpenTypeTypes.h.

2014-04-02 Ion Rosca <rosca@adobe.com>

[CSS Blending] Compositing requirements for blending are not computed correctly
@@ -4596,6 +4596,7 @@
B2C3DA650D006CD600EF6F26 /* SimpleFontData.h in Headers */ = {isa = PBXBuildFile; fileRef = B2C3DA540D006CD600EF6F26 /* SimpleFontData.h */; settings = {ATTRIBUTES = (Private, ); }; };
B2D3DA640D006CD600EF6F27 /* OpenTypeMathData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2D3DA530D006CD600EF6F27 /* OpenTypeMathData.cpp */; };
B2D3DA650D006CD600EF6F27 /* OpenTypeMathData.h in Headers */ = {isa = PBXBuildFile; fileRef = B2D3DA540D006CD600EF6F27 /* OpenTypeMathData.h */; settings = {ATTRIBUTES = (Private, ); }; };
B2D3EA650D006CD600EF6F28 /* OpenTypeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = B2D3EA540D006CD600EF6F28 /* OpenTypeTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
B2C3DA660D006CD600EF6F26 /* FontDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = B2C3DA550D006CD600EF6F26 /* FontDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
B2C3DA670D006CD600EF6F26 /* FontGlyphs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2C3DA560D006CD600EF6F26 /* FontGlyphs.cpp */; };
B2C3DA680D006CD600EF6F26 /* FontGlyphs.h in Headers */ = {isa = PBXBuildFile; fileRef = B2C3DA570D006CD600EF6F26 /* FontGlyphs.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -11852,6 +11853,7 @@
B2C3DA540D006CD600EF6F26 /* SimpleFontData.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SimpleFontData.h; sourceTree = "<group>"; };
B2D3DA530D006CD600EF6F27 /* OpenTypeMathData.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = opentype/OpenTypeMathData.cpp; sourceTree = "<group>"; };
B2D3DA540D006CD600EF6F27 /* OpenTypeMathData.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = opentype/OpenTypeMathData.h; sourceTree = "<group>"; };
B2D3EA540D006CD600EF6F28 /* OpenTypeTypes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = opentype/OpenTypeTypes.h; sourceTree = "<group>"; };
B2C3DA550D006CD600EF6F26 /* FontDescription.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FontDescription.h; sourceTree = "<group>"; };
B2C3DA560D006CD600EF6F26 /* FontGlyphs.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FontGlyphs.cpp; sourceTree = "<group>"; };
B2C3DA570D006CD600EF6F26 /* FontGlyphs.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FontGlyphs.h; sourceTree = "<group>"; };
@@ -20146,6 +20148,7 @@
B2C3DA540D006CD600EF6F26 /* SimpleFontData.h */,
B2D3DA530D006CD600EF6F27 /* OpenTypeMathData.cpp */,
B2D3DA540D006CD600EF6F27 /* OpenTypeMathData.h */,
B2D3EA540D006CD600EF6F28 /* OpenTypeTypes.h */,
CD641EB21818F5ED00EE4C41 /* SourceBufferPrivate.h */,
CDC61DA0180867D8004B913F /* SourceBufferPrivate.h */,
CDC8B5AC1804AE5D0016E685 /* SourceBufferPrivateClient.h */,
@@ -25494,6 +25497,7 @@
41D168EE10226E89009BC827 /* SharedWorkerThread.h in Headers */,
B2C3DA650D006CD600EF6F26 /* SimpleFontData.h in Headers */,
B2D3DA650D006CD600EF6F27 /* OpenTypeMathData.h in Headers */,
B2D3EA650D006CD600EF6F28 /* OpenTypeTypes.h in Headers */,
E48944A3180B57D800F165D8 /* SimpleLineLayout.h in Headers */,
E4E9B11D1814569C003ACCDF /* SimpleLineLayoutFunctions.h in Headers */,
E4E9B1191810916F003ACCDF /* SimpleLineLayoutResolver.h in Headers */,
@@ -27,15 +27,300 @@
#include "OpenTypeMathData.h"

#include "FontPlatformData.h"
#if ENABLE(OPENTYPE_MATH)
#include "OpenTypeTypes.h"
#endif
#include "SimpleFontData.h"

using namespace std;

namespace WebCore {

OpenTypeMathData::OpenTypeMathData(const FontPlatformData&)
#if ENABLE(OPENTYPE_MATH)
namespace OpenType {

const uint32_t MATHTag = OT_MAKE_TAG('M', 'A', 'T', 'H');

#pragma pack(1)

struct MathValueRecord {
OpenType::Int16 value;
OpenType::Offset deviceTableOffset;
};

struct MathConstants {
OpenType::Int16 intConstants[OpenTypeMathData::ScriptScriptPercentScaleDown - OpenTypeMathData::ScriptPercentScaleDown + 1];
OpenType::UInt16 uIntConstants[OpenTypeMathData::DisplayOperatorMinHeight - OpenTypeMathData::DelimitedSubFormulaMinHeight + 1];
OpenType::MathValueRecord mathValuesConstants[OpenTypeMathData::RadicalKernAfterDegree - OpenTypeMathData::MathLeading + 1];
OpenType::UInt16 radicalDegreeBottomRaisePercent;
};

struct MathItalicsCorrectionInfo : TableWithCoverage {
OpenType::Offset coverageOffset;
OpenType::UInt16 italicsCorrectionCount;
OpenType::MathValueRecord italicsCorrection[1]; // There are italicsCorrectionCount italic correction values.

int16_t getItalicCorrection(const SharedBuffer& buffer, Glyph glyph) const
{
uint16_t count = uint16_t(italicsCorrectionCount);
if (!isValidEnd(buffer, &italicsCorrection[count]))
return 0;

uint16_t offset = coverageOffset;
if (!offset)
return 0;
const CoverageTable* coverage = validateOffset<CoverageTable>(buffer, offset);
if (!coverage)
return 0;

// We determine the index in the italicsCorrection table.
uint32_t i;
if (!getCoverageIndex(buffer, coverage, glyph, i) || i >= count)
return 0;

return int16_t(italicsCorrection[i].value);
}
};

struct MathGlyphInfo : TableWithCoverage {
OpenType::Offset mathItalicsCorrectionInfoOffset;
OpenType::Offset mathTopAccentAttachmentOffset;
OpenType::Offset extendedShapeCoverageOffset;
OpenType::Offset mathKernInfoOffset;

const MathItalicsCorrectionInfo* mathItalicsCorrectionInfo(const SharedBuffer& buffer) const
{
uint16_t offset = mathItalicsCorrectionInfoOffset;
if (offset)
return validateOffset<MathItalicsCorrectionInfo>(buffer, offset);
return nullptr;
}
};

struct GlyphAssembly : TableBase {
OpenType::MathValueRecord italicsCorrection;
OpenType::UInt16 partCount;
struct GlyphPartRecord {
OpenType::GlyphID glyph;
OpenType::UInt16 startConnectorLength;
OpenType::UInt16 endConnectorLength;
OpenType::UInt16 fullAdvance;
OpenType::UInt16 partFlags;
} partRecords[1]; // There are partCount GlyphPartRecord's.

// PartFlags enumeration currently uses only one bit:
// 0x0001 If set, the part can be skipped or repeated.
// 0xFFFE Reserved.
enum {
PartFlagsExtender = 0x01
};

void getAssemblyParts(const SharedBuffer& buffer, Vector<OpenTypeMathData::AssemblyPart>& assemblyParts) const
{
uint16_t count = partCount;
if (!isValidEnd(buffer, &partRecords[count]))
return;
assemblyParts.resize(count);
for (uint16_t i = 0; i < count; i++) {
assemblyParts[i].glyph = partRecords[i].glyph;
uint16_t flag = partRecords[i].partFlags;
assemblyParts[i].isExtender = flag & PartFlagsExtender;
}
}

};

struct MathGlyphConstruction : TableBase {
OpenType::Offset glyphAssemblyOffset;
OpenType::UInt16 variantCount;
struct MathGlyphVariantRecord {
OpenType::GlyphID variantGlyph;
OpenType::UInt16 advanceMeasurement;
} mathGlyphVariantRecords[1]; // There are variantCount MathGlyphVariantRecord's.

void getSizeVariants(const SharedBuffer& buffer, Vector<Glyph>& variants) const
{
uint16_t count = variantCount;
if (!isValidEnd(buffer, &mathGlyphVariantRecords[count]))
return;
variants.resize(count);
for (uint16_t i = 0; i < count; i++)
variants[i] = mathGlyphVariantRecords[i].variantGlyph;
}

void getAssemblyParts(const SharedBuffer& buffer, Vector<OpenTypeMathData::AssemblyPart>& assemblyParts) const
{
uint16_t offset = glyphAssemblyOffset;
const GlyphAssembly* glyphAssembly = validateOffset<GlyphAssembly>(buffer, offset);
if (glyphAssembly)
glyphAssembly->getAssemblyParts(buffer, assemblyParts);
}
};

struct MathVariants : TableWithCoverage {
OpenType::UInt16 minConnectorOverlap;
OpenType::Offset verticalGlyphCoverageOffset;
OpenType::Offset horizontalGlyphCoverageOffset;
OpenType::UInt16 verticalGlyphCount;
OpenType::UInt16 horizontalGlyphCount;
OpenType::Offset mathGlyphConstructionsOffset[1]; // There are verticalGlyphCount vertical glyph contructions and horizontalGlyphCount vertical glyph contructions.

const MathGlyphConstruction* mathGlyphConstruction(const SharedBuffer& buffer, Glyph glyph, bool isVertical) const
{
uint32_t count = uint16_t(verticalGlyphCount) + uint16_t(horizontalGlyphCount);
if (!isValidEnd(buffer, &mathGlyphConstructionsOffset[count]))
return nullptr;

// We determine the coverage table for the specified glyph.
uint16_t coverageOffset = isVertical ? verticalGlyphCoverageOffset : horizontalGlyphCoverageOffset;
if (!coverageOffset)
return nullptr;
const CoverageTable* coverage = validateOffset<CoverageTable>(buffer, coverageOffset);
if (!coverage)
return nullptr;

// We determine the index in the mathGlyphConstructionsOffset table.
uint32_t i;
if (!getCoverageIndex(buffer, coverage, glyph, i))
return nullptr;
count = isVertical ? verticalGlyphCount : horizontalGlyphCount;
if (i >= count)
return nullptr;
if (!isVertical)
i += uint16_t(verticalGlyphCount);

return validateOffset<MathGlyphConstruction>(buffer, mathGlyphConstructionsOffset[i]);
}
};

struct MATHTable : TableBase {
OpenType::Fixed version;
OpenType::Offset mathConstantsOffset;
OpenType::Offset mathGlyphInfoOffset;
OpenType::Offset mathVariantsOffset;

const MathConstants* mathConstants(const SharedBuffer& buffer) const
{
uint16_t offset = mathConstantsOffset;
if (offset)
return validateOffset<MathConstants>(buffer, offset);
return nullptr;
}

const MathGlyphInfo* mathGlyphInfo(const SharedBuffer& buffer) const
{
uint16_t offset = mathGlyphInfoOffset;
if (offset)
return validateOffset<MathGlyphInfo>(buffer, offset);
return nullptr;
}

const MathVariants* mathVariants(const SharedBuffer& buffer) const
{
uint16_t offset = mathVariantsOffset;
if (offset)
return validateOffset<MathVariants>(buffer, offset);
return nullptr;
}
};

#pragma pack()

} // namespace OpenType
#endif // ENABLE(OPENTYPE_MATH)

OpenTypeMathData::OpenTypeMathData(const FontPlatformData& fontData)
{
// FIXME: We should read the data from the MATH table (https://bugs.webkit.org/show_bug.cgi?id=130324).
#if ENABLE(OPENTYPE_MATH)
m_mathBuffer = fontData.openTypeTable(OpenType::MATHTag);
const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
if (!math) {
m_mathBuffer = nullptr;
return;
}

const OpenType::MathConstants* mathConstants = math->mathConstants(*m_mathBuffer);
if (!mathConstants) {
m_mathBuffer = nullptr;
return;
}

const OpenType::MathVariants* mathVariants = math->mathVariants(*m_mathBuffer);
if (!mathVariants)
m_mathBuffer = nullptr;
#else
m_mathBuffer = nullptr;
#endif
}

float OpenTypeMathData::getMathConstant(const SimpleFontData* font, MathConstant constant) const
{
#if ENABLE(OPENTYPE_MATH)
int32_t value = 0;

const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
ASSERT(math);
const OpenType::MathConstants* mathConstants = math->mathConstants(*m_mathBuffer);
ASSERT(mathConstants);

if (constant >= 0 && constant <= ScriptScriptPercentScaleDown)
value = int16_t(mathConstants->intConstants[constant]);
else if (constant >= DelimitedSubFormulaMinHeight && constant <= DisplayOperatorMinHeight)
value = uint16_t(mathConstants->uIntConstants[constant - DelimitedSubFormulaMinHeight]);
else if (constant >= MathLeading && constant <= RadicalKernAfterDegree)
value = int16_t(mathConstants->mathValuesConstants[constant - MathLeading].value);
else if (constant == RadicalDegreeBottomRaisePercent)
value = uint16_t(mathConstants->radicalDegreeBottomRaisePercent);

if (constant == ScriptPercentScaleDown || constant == ScriptScriptPercentScaleDown || constant == RadicalDegreeBottomRaisePercent)
return value / 100.0;

return value * font->sizePerUnit();
#else
ASSERT_NOT_REACHED();
return 0;
#endif
}

float OpenTypeMathData::getItalicCorrection(const SimpleFontData* font, Glyph glyph) const
{
#if ENABLE(OPENTYPE_MATH)
const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
ASSERT(math);
const OpenType::MathGlyphInfo* mathGlyphInfo = math->mathGlyphInfo(*m_mathBuffer);
if (!mathGlyphInfo)
return 0;

const OpenType::MathItalicsCorrectionInfo* mathItalicsCorrectionInfo = mathGlyphInfo->mathItalicsCorrectionInfo(*m_mathBuffer);
if (!mathItalicsCorrectionInfo)
return 0;

return mathItalicsCorrectionInfo->getItalicCorrection(*m_mathBuffer, glyph) * font->sizePerUnit();
#else
ASSERT_NOT_REACHED();
return 0;
#endif
}

void OpenTypeMathData::getMathVariants(Glyph glyph, bool isVertical, Vector<Glyph>& sizeVariants, Vector<AssemblyPart>& assemblyParts) const
{
sizeVariants.clear();
assemblyParts.clear();
#if ENABLE(OPENTYPE_MATH)
const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
ASSERT(math);
const OpenType::MathVariants* mathVariants = math->mathVariants(*m_mathBuffer);
ASSERT(mathVariants);

const OpenType::MathGlyphConstruction* mathGlyphConstruction = mathVariants->mathGlyphConstruction(*m_mathBuffer, glyph, isVertical);
if (!mathGlyphConstruction)
return;

mathGlyphConstruction->getSizeVariants(*m_mathBuffer, sizeVariants);
mathGlyphConstruction->getAssemblyParts(*m_mathBuffer, assemblyParts);
#else
ASSERT_NOT_REACHED();
#endif
}

} // namespace WebCore

0 comments on commit 8201c4f

Please sign in to comment.