| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 Koji Ishii <kojiishi@gmail.com> | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * 1. Redistributions of source code must retain the above copyright | |
| 8 * notice, this list of conditions and the following disclaimer. | |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer in the | |
| 11 * documentation and/or other materials provided with the distribution. | |
| 12 * | |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN
Y | |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN
Y | |
| 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O
N | |
| 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 23 */ | |
| 24 | |
| 25 #include "config.h" | |
| 26 #if ENABLE(OPENTYPE_VERTICAL) | |
| 27 #include "core/platform/graphics/opentype/OpenTypeVerticalData.h" | |
| 28 | |
| 29 #include "platform/SharedBuffer.h" | |
| 30 #include "core/platform/graphics/SimpleFontData.h" | |
| 31 #include "platform/fonts/GlyphPage.h" | |
| 32 #include "platform/fonts/opentype/OpenTypeTypes.h" | |
| 33 #include "platform/geometry/FloatRect.h" | |
| 34 #include "wtf/RefPtr.h" | |
| 35 | |
| 36 using namespace std; | |
| 37 | |
| 38 namespace WebCore { | |
| 39 namespace OpenType { | |
| 40 | |
| 41 const uint32_t GSUBTag = OT_MAKE_TAG('G', 'S', 'U', 'B'); | |
| 42 const uint32_t HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a'); | |
| 43 const uint32_t HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x'); | |
| 44 const uint32_t VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a'); | |
| 45 const uint32_t VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x'); | |
| 46 const uint32_t VORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G'); | |
| 47 | |
| 48 const uint32_t DefaultScriptTag = OT_MAKE_TAG('D', 'F', 'L', 'T'); | |
| 49 | |
| 50 const uint32_t VertFeatureTag = OT_MAKE_TAG('v', 'e', 'r', 't'); | |
| 51 | |
| 52 #pragma pack(1) | |
| 53 | |
| 54 struct HheaTable { | |
| 55 OpenType::Fixed version; | |
| 56 OpenType::Int16 ascender; | |
| 57 OpenType::Int16 descender; | |
| 58 OpenType::Int16 lineGap; | |
| 59 OpenType::Int16 advanceWidthMax; | |
| 60 OpenType::Int16 minLeftSideBearing; | |
| 61 OpenType::Int16 minRightSideBearing; | |
| 62 OpenType::Int16 xMaxExtent; | |
| 63 OpenType::Int16 caretSlopeRise; | |
| 64 OpenType::Int16 caretSlopeRun; | |
| 65 OpenType::Int16 caretOffset; | |
| 66 OpenType::Int16 reserved[4]; | |
| 67 OpenType::Int16 metricDataFormat; | |
| 68 OpenType::UInt16 numberOfHMetrics; | |
| 69 }; | |
| 70 | |
| 71 struct VheaTable { | |
| 72 OpenType::Fixed version; | |
| 73 OpenType::Int16 ascent; | |
| 74 OpenType::Int16 descent; | |
| 75 OpenType::Int16 lineGap; | |
| 76 OpenType::Int16 advanceHeightMax; | |
| 77 OpenType::Int16 minTopSideBearing; | |
| 78 OpenType::Int16 minBottomSideBearing; | |
| 79 OpenType::Int16 yMaxExtent; | |
| 80 OpenType::Int16 caretSlopeRise; | |
| 81 OpenType::Int16 caretSlopeRun; | |
| 82 OpenType::Int16 caretOffset; | |
| 83 OpenType::Int16 reserved[4]; | |
| 84 OpenType::Int16 metricDataFormat; | |
| 85 OpenType::UInt16 numOfLongVerMetrics; | |
| 86 }; | |
| 87 | |
| 88 struct HmtxTable { | |
| 89 struct Entry { | |
| 90 OpenType::UInt16 advanceWidth; | |
| 91 OpenType::Int16 lsb; | |
| 92 } entries[1]; | |
| 93 }; | |
| 94 | |
| 95 struct VmtxTable { | |
| 96 struct Entry { | |
| 97 OpenType::UInt16 advanceHeight; | |
| 98 OpenType::Int16 topSideBearing; | |
| 99 } entries[1]; | |
| 100 }; | |
| 101 | |
| 102 struct VORGTable { | |
| 103 OpenType::UInt16 majorVersion; | |
| 104 OpenType::UInt16 minorVersion; | |
| 105 OpenType::Int16 defaultVertOriginY; | |
| 106 OpenType::UInt16 numVertOriginYMetrics; | |
| 107 struct VertOriginYMetrics { | |
| 108 OpenType::UInt16 glyphIndex; | |
| 109 OpenType::Int16 vertOriginY; | |
| 110 } vertOriginYMetrics[1]; | |
| 111 | |
| 112 size_t requiredSize() const { return sizeof(*this) + sizeof(VertOriginYMetri
cs) * (numVertOriginYMetrics - 1); } | |
| 113 }; | |
| 114 | |
| 115 struct CoverageTable : TableBase { | |
| 116 OpenType::UInt16 coverageFormat; | |
| 117 }; | |
| 118 | |
| 119 struct Coverage1Table : CoverageTable { | |
| 120 OpenType::UInt16 glyphCount; | |
| 121 OpenType::GlyphID glyphArray[1]; | |
| 122 }; | |
| 123 | |
| 124 struct Coverage2Table : CoverageTable { | |
| 125 OpenType::UInt16 rangeCount; | |
| 126 struct RangeRecord { | |
| 127 OpenType::GlyphID start; | |
| 128 OpenType::GlyphID end; | |
| 129 OpenType::UInt16 startCoverageIndex; | |
| 130 } ranges[1]; | |
| 131 }; | |
| 132 | |
| 133 struct SubstitutionSubTable : TableBase { | |
| 134 OpenType::UInt16 substFormat; | |
| 135 OpenType::Offset coverageOffset; | |
| 136 | |
| 137 const CoverageTable* coverage(const SharedBuffer& buffer) const { return val
idateOffset<CoverageTable>(buffer, coverageOffset); } | |
| 138 }; | |
| 139 | |
| 140 struct SingleSubstitution2SubTable : SubstitutionSubTable { | |
| 141 OpenType::UInt16 glyphCount; | |
| 142 OpenType::GlyphID substitute[1]; | |
| 143 }; | |
| 144 | |
| 145 struct LookupTable : TableBase { | |
| 146 OpenType::UInt16 lookupType; | |
| 147 OpenType::UInt16 lookupFlag; | |
| 148 OpenType::UInt16 subTableCount; | |
| 149 OpenType::Offset subTableOffsets[1]; | |
| 150 // OpenType::UInt16 markFilteringSet; this field comes after variable length
, so offset is determined dynamically. | |
| 151 | |
| 152 bool getSubstitutions(HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer
) const | |
| 153 { | |
| 154 uint16_t countSubTable = subTableCount; | |
| 155 if (!isValidEnd(buffer, &subTableOffsets[countSubTable])) | |
| 156 return false; | |
| 157 if (lookupType != 1) // "Single Substitution Subtable" is all what we su
pport | |
| 158 return false; | |
| 159 for (uint16_t i = 0; i < countSubTable; ++i) { | |
| 160 const SubstitutionSubTable* substitution = validateOffset<Substituti
onSubTable>(buffer, subTableOffsets[i]); | |
| 161 if (!substitution) | |
| 162 return false; | |
| 163 const CoverageTable* coverage = substitution->coverage(buffer); | |
| 164 if (!coverage) | |
| 165 return false; | |
| 166 if (substitution->substFormat != 2) // "Single Substitution Format 2
" is all what we support | |
| 167 return false; | |
| 168 const SingleSubstitution2SubTable* singleSubstitution2 = validatePtr
<SingleSubstitution2SubTable>(buffer, substitution); | |
| 169 if (!singleSubstitution2) | |
| 170 return false; | |
| 171 uint16_t countTo = singleSubstitution2->glyphCount; | |
| 172 if (!isValidEnd(buffer, &singleSubstitution2->substitute[countTo])) | |
| 173 return false; | |
| 174 switch (coverage->coverageFormat) { | |
| 175 case 1: { // Coverage Format 1 (e.g., MS Gothic) | |
| 176 const Coverage1Table* coverage1 = validatePtr<Coverage1Table>(bu
ffer, coverage); | |
| 177 if (!coverage1) | |
| 178 return false; | |
| 179 uint16_t countFrom = coverage1->glyphCount; | |
| 180 if (!isValidEnd(buffer, &coverage1->glyphArray[countFrom]) || co
untTo != countFrom) | |
| 181 return false; | |
| 182 for (uint16_t i = 0; i < countTo; ++i) | |
| 183 map->set(coverage1->glyphArray[i], singleSubstitution2->subs
titute[i]); | |
| 184 break; | |
| 185 } | |
| 186 case 2: { // Coverage Format 2 (e.g., Adobe Kozuka Gothic) | |
| 187 const Coverage2Table* coverage2 = validatePtr<Coverage2Table>(bu
ffer, coverage); | |
| 188 if (!coverage2) | |
| 189 return false; | |
| 190 uint16_t countRange = coverage2->rangeCount; | |
| 191 if (!isValidEnd(buffer, &coverage2->ranges[countRange])) | |
| 192 return false; | |
| 193 for (uint16_t i = 0, indexTo = 0; i < countRange; ++i) { | |
| 194 uint16_t from = coverage2->ranges[i].start; | |
| 195 uint16_t fromEnd = coverage2->ranges[i].end + 1; // OpenType
"end" is inclusive | |
| 196 if (indexTo + (fromEnd - from) > countTo) | |
| 197 return false; | |
| 198 for (; from != fromEnd; ++from, ++indexTo) | |
| 199 map->set(from, singleSubstitution2->substitute[indexTo])
; | |
| 200 } | |
| 201 break; | |
| 202 } | |
| 203 default: | |
| 204 return false; | |
| 205 } | |
| 206 } | |
| 207 return true; | |
| 208 } | |
| 209 }; | |
| 210 | |
| 211 struct LookupList : TableBase { | |
| 212 OpenType::UInt16 lookupCount; | |
| 213 OpenType::Offset lookupOffsets[1]; | |
| 214 | |
| 215 const LookupTable* lookup(uint16_t index, const SharedBuffer& buffer) const | |
| 216 { | |
| 217 uint16_t count = lookupCount; | |
| 218 if (index >= count || !isValidEnd(buffer, &lookupOffsets[count])) | |
| 219 return 0; | |
| 220 return validateOffset<LookupTable>(buffer, lookupOffsets[index]); | |
| 221 } | |
| 222 }; | |
| 223 | |
| 224 struct FeatureTable : TableBase { | |
| 225 OpenType::Offset featureParams; | |
| 226 OpenType::UInt16 lookupCount; | |
| 227 OpenType::UInt16 lookupListIndex[1]; | |
| 228 | |
| 229 bool getGlyphSubstitutions(const LookupList* lookups, HashMap<Glyph, Glyph>*
map, const SharedBuffer& buffer) const | |
| 230 { | |
| 231 uint16_t count = lookupCount; | |
| 232 if (!isValidEnd(buffer, &lookupListIndex[count])) | |
| 233 return false; | |
| 234 for (uint16_t i = 0; i < count; ++i) { | |
| 235 const LookupTable* lookup = lookups->lookup(lookupListIndex[i], buff
er); | |
| 236 if (!lookup || !lookup->getSubstitutions(map, buffer)) | |
| 237 return false; | |
| 238 } | |
| 239 return true; | |
| 240 } | |
| 241 }; | |
| 242 | |
| 243 struct FeatureList : TableBase { | |
| 244 OpenType::UInt16 featureCount; | |
| 245 struct FeatureRecord { | |
| 246 OpenType::Tag featureTag; | |
| 247 OpenType::Offset featureOffset; | |
| 248 } features[1]; | |
| 249 | |
| 250 const FeatureTable* feature(uint16_t index, OpenType::Tag tag, const SharedB
uffer& buffer) const | |
| 251 { | |
| 252 uint16_t count = featureCount; | |
| 253 if (index >= count || !isValidEnd(buffer, &features[count])) | |
| 254 return 0; | |
| 255 if (features[index].featureTag == tag) | |
| 256 return validateOffset<FeatureTable>(buffer, features[index].featureO
ffset); | |
| 257 return 0; | |
| 258 } | |
| 259 | |
| 260 const FeatureTable* findFeature(OpenType::Tag tag, const SharedBuffer& buffe
r) const | |
| 261 { | |
| 262 for (uint16_t i = 0; i < featureCount; ++i) { | |
| 263 if (isValidEnd(buffer, &features[i]) && features[i].featureTag == ta
g) | |
| 264 return validateOffset<FeatureTable>(buffer, features[i].featureO
ffset); | |
| 265 } | |
| 266 return 0; | |
| 267 } | |
| 268 }; | |
| 269 | |
| 270 struct LangSysTable : TableBase { | |
| 271 OpenType::Offset lookupOrder; | |
| 272 OpenType::UInt16 reqFeatureIndex; | |
| 273 OpenType::UInt16 featureCount; | |
| 274 OpenType::UInt16 featureIndex[1]; | |
| 275 | |
| 276 const FeatureTable* feature(OpenType::Tag featureTag, const FeatureList* fea
tures, const SharedBuffer& buffer) const | |
| 277 { | |
| 278 uint16_t count = featureCount; | |
| 279 if (!isValidEnd(buffer, &featureIndex[count])) | |
| 280 return 0; | |
| 281 for (uint16_t i = 0; i < count; ++i) { | |
| 282 const FeatureTable* featureTable = features->feature(featureIndex[i]
, featureTag, buffer); | |
| 283 if (featureTable) | |
| 284 return featureTable; | |
| 285 } | |
| 286 return 0; | |
| 287 } | |
| 288 }; | |
| 289 | |
| 290 struct ScriptTable : TableBase { | |
| 291 OpenType::Offset defaultLangSysOffset; | |
| 292 OpenType::UInt16 langSysCount; | |
| 293 struct LangSysRecord { | |
| 294 OpenType::Tag langSysTag; | |
| 295 OpenType::Offset langSysOffset; | |
| 296 } langSysRecords[1]; | |
| 297 | |
| 298 const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const | |
| 299 { | |
| 300 uint16_t count = langSysCount; | |
| 301 if (!isValidEnd(buffer, &langSysRecords[count])) | |
| 302 return 0; | |
| 303 uint16_t offset = defaultLangSysOffset; | |
| 304 if (offset) | |
| 305 return validateOffset<LangSysTable>(buffer, offset); | |
| 306 if (count) | |
| 307 return validateOffset<LangSysTable>(buffer, langSysRecords[0].langSy
sOffset); | |
| 308 return 0; | |
| 309 } | |
| 310 }; | |
| 311 | |
| 312 struct ScriptList : TableBase { | |
| 313 OpenType::UInt16 scriptCount; | |
| 314 struct ScriptRecord { | |
| 315 OpenType::Tag scriptTag; | |
| 316 OpenType::Offset scriptOffset; | |
| 317 } scripts[1]; | |
| 318 | |
| 319 const ScriptTable* script(OpenType::Tag tag, const SharedBuffer& buffer) con
st | |
| 320 { | |
| 321 uint16_t count = scriptCount; | |
| 322 if (!isValidEnd(buffer, &scripts[count])) | |
| 323 return 0; | |
| 324 for (uint16_t i = 0; i < count; ++i) { | |
| 325 if (scripts[i].scriptTag == tag) | |
| 326 return validateOffset<ScriptTable>(buffer, scripts[i].scriptOffs
et); | |
| 327 } | |
| 328 return 0; | |
| 329 } | |
| 330 | |
| 331 const ScriptTable* defaultScript(const SharedBuffer& buffer) const | |
| 332 { | |
| 333 uint16_t count = scriptCount; | |
| 334 if (!count || !isValidEnd(buffer, &scripts[count])) | |
| 335 return 0; | |
| 336 const ScriptTable* scriptOfDefaultTag = script(OpenType::DefaultScriptTa
g, buffer); | |
| 337 if (scriptOfDefaultTag) | |
| 338 return scriptOfDefaultTag; | |
| 339 return validateOffset<ScriptTable>(buffer, scripts[0].scriptOffset); | |
| 340 } | |
| 341 | |
| 342 const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const | |
| 343 { | |
| 344 const ScriptTable* scriptTable = defaultScript(buffer); | |
| 345 if (!scriptTable) | |
| 346 return 0; | |
| 347 return scriptTable->defaultLangSys(buffer); | |
| 348 } | |
| 349 }; | |
| 350 | |
| 351 struct GSUBTable : TableBase { | |
| 352 OpenType::Fixed version; | |
| 353 OpenType::Offset scriptListOffset; | |
| 354 OpenType::Offset featureListOffset; | |
| 355 OpenType::Offset lookupListOffset; | |
| 356 | |
| 357 const ScriptList* scriptList(const SharedBuffer& buffer) const { return vali
dateOffset<ScriptList>(buffer, scriptListOffset); } | |
| 358 const FeatureList* featureList(const SharedBuffer& buffer) const { return va
lidateOffset<FeatureList>(buffer, featureListOffset); } | |
| 359 const LookupList* lookupList(const SharedBuffer& buffer) const { return vali
dateOffset<LookupList>(buffer, lookupListOffset); } | |
| 360 | |
| 361 const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const | |
| 362 { | |
| 363 const ScriptList* scripts = scriptList(buffer); | |
| 364 if (!scripts) | |
| 365 return 0; | |
| 366 return scripts->defaultLangSys(buffer); | |
| 367 } | |
| 368 | |
| 369 const FeatureTable* feature(OpenType::Tag featureTag, const SharedBuffer& bu
ffer) const | |
| 370 { | |
| 371 const LangSysTable* langSys = defaultLangSys(buffer); | |
| 372 const FeatureList* features = featureList(buffer); | |
| 373 if (!features) | |
| 374 return 0; | |
| 375 const FeatureTable* feature = 0; | |
| 376 if (langSys) | |
| 377 feature = langSys->feature(featureTag, features, buffer); | |
| 378 if (!feature) { | |
| 379 // If the font has no langSys table, or has no default script and th
e first script doesn't | |
| 380 // have the requested feature, then use the first matching feature d
irectly. | |
| 381 feature = features->findFeature(featureTag, buffer); | |
| 382 } | |
| 383 return feature; | |
| 384 } | |
| 385 | |
| 386 bool getVerticalGlyphSubstitutions(HashMap<Glyph, Glyph>* map, const SharedB
uffer& buffer) const | |
| 387 { | |
| 388 const FeatureTable* verticalFeatureTable = feature(OpenType::VertFeature
Tag, buffer); | |
| 389 if (!verticalFeatureTable) | |
| 390 return false; | |
| 391 const LookupList* lookups = lookupList(buffer); | |
| 392 return lookups && verticalFeatureTable->getGlyphSubstitutions(lookups, m
ap, buffer); | |
| 393 } | |
| 394 }; | |
| 395 | |
| 396 #pragma pack() | |
| 397 | |
| 398 } // namespace OpenType | |
| 399 | |
| 400 OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData) | |
| 401 : m_defaultVertOriginY(0) | |
| 402 { | |
| 403 loadMetrics(platformData); | |
| 404 loadVerticalGlyphSubstitutions(platformData); | |
| 405 } | |
| 406 | |
| 407 void OpenTypeVerticalData::loadMetrics(const FontPlatformData& platformData) | |
| 408 { | |
| 409 // Load hhea and hmtx to get x-component of vertical origins. | |
| 410 // If these tables are missing, it's not an OpenType font. | |
| 411 RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::HheaTag); | |
| 412 const OpenType::HheaTable* hhea = OpenType::validateTable<OpenType::HheaTabl
e>(buffer); | |
| 413 if (!hhea) | |
| 414 return; | |
| 415 uint16_t countHmtxEntries = hhea->numberOfHMetrics; | |
| 416 if (!countHmtxEntries) { | |
| 417 WTF_LOG_ERROR("Invalid numberOfHMetrics"); | |
| 418 return; | |
| 419 } | |
| 420 | |
| 421 buffer = platformData.openTypeTable(OpenType::HmtxTag); | |
| 422 const OpenType::HmtxTable* hmtx = OpenType::validateTable<OpenType::HmtxTabl
e>(buffer, countHmtxEntries); | |
| 423 if (!hmtx) { | |
| 424 WTF_LOG_ERROR("hhea exists but hmtx does not (or broken)"); | |
| 425 return; | |
| 426 } | |
| 427 m_advanceWidths.resize(countHmtxEntries); | |
| 428 for (uint16_t i = 0; i < countHmtxEntries; ++i) | |
| 429 m_advanceWidths[i] = hmtx->entries[i].advanceWidth; | |
| 430 | |
| 431 // Load vhea first. This table is required for fonts that support vertical f
low. | |
| 432 buffer = platformData.openTypeTable(OpenType::VheaTag); | |
| 433 const OpenType::VheaTable* vhea = OpenType::validateTable<OpenType::VheaTabl
e>(buffer); | |
| 434 if (!vhea) | |
| 435 return; | |
| 436 uint16_t countVmtxEntries = vhea->numOfLongVerMetrics; | |
| 437 if (!countVmtxEntries) { | |
| 438 WTF_LOG_ERROR("Invalid numOfLongVerMetrics"); | |
| 439 return; | |
| 440 } | |
| 441 | |
| 442 // Load VORG. This table is optional. | |
| 443 buffer = platformData.openTypeTable(OpenType::VORGTag); | |
| 444 const OpenType::VORGTable* vorg = OpenType::validateTable<OpenType::VORGTabl
e>(buffer); | |
| 445 if (vorg && buffer->size() >= vorg->requiredSize()) { | |
| 446 m_defaultVertOriginY = vorg->defaultVertOriginY; | |
| 447 uint16_t countVertOriginYMetrics = vorg->numVertOriginYMetrics; | |
| 448 if (!countVertOriginYMetrics) { | |
| 449 // Add one entry so that hasVORG() becomes true | |
| 450 m_vertOriginY.set(0, m_defaultVertOriginY); | |
| 451 } else { | |
| 452 for (uint16_t i = 0; i < countVertOriginYMetrics; ++i) { | |
| 453 const OpenType::VORGTable::VertOriginYMetrics& metrics = vorg->v
ertOriginYMetrics[i]; | |
| 454 m_vertOriginY.set(metrics.glyphIndex, metrics.vertOriginY); | |
| 455 } | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 // Load vmtx then. This table is required for fonts that support vertical fl
ow. | |
| 460 buffer = platformData.openTypeTable(OpenType::VmtxTag); | |
| 461 const OpenType::VmtxTable* vmtx = OpenType::validateTable<OpenType::VmtxTabl
e>(buffer, countVmtxEntries); | |
| 462 if (!vmtx) { | |
| 463 WTF_LOG_ERROR("vhea exists but vmtx does not (or broken)"); | |
| 464 return; | |
| 465 } | |
| 466 m_advanceHeights.resize(countVmtxEntries); | |
| 467 for (uint16_t i = 0; i < countVmtxEntries; ++i) | |
| 468 m_advanceHeights[i] = vmtx->entries[i].advanceHeight; | |
| 469 | |
| 470 // VORG is preferred way to calculate vertical origin than vmtx, | |
| 471 // so load topSideBearing from vmtx only if VORG is missing. | |
| 472 if (hasVORG()) | |
| 473 return; | |
| 474 | |
| 475 size_t sizeExtra = buffer->size() - sizeof(OpenType::VmtxTable::Entry) * cou
ntVmtxEntries; | |
| 476 if (sizeExtra % sizeof(OpenType::Int16)) { | |
| 477 WTF_LOG_ERROR("vmtx has incorrect tsb count"); | |
| 478 return; | |
| 479 } | |
| 480 size_t countTopSideBearings = countVmtxEntries + sizeExtra / sizeof(OpenType
::Int16); | |
| 481 m_topSideBearings.resize(countTopSideBearings); | |
| 482 size_t i; | |
| 483 for (i = 0; i < countVmtxEntries; ++i) | |
| 484 m_topSideBearings[i] = vmtx->entries[i].topSideBearing; | |
| 485 if (i < countTopSideBearings) { | |
| 486 const OpenType::Int16* pTopSideBearingsExtra = reinterpret_cast<const Op
enType::Int16*>(&vmtx->entries[countVmtxEntries]); | |
| 487 for (; i < countTopSideBearings; ++i, ++pTopSideBearingsExtra) | |
| 488 m_topSideBearings[i] = *pTopSideBearingsExtra; | |
| 489 } | |
| 490 } | |
| 491 | |
| 492 void OpenTypeVerticalData::loadVerticalGlyphSubstitutions(const FontPlatformData
& platformData) | |
| 493 { | |
| 494 RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::GSUBTag); | |
| 495 const OpenType::GSUBTable* gsub = OpenType::validateTable<OpenType::GSUBTabl
e>(buffer); | |
| 496 if (gsub) | |
| 497 gsub->getVerticalGlyphSubstitutions(&m_verticalGlyphMap, *buffer.get()); | |
| 498 } | |
| 499 | |
| 500 float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font, Glyph glyp
h) const | |
| 501 { | |
| 502 size_t countHeights = m_advanceHeights.size(); | |
| 503 if (countHeights) { | |
| 504 uint16_t advanceFUnit = m_advanceHeights[glyph < countHeights ? glyph :
countHeights - 1]; | |
| 505 float advance = advanceFUnit * font->sizePerUnit(); | |
| 506 return advance; | |
| 507 } | |
| 508 | |
| 509 // No vertical info in the font file; use height as advance. | |
| 510 return font->fontMetrics().height(); | |
| 511 } | |
| 512 | |
| 513 void OpenTypeVerticalData::getVerticalTranslationsForGlyphs(const SimpleFontData
* font, const Glyph* glyphs, size_t count, float* outXYArray) const | |
| 514 { | |
| 515 size_t countWidths = m_advanceWidths.size(); | |
| 516 ASSERT(countWidths > 0); | |
| 517 const FontMetrics& metrics = font->fontMetrics(); | |
| 518 float sizePerUnit = font->sizePerUnit(); | |
| 519 float ascent = metrics.ascent(); | |
| 520 bool useVORG = hasVORG(); | |
| 521 size_t countTopSideBearings = m_topSideBearings.size(); | |
| 522 float defaultVertOriginY = std::numeric_limits<float>::quiet_NaN(); | |
| 523 for (float* end = &(outXYArray[count * 2]); outXYArray != end; ++glyphs, out
XYArray += 2) { | |
| 524 Glyph glyph = *glyphs; | |
| 525 uint16_t widthFUnit = m_advanceWidths[glyph < countWidths ? glyph : coun
tWidths - 1]; | |
| 526 float width = widthFUnit * sizePerUnit; | |
| 527 outXYArray[0] = -width / 2; | |
| 528 | |
| 529 // For Y, try VORG first. | |
| 530 if (useVORG) { | |
| 531 int16_t vertOriginYFUnit = m_vertOriginY.get(glyph); | |
| 532 if (vertOriginYFUnit) { | |
| 533 outXYArray[1] = -vertOriginYFUnit * sizePerUnit; | |
| 534 continue; | |
| 535 } | |
| 536 if (std::isnan(defaultVertOriginY)) | |
| 537 defaultVertOriginY = -m_defaultVertOriginY * sizePerUnit; | |
| 538 outXYArray[1] = defaultVertOriginY; | |
| 539 continue; | |
| 540 } | |
| 541 | |
| 542 // If no VORG, try vmtx next. | |
| 543 if (countTopSideBearings) { | |
| 544 int16_t topSideBearingFUnit = m_topSideBearings[glyph < countTopSide
Bearings ? glyph : countTopSideBearings - 1]; | |
| 545 float topSideBearing = topSideBearingFUnit * sizePerUnit; | |
| 546 FloatRect bounds = font->boundsForGlyph(glyph); | |
| 547 outXYArray[1] = bounds.y() - topSideBearing; | |
| 548 continue; | |
| 549 } | |
| 550 | |
| 551 // No vertical info in the font file; use ascent as vertical origin. | |
| 552 outXYArray[1] = -ascent; | |
| 553 } | |
| 554 } | |
| 555 | |
| 556 void OpenTypeVerticalData::substituteWithVerticalGlyphs(const SimpleFontData* fo
nt, GlyphPage* glyphPage, unsigned offset, unsigned length) const | |
| 557 { | |
| 558 const HashMap<Glyph, Glyph>& map = m_verticalGlyphMap; | |
| 559 if (map.isEmpty()) | |
| 560 return; | |
| 561 | |
| 562 for (unsigned index = offset, end = offset + length; index < end; ++index) { | |
| 563 Glyph glyph = glyphPage->glyphAt(index); | |
| 564 if (glyph) { | |
| 565 ASSERT(glyphPage->glyphDataForIndex(index).fontData == font); | |
| 566 Glyph to = map.get(glyph); | |
| 567 if (to) | |
| 568 glyphPage->setGlyphDataForIndex(index, to, font); | |
| 569 } | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 } // namespace WebCore | |
| 574 #endif // ENABLE(OPENTYPE_VERTICAL) | |
| OLD | NEW |