Title: [122788] trunk/Source
Revision
122788
Author
[email protected]
Date
2012-07-16 17:57:46 -0700 (Mon, 16 Jul 2012)

Log Message

Vertical alternate glyph (GSUB) support for OpenTypeVerticalData
https://bugs.webkit.org/show_bug.cgi?id=81389

Patch by Koji Ishii <[email protected]> on 2012-07-16
Reviewed by Tony Chang.

Source/WebCore:

This patch adds support for reading 'GSUB' OpenType table to get
vertical alternate glyphs.
http://www.microsoft.com/typography/otspec/gsub.htm

Like bug 81326, this code isn't on any code path yet.

Tests: WebKit/chromium/tests/OpenTypeVerticalDataTest.cpp

* platform/graphics/opentype/OpenTypeTypes.h:
(WebCore::OpenType::validateTable): Moved from OpenTypeVerticalData.cpp for unit tests.
(OpenType):
(TableBase): Ditto.
(WebCore::OpenType::TableBase::isValidEnd):
(WebCore::OpenType::TableBase::validatePtr):
(WebCore::OpenType::TableBase::validateOffset):
* platform/graphics/opentype/OpenTypeVerticalData.cpp:
(OpenType): Added several OpenType tables used by 'GSUB' table.
(CoverageTable):
(Coverage1Table):
(Coverage2Table):
(RangeRecord):
(SubstitutionSubTable):
(WebCore::OpenType::SubstitutionSubTable::coverage):
(SingleSubstitution2SubTable):
(LookupTable):
(WebCore::OpenType::LookupTable::getSubstitutions):
(LookupList):
(WebCore::OpenType::LookupList::lookup):
(FeatureTable):
(WebCore::OpenType::FeatureTable::getGlyphSubstitutions):
(FeatureList):
(FeatureRecord):
(WebCore::OpenType::FeatureList::feature):
(LangSysTable):
(WebCore::OpenType::LangSysTable::feature):
(ScriptTable):
(LangSysRecord):
(WebCore::OpenType::ScriptTable::defaultLangSys):
(ScriptList):
(ScriptRecord):
(WebCore::OpenType::ScriptList::script):
(WebCore::OpenType::ScriptList::defaultScript):
(WebCore::OpenType::ScriptList::defaultLangSys):
(GSUBTable):
(WebCore::OpenType::GSUBTable::scriptList):
(WebCore::OpenType::GSUBTable::featureList):
(WebCore::OpenType::GSUBTable::lookupList):
(WebCore::OpenType::GSUBTable::defaultLangSys):
(WebCore::OpenType::GSUBTable::feature):
(WebCore::OpenType::GSUBTable::getVerticalGlyphSubstitutions):
(WebCore::OpenTypeVerticalData::OpenTypeVerticalData):
(WebCore::OpenTypeVerticalData::loadMetrics): Split code to load metrics from ctor.
(WebCore::OpenTypeVerticalData::loadVerticalGlyphSubstitutions): Load the vertical alternate Glyph substitution table.
(WebCore):
(WebCore::OpenTypeVerticalData::substituteWithVerticalGlyphs): Substitute Glyph IDs with vertical alternate Glyph IDs.
* platform/graphics/opentype/OpenTypeVerticalData.h:
(OpenTypeVerticalData): Added m_verticalGlyphMap.

Source/WebKit/chromium:

Tests for pointer validations for OpenType tables.

