Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2524)

Unified Diff: Source/platform/fonts/opentype/OpenTypeVerticalData.cpp

Issue 932033002: Re-enable vertical flow in SimplePath (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: TestExpectations Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/platform/fonts/opentype/OpenTypeVerticalData.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/platform/fonts/opentype/OpenTypeVerticalData.cpp
diff --git a/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp b/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp
index e058c8129af259d0023b079f261d277ae38ffb3f..45ce79b16d4dad4bf21a178563fa70e740edc4bc 100644
--- a/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp
+++ b/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp
@@ -35,12 +35,17 @@
namespace blink {
namespace OpenType {
+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 {
@@ -104,6 +109,287 @@ struct VORGTable {
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;
+ }
+
+ const FeatureTable* findFeature(OpenType::Tag tag, const SharedBuffer& buffer) const
+ {
+ for (uint16_t i = 0; i < featureCount; ++i) {
+ if (isValidEnd(buffer, &features[i]) && features[i].featureTag == tag)
+ return validateOffset<FeatureTable>(buffer, features[i].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 (!features)
+ return 0;
+ const FeatureTable* feature = 0;
+ if (langSys)
+ feature = langSys->feature(featureTag, features, buffer);
+ if (!feature) {
+ // If the font has no langSys table, or has no default script and the first script doesn't
+ // have the requested feature, then use the first matching feature directly.
+ feature = features->findFeature(featureTag, buffer);
+ }
+ return feature;
+ }
+
+ 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
@@ -112,6 +398,7 @@ OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
: m_defaultVertOriginY(0)
{
loadMetrics(platformData);
+ loadVerticalGlyphSubstitutions(platformData);
}
void OpenTypeVerticalData::loadMetrics(const FontPlatformData& platformData)
@@ -255,4 +542,28 @@ void OpenTypeVerticalData::getVerticalTranslationsForGlyphs(const SimpleFontData
}
}
+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());
+}
+
+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) {
+ GlyphData glyphData = glyphPage->glyphDataForIndex(index);
+ if (glyphData.glyph && glyphData.fontData == font) {
+ Glyph to = map.get(glyphData.glyph);
+ if (to)
+ glyphPage->setGlyphDataForIndex(index, to, font);
+ }
+ }
+}
+
} // namespace blink
« no previous file with comments | « Source/platform/fonts/opentype/OpenTypeVerticalData.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698