* WebKit.gypi:
* tests/OpenTypeVerticalDataTest.cpp: Added.
(WebCore):
(TestTable):
(WebCore::TestTable::validateOffset):
(WebCore::TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (122787 => 122788)


--- trunk/Source/WebCore/ChangeLog	2012-07-17 00:52:57 UTC (rev 122787)
+++ trunk/Source/WebCore/ChangeLog	2012-07-17 00:57:46 UTC (rev 122788)
@@ -1,3 +1,68 @@
+2012-07-16  Koji Ishii  <[email protected]>
+
+        Vertical alternate glyph (GSUB) support for OpenTypeVerticalData
+        https://bugs.webkit.org/show_bug.cgi?id=81389
+
+        Reviewed by Tony Chang.
+
+        This patch adds support for reading 'GSUB' OpenType table to get
+        vertical alternate glyphs.
+        http://www.microsoft.com/typography/otspec/gsub.htm
+
+        Like bug 81326, this code isn't on any code path yet.
+
+        Tests: WebKit/chromium/tests/OpenTypeVerticalDataTest.cpp
+
+        * platform/graphics/opentype/OpenTypeTypes.h:
+        (WebCore::OpenType::validateTable): Moved from OpenTypeVerticalData.cpp for unit tests.
+        (OpenType):
+        (TableBase): Ditto.
+        (WebCore::OpenType::TableBase::isValidEnd):
+        (WebCore::OpenType::TableBase::validatePtr):
+        (WebCore::OpenType::TableBase::validateOffset):
+        * platform/graphics/opentype/OpenTypeVerticalData.cpp:
+        (OpenType): Added several OpenType tables used by 'GSUB' table.
+        (CoverageTable):
+        (Coverage1Table):
+        (Coverage2Table):
+        (RangeRecord):
+        (SubstitutionSubTable):
+        (WebCore::OpenType::SubstitutionSubTable::coverage):
+        (SingleSubstitution2SubTable):
+        (LookupTable):
+        (WebCore::OpenType::LookupTable::getSubstitutions):
+        (LookupList):
+        (WebCore::OpenType::LookupList::lookup):
+        (FeatureTable):
+        (WebCore::OpenType::FeatureTable::getGlyphSubstitutions):
+        (FeatureList):
+        (FeatureRecord):
+        (WebCore::OpenType::FeatureList::feature):
+        (LangSysTable):
+        (WebCore::OpenType::LangSysTable::feature):
+        (ScriptTable):
+        (LangSysRecord):
+        (WebCore::OpenType::ScriptTable::defaultLangSys):
+        (ScriptList):
+        (ScriptRecord):
+        (WebCore::OpenType::ScriptList::script):
+        (WebCore::OpenType::ScriptList::defaultScript):
+        (WebCore::OpenType::ScriptList::defaultLangSys):
+        (GSUBTable):
+        (WebCore::OpenType::GSUBTable::scriptList):
+        (WebCore::OpenType::GSUBTable::featureList):
+        (WebCore::OpenType::GSUBTable::lookupList):
+        (WebCore::OpenType::GSUBTable::defaultLangSys):
+        (WebCore::OpenType::GSUBTable::feature):
+        (WebCore::OpenType::GSUBTable::getVerticalGlyphSubstitutions):
+        (WebCore::OpenTypeVerticalData::OpenTypeVerticalData):
+        (WebCore::OpenTypeVerticalData::loadMetrics): Split code to load metrics from ctor.
+        (WebCore::OpenTypeVerticalData::loadVerticalGlyphSubstitutions): Load the vertical alternate Glyph substitution table.
+        (WebCore):
+        (WebCore::OpenTypeVerticalData::substituteWithVerticalGlyphs): Substitute Glyph IDs with vertical alternate Glyph IDs.
+        * platform/graphics/opentype/OpenTypeVerticalData.h:
+        (OpenTypeVerticalData): Added m_verticalGlyphMap.
+
 2012-07-16  Vincent Scheib  <[email protected]>
 
         Fix spelling of EnforceIFrameAllowFullScreenRequirement and ExemptIFrameAllowFullScreenRequirement.

Modified: trunk/Source/WebCore/platform/graphics/opentype/OpenTypeTypes.h (122787 => 122788)


--- trunk/Source/WebCore/platform/graphics/opentype/OpenTypeTypes.h	2012-07-17 00:52:57 UTC (rev 122787)
+++ trunk/Source/WebCore/platform/graphics/opentype/OpenTypeTypes.h	2012-07-17 00:57:46 UTC (rev 122788)
@@ -25,6 +25,8 @@
 #ifndef OpenTypeTypes_h
 #define OpenTypeTypes_h
 
+#include "SharedBuffer.h"
+
 namespace WebCore {
 namespace OpenType {
 
@@ -67,6 +69,37 @@
 typedef uint32_t Tag;
 #define OT_MAKE_TAG(ch1, ch2, ch3, ch4) ((((uint32_t)(ch4)) << 24) | (((uint32_t)(ch3)) << 16) | (((uint32_t)(ch2)) << 8) | ((uint32_t)(ch1)))
 
+template <typename T> static const T* validateTable(const RefPtr<SharedBuffer>& buffer, size_t count = 1)
+{
+    if (!buffer || buffer->size() < sizeof(T) * count)
+        return 0;
+    return reinterpret_cast<const T*>(buffer->data());
+}
+
+struct TableBase {
+protected:
+    static bool isValidEnd(const SharedBuffer& buffer, const void* position)
+    {
+        if (position < buffer.data())
+            return false;
+        size_t offset = reinterpret_cast<const char*>(position) - buffer.data();
+        return offset <= buffer.size(); // "<=" because end is included as valid
+    }
+
+    template <typename T> static const T* validatePtr(const SharedBuffer& buffer, const void* position)
+    {
+        const T* casted = reinterpret_cast<const T*>(position);
+        if (!isValidEnd(buffer, &casted[1]))
+            return 0;
+        return casted;
+    }
+
+    template <typename T> const T* validateOffset(const SharedBuffer& buffer, uint16_t offset) const
+    {
+        return validatePtr<T>(buffer, reinterpret_cast<const int8_t*>(this) + offset);
+    }
+};
+
 } // namespace OpenType
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.cpp (122787 => 122788)


--- trunk/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.cpp	2012-07-17 00:52:57 UTC (rev 122787)
+++ trunk/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.cpp	2012-07-17 00:57:46 UTC (rev 122788)
@@ -23,6 +23,7 @@
  */
 
 #include "config.h"
+#if ENABLE(OPENTYPE_VERTICAL)
 #include "OpenTypeVerticalData.h"
 
 #include "FloatRect.h"
@@ -37,14 +38,17 @@
 namespace WebCore {
 namespace OpenType {
 
-enum {
-    HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a'),
-    HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x'),
-    VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a'),
-    VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x'),
-    VORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G'),
-};
+const uint32_t GSUBTag = OT_MAKE_TAG('G', 'S', 'U', 'B');
+const uint32_t HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a');
+const uint32_t HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x');
+const uint32_t VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a');
+const uint32_t VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x');
+const uint32_t VORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G');
 
+const uint32_t DefaultScriptTag = OT_MAKE_TAG('D', 'F', 'L', 'T');
+
+const uint32_t VertFeatureTag = OT_MAKE_TAG('v', 'e', 'r', 't');
+
 #pragma pack(1)
 
 struct HheaTable {
@@ -108,24 +112,287 @@
     size_t requiredSize() const { return sizeof(*this) + sizeof(VertOriginYMetrics) * (numVertOriginYMetrics - 1); }
 };
 
+struct CoverageTable : TableBase {
+    OpenType::UInt16 coverageFormat;
+};
+
+struct Coverage1Table : CoverageTable {
+    OpenType::UInt16 glyphCount;
+    OpenType::GlyphID glyphArray[1];
+};
+
+struct Coverage2Table : CoverageTable {
+    OpenType::UInt16 rangeCount;
+    struct RangeRecord {
+        OpenType::GlyphID start;
+        OpenType::GlyphID end;
+        OpenType::UInt16 startCoverageIndex;
+    } ranges[1];
+};
+
+struct SubstitutionSubTable : TableBase {
+    OpenType::UInt16 substFormat;
+    OpenType::Offset coverageOffset;
+
+    const CoverageTable* coverage(const SharedBuffer& buffer) const { return validateOffset<CoverageTable>(buffer, coverageOffset); }
+};
+
+struct SingleSubstitution2SubTable : SubstitutionSubTable {
+    OpenType::UInt16 glyphCount;
+    OpenType::GlyphID substitute[1];
+};
+
+struct LookupTable : TableBase {
+    OpenType::UInt16 lookupType;
+    OpenType::UInt16 lookupFlag;
+    OpenType::UInt16 subTableCount;
+    OpenType::Offset subTableOffsets[1];
+    // OpenType::UInt16 markFilteringSet; this field comes after variable length, so offset is determined dynamically.
+
+    bool getSubstitutions(HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer) const
+    {
+        uint16_t countSubTable = subTableCount;
+        if (!isValidEnd(buffer, &subTableOffsets[countSubTable]))
+            return false;
+        if (lookupType != 1) // "Single Substitution Subtable" is all what we support
+            return false;
+        for (uint16_t i = 0; i < countSubTable; ++i) {
+            const SubstitutionSubTable* substitution = validateOffset<SubstitutionSubTable>(buffer, subTableOffsets[i]);
+            if (!substitution)
+                return false;
+            const CoverageTable* coverage = substitution->coverage(buffer);
+            if (!coverage)
+                return false;
+            if (substitution->substFormat != 2) // "Single Substitution Format 2" is all what we support
+                return false;
+            const SingleSubstitution2SubTable* singleSubstitution2 = validatePtr<SingleSubstitution2SubTable>(buffer, substitution);
+            if (!singleSubstitution2)
+                return false;
+            uint16_t countTo = singleSubstitution2->glyphCount;
+            if (!isValidEnd(buffer, &singleSubstitution2->substitute[countTo]))
+                return false;
+            switch (coverage->coverageFormat) {
+            case 1: { // Coverage Format 1 (e.g., MS Gothic)
+                const Coverage1Table* coverage1 = validatePtr<Coverage1Table>(buffer, coverage);
+                if (!coverage1)
+                    return false;
+                uint16_t countFrom = coverage1->glyphCount;
+                if (!isValidEnd(buffer, &coverage1->glyphArray[countFrom]) || countTo != countFrom)
+                    return false;
+                for (uint16_t i = 0; i < countTo; ++i)
+                    map->set(coverage1->glyphArray[i], singleSubstitution2->substitute[i]);
+                break;
+            }
+            case 2: { // Coverage Format 2 (e.g., Adobe Kozuka Gothic)
+                const Coverage2Table* coverage2 = validatePtr<Coverage2Table>(buffer, coverage);
+                if (!coverage2)
+                    return false;
+                uint16_t countRange = coverage2->rangeCount;
+                if (!isValidEnd(buffer, &coverage2->ranges[countRange]))
+                    return false;
+                for (uint16_t i = 0, indexTo = 0; i < countRange; ++i) {
+                    uint16_t from = coverage2->ranges[i].start;
+                    uint16_t fromEnd = coverage2->ranges[i].end + 1; // OpenType "end" is inclusive
+                    if (indexTo + (fromEnd - from) > countTo)
+                        return false;
+                    for (; from != fromEnd; ++from, ++indexTo)
+                        map->set(from, singleSubstitution2->substitute[indexTo]);
+                }
+                break;
+            }
+            default:
+                return false;
+            }
+        }
+        return true;
+    }
+};
+
+struct LookupList : TableBase {
+    OpenType::UInt16 lookupCount;
+    OpenType::Offset lookupOffsets[1];
+
+    const LookupTable* lookup(uint16_t index, const SharedBuffer& buffer) const
+    {
+        uint16_t count = lookupCount;
+        if (index >= count || !isValidEnd(buffer, &lookupOffsets[count]))
+            return 0;
+        return validateOffset<LookupTable>(buffer, lookupOffsets[index]);
+    }
+};
+
+struct FeatureTable : TableBase {
+    OpenType::Offset featureParams;
+    OpenType::UInt16 lookupCount;
+    OpenType::UInt16 lookupListIndex[1];
+
+    bool getGlyphSubstitutions(const LookupList* lookups, HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer) const
+    {
+        uint16_t count = lookupCount;
+        if (!isValidEnd(buffer, &lookupListIndex[count]))
+            return false;
+        for (uint16_t i = 0; i < count; ++i) {
+            const LookupTable* lookup = lookups->lookup(lookupListIndex[i], buffer);
+            if (!lookup || !lookup->getSubstitutions(map, buffer))
+                return false;
+        }
+        return true;
+    }
+};
+
+struct FeatureList : TableBase {
+    OpenType::UInt16 featureCount;
+    struct FeatureRecord {
+        OpenType::Tag featureTag;
+        OpenType::Offset featureOffset;
+    } features[1];
+
+    const FeatureTable* feature(uint16_t index, OpenType::Tag tag, const SharedBuffer& buffer) const
+    {
+        uint16_t count = featureCount;
+        if (index >= count || !isValidEnd(buffer, &features[count]))
+            return 0;
+        if (features[index].featureTag == tag)
+            return validateOffset<FeatureTable>(buffer, features[index].featureOffset);
+        return 0;
+    }
+};
+
+struct LangSysTable : TableBase {
+    OpenType::Offset lookupOrder;
+    OpenType::UInt16 reqFeatureIndex;
+    OpenType::UInt16 featureCount;
+    OpenType::UInt16 featureIndex[1];
+
+    const FeatureTable* feature(OpenType::Tag featureTag, const FeatureList* features, const SharedBuffer& buffer) const
+    {
+        uint16_t count = featureCount;
+        if (!isValidEnd(buffer, &featureIndex[count]))
+            return 0;
+        for (uint16_t i = 0; i < count; ++i) {
+            const FeatureTable* featureTable = features->feature(featureIndex[i], featureTag, buffer);
+            if (featureTable)
+                return featureTable;
+        }
+        return 0;
+    }
+};
+
+struct ScriptTable : TableBase {
+    OpenType::Offset defaultLangSysOffset;
+    OpenType::UInt16 langSysCount;
+    struct LangSysRecord {
+        OpenType::Tag langSysTag;
+        OpenType::Offset langSysOffset;
+    } langSysRecords[1];
+
+    const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const
+    {
+        uint16_t count = langSysCount;
+        if (!isValidEnd(buffer, &langSysRecords[count]))
+            return 0;
+        uint16_t offset = defaultLangSysOffset;
+        if (offset)
+            return validateOffset<LangSysTable>(buffer, offset);
+        if (count)
+            return validateOffset<LangSysTable>(buffer, langSysRecords[0].langSysOffset);
+        return 0;
+    }
+};
+
+struct ScriptList : TableBase {
+    OpenType::UInt16 scriptCount;
+    struct ScriptRecord {
+        OpenType::Tag scriptTag;
+        OpenType::Offset scriptOffset;
+    } scripts[1];
+
+    const ScriptTable* script(OpenType::Tag tag, const SharedBuffer& buffer) const
+    {
+        uint16_t count = scriptCount;
+        if (!isValidEnd(buffer, &scripts[count]))
+            return 0;
+        for (uint16_t i = 0; i < count; ++i) {
+            if (scripts[i].scriptTag == tag)
+                return validateOffset<ScriptTable>(buffer, scripts[i].scriptOffset);
+        }
+        return 0;
+    }
+
+    const ScriptTable* defaultScript(const SharedBuffer& buffer) const
+    {
+        uint16_t count = scriptCount;
+        if (!count || !isValidEnd(buffer, &scripts[count]))
+            return 0;
+        const ScriptTable* scriptOfDefaultTag = script(OpenType::DefaultScriptTag, buffer);
+        if (scriptOfDefaultTag)
+            return scriptOfDefaultTag;
+        return validateOffset<ScriptTable>(buffer, scripts[0].scriptOffset);
+    }
+
+    const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const
+    {
+        const ScriptTable* scriptTable = defaultScript(buffer);
+        if (!scriptTable)
+            return 0;
+        return scriptTable->defaultLangSys(buffer);
+    }
+};
+
+struct GSUBTable : TableBase {
+    OpenType::Fixed version;
+    OpenType::Offset scriptListOffset;
+    OpenType::Offset featureListOffset;
+    OpenType::Offset lookupListOffset;
+
+    const ScriptList* scriptList(const SharedBuffer& buffer) const { return validateOffset<ScriptList>(buffer, scriptListOffset); }
+    const FeatureList* featureList(const SharedBuffer& buffer) const { return validateOffset<FeatureList>(buffer, featureListOffset); }
+    const LookupList* lookupList(const SharedBuffer& buffer) const { return validateOffset<LookupList>(buffer, lookupListOffset); }
+
+    const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const
+    {
+        const ScriptList* scripts = scriptList(buffer);
+        if (!scripts)
+            return 0;
+        return scripts->defaultLangSys(buffer);
+    }
+
+    const FeatureTable* feature(OpenType::Tag featureTag, const SharedBuffer& buffer) const
+    {
+        const LangSysTable* langSys = defaultLangSys(buffer);
+        const FeatureList* features = featureList(buffer);
+        if (!langSys || !features)
+            return 0;
+        return langSys->feature(featureTag, features, buffer);
+    }
+
+    bool getVerticalGlyphSubstitutions(HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer) const
+    {
+        const FeatureTable* verticalFeatureTable = feature(OpenType::VertFeatureTag, buffer);
+        if (!verticalFeatureTable)
+            return false;
+        const LookupList* lookups = lookupList(buffer);
+        return lookups && verticalFeatureTable->getGlyphSubstitutions(lookups, map, buffer);
+    }
+};
+
 #pragma pack()
 
 } // namespace OpenType
 
-template <typename T> const T* validatedPtr(const RefPtr<SharedBuffer>& buffer, size_t count = 1)
+OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
+    : m_defaultVertOriginY(0)
 {
-    if (!buffer || buffer->size() < sizeof(T) * count)
-        return 0;
-    return reinterpret_cast<const T*>(buffer->data());
+    loadMetrics(platformData);
+    loadVerticalGlyphSubstitutions(platformData);
 }
 
-OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
-    : m_defaultVertOriginY(0)
+void OpenTypeVerticalData::loadMetrics(const FontPlatformData& platformData)
 {
     // Load hhea and hmtx to get x-component of vertical origins.
     // If these tables are missing, it's not an OpenType font.
     RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::HheaTag);
-    const OpenType::HheaTable* hhea = validatedPtr<OpenType::HheaTable>(buffer);
+    const OpenType::HheaTable* hhea = OpenType::validateTable<OpenType::HheaTable>(buffer);
     if (!hhea)
         return;
     uint16_t countHmtxEntries = hhea->numberOfHMetrics;
@@ -135,7 +402,7 @@
     }
 
     buffer = platformData.openTypeTable(OpenType::HmtxTag);
-    const OpenType::HmtxTable* hmtx = validatedPtr<OpenType::HmtxTable>(buffer, countHmtxEntries);
+    const OpenType::HmtxTable* hmtx = OpenType::validateTable<OpenType::HmtxTable>(buffer, countHmtxEntries);
     if (!hmtx) {
         LOG_ERROR("hhea exists but hmtx does not (or broken)");
         return;
@@ -146,7 +413,7 @@
 
     // Load vhea first. This table is required for fonts that support vertical flow.
     buffer = platformData.openTypeTable(OpenType::VheaTag);
-    const OpenType::VheaTable* vhea = validatedPtr<OpenType::VheaTable>(buffer);
+    const OpenType::VheaTable* vhea = OpenType::validateTable<OpenType::VheaTable>(buffer);
     if (!vhea)
         return;
     uint16_t countVmtxEntries = vhea->numOfLongVerMetrics;
@@ -157,7 +424,7 @@
 
     // Load VORG. This table is optional.
     buffer = platformData.openTypeTable(OpenType::VORGTag);
-    const OpenType::VORGTable* vorg = validatedPtr<OpenType::VORGTable>(buffer);
+    const OpenType::VORGTable* vorg = OpenType::validateTable<OpenType::VORGTable>(buffer);
     if (vorg && buffer->size() >= vorg->requiredSize()) {
         m_defaultVertOriginY = vorg->defaultVertOriginY;
         uint16_t countVertOriginYMetrics = vorg->numVertOriginYMetrics;
@@ -174,7 +441,7 @@
 
     // Load vmtx then. This table is required for fonts that support vertical flow.
     buffer = platformData.openTypeTable(OpenType::VmtxTag);
-    const OpenType::VmtxTable* vmtx = validatedPtr<OpenType::VmtxTable>(buffer, countVmtxEntries);
+    const OpenType::VmtxTable* vmtx = OpenType::validateTable<OpenType::VmtxTable>(buffer, countVmtxEntries);
     if (!vmtx) {
         LOG_ERROR("vhea exists but vmtx does not (or broken)");
         return;
@@ -205,6 +472,14 @@
     }
 }
 
+void OpenTypeVerticalData::loadVerticalGlyphSubstitutions(const FontPlatformData& platformData)
+{
+    RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::GSUBTag);
+    const OpenType::GSUBTable* gsub = OpenType::validateTable<OpenType::GSUBTable>(buffer);
+    if (gsub)
+        gsub->getVerticalGlyphSubstitutions(&m_verticalGlyphMap, *buffer.get());
+}
+
 float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font, Glyph glyph) const
 {
     size_t countHeights = m_advanceHeights.size();
@@ -261,4 +536,23 @@
     }
 }
 
+void OpenTypeVerticalData::substituteWithVerticalGlyphs(const SimpleFontData* font, GlyphPage* glyphPage, unsigned offset, unsigned length) const
+{
+    const HashMap<Glyph, Glyph>& map = m_verticalGlyphMap;
+    if (map.isEmpty())
+        return;
+
+    for (unsigned index = offset, end = offset + length; index < end; ++index) {
+        Glyph glyph = glyphPage->glyphAt(index);
+        if (glyph) {
+            ASSERT(glyphPage->glyphDataForIndex(index).fontData == font);
+            Glyph to = map.get(glyph);
+            if (to)
+                glyphPage->setGlyphDataForIndex(index, to, font);
+        }
+    }
+}
+
 } // namespace WebCore
+
+#endif // ENABLE(OPENTYPE_VERTICAL)

Modified: trunk/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.h (122787 => 122788)


--- trunk/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.h	2012-07-17 00:52:57 UTC (rev 122787)
+++ trunk/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.h	2012-07-17 00:57:46 UTC (rev 122788)
@@ -43,10 +43,14 @@
     bool hasVerticalMetrics() const { return !m_advanceHeights.isEmpty(); }
     float advanceHeight(const SimpleFontData*, Glyph) const;
     void getVerticalTranslationsForGlyphs(const SimpleFontData*, const Glyph*, size_t, float* outXYArray) const;
+    void substituteWithVerticalGlyphs(const SimpleFontData*, GlyphPage*, unsigned offset, unsigned length) const;
 
 private:
+    void loadMetrics(const FontPlatformData&);
+    void loadVerticalGlyphSubstitutions(const FontPlatformData&);
     bool hasVORG() const { return !m_vertOriginY.isEmpty(); }
 
+    HashMap<Glyph, Glyph> m_verticalGlyphMap;
     Vector<uint16_t> m_advanceWidths;
     Vector<uint16_t> m_advanceHeights;
     Vector<int16_t> m_topSideBearings;

Modified: trunk/Source/WebKit/chromium/ChangeLog (122787 => 122788)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-07-17 00:52:57 UTC (rev 122787)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-07-17 00:57:46 UTC (rev 122788)
@@ -1,3 +1,19 @@
+2012-07-16  Koji Ishii  <[email protected]>
+
+        Vertical alternate glyph (GSUB) support for OpenTypeVerticalData
+        https://bugs.webkit.org/show_bug.cgi?id=81389
+
+        Reviewed by Tony Chang.
+
+        Tests for pointer validations for OpenType tables.
+
+        * WebKit.gypi:
+        * tests/OpenTypeVerticalDataTest.cpp: Added.
+        (WebCore):
+        (TestTable):
+        (WebCore::TestTable::validateOffset):
+        (WebCore::TEST):
+
 2012-07-16  Alexandre Elias  <[email protected]>
 
         [chromium] Fix WebFrameTest flakiness due to synthetic mouse events

Modified: trunk/Source/WebKit/chromium/WebKit.gypi (122787 => 122788)


--- trunk/Source/WebKit/chromium/WebKit.gypi	2012-07-17 00:52:57 UTC (rev 122787)
+++ trunk/Source/WebKit/chromium/WebKit.gypi	2012-07-17 00:57:46 UTC (rev 122788)
@@ -126,6 +126,7 @@
             'tests/LocalizedNumberICUTest.cpp',
             'tests/MockCCQuadCuller.h',
             'tests/OpaqueRectTrackingContentLayerDelegateTest.cpp',
+            'tests/OpenTypeVerticalDataTest.cpp',
             'tests/PaintAggregatorTest.cpp',
             'tests/PlatformGestureCurveTest.cpp',
             'tests/PlatformContextSkiaTest.cpp',

Added: trunk/Source/WebKit/chromium/tests/OpenTypeVerticalDataTest.cpp (0 => 122788)


--- trunk/Source/WebKit/chromium/tests/OpenTypeVerticalDataTest.cpp	                        (rev 0)
+++ trunk/Source/WebKit/chromium/tests/OpenTypeVerticalDataTest.cpp	2012-07-17 00:57:46 UTC (rev 122788)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 Koji Ishii <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(OPENTYPE_VERTICAL)
+
+#include "OpenTypeTypes.h"
+#include "SharedBuffer.h"
+#include <gtest/gtest.h>
+#include <wtf/RefPtr.h>
+
+using namespace WebCore;
+
+namespace {
+
+struct TestTable : OpenType::TableBase {
+    OpenType::Fixed version;
+    OpenType::Int16 ascender;
+
+    template <typename T> const T* validateOffset(const SharedBuffer& buffer, uint16_t offset) const
+    {
+        return TableBase::validateOffset<T>(buffer, offset);
+    }
+};
+
+TEST(OpenTypeVerticalDataTest, ValidateTableTest)
+{
+    RefPtr<SharedBuffer> buffer = SharedBuffer::create(sizeof(TestTable));
+    const TestTable* table = OpenType::validateTable<TestTable>(buffer);
+    EXPECT_TRUE(table);
+
+    buffer = SharedBuffer::create(sizeof(TestTable) - 1);
+    table = OpenType::validateTable<TestTable>(buffer);
+    EXPECT_FALSE(table);
+
+    buffer = SharedBuffer::create(sizeof(TestTable) + 1);
+    table = OpenType::validateTable<TestTable>(buffer);
+    EXPECT_TRUE(table);
+}
+
+TEST(OpenTypeVerticalDataTest, ValidateOffsetTest)
+{
+    RefPtr<SharedBuffer> buffer = SharedBuffer::create(sizeof(TestTable));
+    const TestTable* table = OpenType::validateTable<TestTable>(buffer);
+    ASSERT_TRUE(table);
+
+    // Test overflow
+    EXPECT_FALSE(table->validateOffset<uint8_t>(*buffer, -1));
+
+    // uint8_t is valid for all offsets
+    for (uint16_t offset = 0; offset < sizeof(TestTable); offset++)
+        EXPECT_TRUE(table->validateOffset<uint8_t>(*buffer, offset));
+    EXPECT_FALSE(table->validateOffset<uint8_t>(*buffer, sizeof(TestTable)));
+    EXPECT_FALSE(table->validateOffset<uint8_t>(*buffer, sizeof(TestTable) + 1));
+
+    // For uint16_t, the last byte is invalid
+    for (uint16_t offset = 0; offset < sizeof(TestTable) - 1; offset++)
+        EXPECT_TRUE(table->validateOffset<uint16_t>(*buffer, offset));
+    EXPECT_FALSE(table->validateOffset<uint16_t>(*buffer, sizeof(TestTable) - 1));
+}
+
+} // namespace
+
+#endif // ENABLE(OPENTYPE_VERTICAL)
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to