| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 Google Inc. All rights reserved. | 2 * Copyright (c) 2012 Google Inc. All rights reserved. |
| 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. | 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
| 7 * met: | 7 * met: |
| 8 * | 8 * |
| 9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 */ | 30 */ |
| 31 | 31 |
| 32 #include "platform/fonts/shaping/HarfBuzzShaper.h" | 32 #include "platform/fonts/shaping/HarfBuzzShaper.h" |
| 33 | 33 |
| 34 #include "platform/RuntimeEnabledFeatures.h" | 34 #include "platform/RuntimeEnabledFeatures.h" |
| 35 #include "platform/fonts/Font.h" | 35 #include "platform/fonts/Font.h" |
| 36 #include "platform/fonts/FontFallbackIterator.h" | 36 #include "platform/fonts/FontFallbackIterator.h" |
| 37 #include "platform/fonts/GlyphBuffer.h" | 37 #include "platform/fonts/GlyphBuffer.h" |
| 38 #include "platform/fonts/SmallCapsIterator.h" |
| 38 #include "platform/fonts/UTF16TextIterator.h" | 39 #include "platform/fonts/UTF16TextIterator.h" |
| 39 #include "platform/fonts/opentype/OpenTypeCapsSupport.h" | 40 #include "platform/fonts/opentype/OpenTypeCapsSupport.h" |
| 40 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h" | 41 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h" |
| 41 #include "platform/fonts/shaping/HarfBuzzFace.h" | 42 #include "platform/fonts/shaping/HarfBuzzFace.h" |
| 42 #include "platform/fonts/shaping/RunSegmenter.h" | 43 #include "platform/fonts/shaping/RunSegmenter.h" |
| 43 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" | 44 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" |
| 44 #include "platform/text/Character.h" | 45 #include "platform/text/Character.h" |
| 45 #include "platform/text/TextBreakIterator.h" | 46 #include "platform/text/TextBreakIterator.h" |
| 46 #include "wtf/Compiler.h" | 47 #include "wtf/Compiler.h" |
| 47 #include "wtf/MathExtras.h" | 48 #include "wtf/MathExtras.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 character = zeroWidthSpaceCharacter; | 115 character = zeroWidthSpaceCharacter; |
| 115 } else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) { | 116 } else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) { |
| 116 character = zeroWidthSpaceCharacter; | 117 character = zeroWidthSpaceCharacter; |
| 117 } | 118 } |
| 118 | 119 |
| 119 U16_APPEND(destination, *destinationLength, length, character, error); | 120 U16_APPEND(destination, *destinationLength, length, character, error); |
| 120 DCHECK(!error); | 121 DCHECK(!error); |
| 121 } | 122 } |
| 122 } | 123 } |
| 123 | 124 |
| 124 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run) | 125 HarfBuzzShaper::HarfBuzzShaper(const TextRun& run) |
| 125 : m_font(font), m_textRun(run), m_normalizedBufferLength(0) { | 126 : m_textRun(run), m_normalizedBufferLength(0) { |
| 126 m_normalizedBuffer = wrapArrayUnique(new UChar[m_textRun.length() + 1]); | 127 m_normalizedBuffer = wrapArrayUnique(new UChar[m_textRun.length() + 1]); |
| 127 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(), | 128 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(), |
| 128 &m_normalizedBufferLength); | 129 &m_normalizedBufferLength); |
| 129 setFontFeatures(); | |
| 130 } | 130 } |
| 131 | 131 |
| 132 static inline hb_feature_t createFeature(uint8_t c1, | 132 namespace { |
| 133 uint8_t c2, | |
| 134 uint8_t c3, | |
| 135 uint8_t c4, | |
| 136 uint32_t value = 0) { | |
| 137 return {HB_TAG(c1, c2, c3, c4), value, 0 /* start */, | |
| 138 static_cast<unsigned>(-1) /* end */}; | |
| 139 } | |
| 140 | |
| 141 void HarfBuzzShaper::setFontFeatures() { | |
| 142 const FontDescription& description = m_font->getFontDescription(); | |
| 143 | |
| 144 static hb_feature_t noKern = createFeature('k', 'e', 'r', 'n'); | |
| 145 static hb_feature_t noVkrn = createFeature('v', 'k', 'r', 'n'); | |
| 146 switch (description.getKerning()) { | |
| 147 case FontDescription::NormalKerning: | |
| 148 // kern/vkrn are enabled by default | |
| 149 break; | |
| 150 case FontDescription::NoneKerning: | |
| 151 m_features.append(description.isVerticalAnyUpright() ? noVkrn : noKern); | |
| 152 break; | |
| 153 case FontDescription::AutoKerning: | |
| 154 break; | |
| 155 } | |
| 156 | |
| 157 static hb_feature_t noClig = createFeature('c', 'l', 'i', 'g'); | |
| 158 static hb_feature_t noLiga = createFeature('l', 'i', 'g', 'a'); | |
| 159 switch (description.commonLigaturesState()) { | |
| 160 case FontDescription::DisabledLigaturesState: | |
| 161 m_features.append(noLiga); | |
| 162 m_features.append(noClig); | |
| 163 break; | |
| 164 case FontDescription::EnabledLigaturesState: | |
| 165 // liga and clig are on by default | |
| 166 break; | |
| 167 case FontDescription::NormalLigaturesState: | |
| 168 break; | |
| 169 } | |
| 170 static hb_feature_t dlig = createFeature('d', 'l', 'i', 'g', 1); | |
| 171 switch (description.discretionaryLigaturesState()) { | |
| 172 case FontDescription::DisabledLigaturesState: | |
| 173 // dlig is off by default | |
| 174 break; | |
| 175 case FontDescription::EnabledLigaturesState: | |
| 176 m_features.append(dlig); | |
| 177 break; | |
| 178 case FontDescription::NormalLigaturesState: | |
| 179 break; | |
| 180 } | |
| 181 static hb_feature_t hlig = createFeature('h', 'l', 'i', 'g', 1); | |
| 182 switch (description.historicalLigaturesState()) { | |
| 183 case FontDescription::DisabledLigaturesState: | |
| 184 // hlig is off by default | |
| 185 break; | |
| 186 case FontDescription::EnabledLigaturesState: | |
| 187 m_features.append(hlig); | |
| 188 break; | |
| 189 case FontDescription::NormalLigaturesState: | |
| 190 break; | |
| 191 } | |
| 192 static hb_feature_t noCalt = createFeature('c', 'a', 'l', 't'); | |
| 193 switch (description.contextualLigaturesState()) { | |
| 194 case FontDescription::DisabledLigaturesState: | |
| 195 m_features.append(noCalt); | |
| 196 break; | |
| 197 case FontDescription::EnabledLigaturesState: | |
| 198 // calt is on by default | |
| 199 break; | |
| 200 case FontDescription::NormalLigaturesState: | |
| 201 break; | |
| 202 } | |
| 203 | |
| 204 static hb_feature_t hwid = createFeature('h', 'w', 'i', 'd', 1); | |
| 205 static hb_feature_t twid = createFeature('t', 'w', 'i', 'd', 1); | |
| 206 static hb_feature_t qwid = createFeature('q', 'w', 'i', 'd', 1); | |
| 207 switch (description.widthVariant()) { | |
| 208 case HalfWidth: | |
| 209 m_features.append(hwid); | |
| 210 break; | |
| 211 case ThirdWidth: | |
| 212 m_features.append(twid); | |
| 213 break; | |
| 214 case QuarterWidth: | |
| 215 m_features.append(qwid); | |
| 216 break; | |
| 217 case RegularWidth: | |
| 218 break; | |
| 219 } | |
| 220 | |
| 221 // font-variant-numeric: | |
| 222 static hb_feature_t lnum = createFeature('l', 'n', 'u', 'm', 1); | |
| 223 if (description.variantNumeric().numericFigureValue() == | |
| 224 FontVariantNumeric::LiningNums) | |
| 225 m_features.append(lnum); | |
| 226 | |
| 227 static hb_feature_t onum = createFeature('o', 'n', 'u', 'm', 1); | |
| 228 if (description.variantNumeric().numericFigureValue() == | |
| 229 FontVariantNumeric::OldstyleNums) | |
| 230 m_features.append(onum); | |
| 231 | |
| 232 static hb_feature_t pnum = createFeature('p', 'n', 'u', 'm', 1); | |
| 233 if (description.variantNumeric().numericSpacingValue() == | |
| 234 FontVariantNumeric::ProportionalNums) | |
| 235 m_features.append(pnum); | |
| 236 static hb_feature_t tnum = createFeature('t', 'n', 'u', 'm', 1); | |
| 237 if (description.variantNumeric().numericSpacingValue() == | |
| 238 FontVariantNumeric::TabularNums) | |
| 239 m_features.append(tnum); | |
| 240 | |
| 241 static hb_feature_t afrc = createFeature('a', 'f', 'r', 'c', 1); | |
| 242 if (description.variantNumeric().numericFractionValue() == | |
| 243 FontVariantNumeric::StackedFractions) | |
| 244 m_features.append(afrc); | |
| 245 static hb_feature_t frac = createFeature('f', 'r', 'a', 'c', 1); | |
| 246 if (description.variantNumeric().numericFractionValue() == | |
| 247 FontVariantNumeric::DiagonalFractions) | |
| 248 m_features.append(frac); | |
| 249 | |
| 250 static hb_feature_t ordn = createFeature('o', 'r', 'd', 'n', 1); | |
| 251 if (description.variantNumeric().ordinalValue() == | |
| 252 FontVariantNumeric::OrdinalOn) | |
| 253 m_features.append(ordn); | |
| 254 | |
| 255 static hb_feature_t zero = createFeature('z', 'e', 'r', 'o', 1); | |
| 256 if (description.variantNumeric().slashedZeroValue() == | |
| 257 FontVariantNumeric::SlashedZeroOn) | |
| 258 m_features.append(zero); | |
| 259 | |
| 260 FontFeatureSettings* settings = description.featureSettings(); | |
| 261 if (!settings) | |
| 262 return; | |
| 263 | |
| 264 // TODO(drott): crbug.com/450619 Implement feature resolution instead of | |
| 265 // just appending the font-feature-settings. | |
| 266 unsigned numFeatures = settings->size(); | |
| 267 for (unsigned i = 0; i < numFeatures; ++i) { | |
| 268 hb_feature_t feature; | |
| 269 const AtomicString& tag = settings->at(i).tag(); | |
| 270 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); | |
| 271 feature.value = settings->at(i).value(); | |
| 272 feature.start = 0; | |
| 273 feature.end = static_cast<unsigned>(-1); | |
| 274 m_features.append(feature); | |
| 275 } | |
| 276 } | |
| 277 | |
| 278 HarfBuzzShaper::CapsFeatureSettingsScopedOverlay:: | |
| 279 CapsFeatureSettingsScopedOverlay( | |
| 280 FeaturesVector& features, | |
| 281 FontDescription::FontVariantCaps variantCaps) | |
| 282 : m_features(features), m_countFeatures(0) { | |
| 283 overlayCapsFeatures(variantCaps); | |
| 284 } | |
| 285 | |
| 286 void HarfBuzzShaper::CapsFeatureSettingsScopedOverlay::overlayCapsFeatures( | |
| 287 FontDescription::FontVariantCaps variantCaps) { | |
| 288 static hb_feature_t smcp = createFeature('s', 'm', 'c', 'p', 1); | |
| 289 static hb_feature_t pcap = createFeature('p', 'c', 'a', 'p', 1); | |
| 290 static hb_feature_t c2sc = createFeature('c', '2', 's', 'c', 1); | |
| 291 static hb_feature_t c2pc = createFeature('c', '2', 'p', 'c', 1); | |
| 292 static hb_feature_t unic = createFeature('u', 'n', 'i', 'c', 1); | |
| 293 static hb_feature_t titl = createFeature('t', 'i', 't', 'l', 1); | |
| 294 if (variantCaps == FontDescription::SmallCaps || | |
| 295 variantCaps == FontDescription::AllSmallCaps) { | |
| 296 prependCounting(smcp); | |
| 297 if (variantCaps == FontDescription::AllSmallCaps) { | |
| 298 prependCounting(c2sc); | |
| 299 } | |
| 300 } | |
| 301 if (variantCaps == FontDescription::PetiteCaps || | |
| 302 variantCaps == FontDescription::AllPetiteCaps) { | |
| 303 prependCounting(pcap); | |
| 304 if (variantCaps == FontDescription::AllPetiteCaps) { | |
| 305 prependCounting(c2pc); | |
| 306 } | |
| 307 } | |
| 308 if (variantCaps == FontDescription::Unicase) { | |
| 309 prependCounting(unic); | |
| 310 } | |
| 311 if (variantCaps == FontDescription::TitlingCaps) { | |
| 312 prependCounting(titl); | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 void HarfBuzzShaper::CapsFeatureSettingsScopedOverlay::prependCounting( | |
| 317 const hb_feature_t& feature) { | |
| 318 m_features.prepend(feature); | |
| 319 m_countFeatures++; | |
| 320 } | |
| 321 | |
| 322 HarfBuzzShaper::CapsFeatureSettingsScopedOverlay:: | |
| 323 ~CapsFeatureSettingsScopedOverlay() { | |
| 324 m_features.remove(0, m_countFeatures); | |
| 325 } | |
| 326 | 133 |
| 327 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built | 134 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built |
| 328 // without hb-icu. See http://crbug.com/356929 | 135 // without hb-icu. See http://crbug.com/356929 |
| 329 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) { | 136 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) { |
| 330 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) | 137 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) |
| 331 return HB_SCRIPT_INVALID; | 138 return HB_SCRIPT_INVALID; |
| 332 | 139 |
| 333 return hb_script_from_string(uscript_getShortName(script), -1); | 140 return hb_script_from_string(uscript_getShortName(script), -1); |
| 334 } | 141 } |
| 335 | 142 |
| 336 static inline hb_direction_t TextDirectionToHBDirection( | 143 static inline hb_direction_t TextDirectionToHBDirection( |
| 337 TextDirection dir, | 144 TextDirection dir, |
| 338 FontOrientation orientation, | 145 FontOrientation orientation, |
| 339 const SimpleFontData* fontData) { | 146 const SimpleFontData* fontData) { |
| 340 hb_direction_t harfBuzzDirection = | 147 hb_direction_t harfBuzzDirection = |
| 341 isVerticalAnyUpright(orientation) && | 148 isVerticalAnyUpright(orientation) && |
| 342 !fontData->isTextOrientationFallback() | 149 !fontData->isTextOrientationFallback() |
| 343 ? HB_DIRECTION_TTB | 150 ? HB_DIRECTION_TTB |
| 344 : HB_DIRECTION_LTR; | 151 : HB_DIRECTION_LTR; |
| 345 return dir == RTL ? HB_DIRECTION_REVERSE(harfBuzzDirection) | 152 return dir == RTL ? HB_DIRECTION_REVERSE(harfBuzzDirection) |
| 346 : harfBuzzDirection; | 153 : harfBuzzDirection; |
| 347 } | 154 } |
| 348 | 155 |
| 156 } // namespace |
| 157 |
| 349 inline bool HarfBuzzShaper::shapeRange( | 158 inline bool HarfBuzzShaper::shapeRange( |
| 350 hb_buffer_t* harfBuzzBuffer, | 159 hb_buffer_t* harfBuzzBuffer, |
| 160 const Font* font, |
| 161 const FeaturesVector& fontFeatures, |
| 351 const SimpleFontData* currentFont, | 162 const SimpleFontData* currentFont, |
| 352 PassRefPtr<UnicodeRangeSet> currentFontRangeSet, | 163 PassRefPtr<UnicodeRangeSet> currentFontRangeSet, |
| 353 UScriptCode currentRunScript, | 164 UScriptCode currentRunScript, |
| 354 hb_language_t language) { | 165 hb_language_t language) { |
| 355 const FontPlatformData* platformData = &(currentFont->platformData()); | 166 const FontPlatformData* platformData = &(currentFont->platformData()); |
| 356 HarfBuzzFace* face = platformData->harfBuzzFace(); | 167 HarfBuzzFace* face = platformData->harfBuzzFace(); |
| 357 if (!face) { | 168 if (!face) { |
| 358 DLOG(ERROR) << "Could not create HarfBuzzFace from FontPlatformData."; | 169 DLOG(ERROR) << "Could not create HarfBuzzFace from FontPlatformData."; |
| 359 return false; | 170 return false; |
| 360 } | 171 } |
| 361 | 172 |
| 362 hb_buffer_set_language(harfBuzzBuffer, language); | 173 hb_buffer_set_language(harfBuzzBuffer, language); |
| 363 hb_buffer_set_script(harfBuzzBuffer, ICUScriptToHBScript(currentRunScript)); | 174 hb_buffer_set_script(harfBuzzBuffer, ICUScriptToHBScript(currentRunScript)); |
| 364 hb_buffer_set_direction( | 175 hb_buffer_set_direction( |
| 365 harfBuzzBuffer, | 176 harfBuzzBuffer, |
| 366 TextDirectionToHBDirection(m_textRun.direction(), | 177 TextDirectionToHBDirection(m_textRun.direction(), |
| 367 m_font->getFontDescription().orientation(), | 178 font->getFontDescription().orientation(), |
| 368 currentFont)); | 179 currentFont)); |
| 369 | 180 |
| 370 hb_font_t* hbFont = face->getScaledFont(std::move(currentFontRangeSet)); | 181 hb_font_t* hbFont = face->getScaledFont(std::move(currentFontRangeSet)); |
| 371 hb_shape(hbFont, harfBuzzBuffer, m_features.isEmpty() ? 0 : m_features.data(), | 182 hb_shape(hbFont, harfBuzzBuffer, |
| 372 m_features.size()); | 183 fontFeatures.isEmpty() ? 0 : fontFeatures.data(), |
| 184 fontFeatures.size()); |
| 373 | 185 |
| 374 return true; | 186 return true; |
| 375 } | 187 } |
| 376 | 188 |
| 377 bool HarfBuzzShaper::extractShapeResults(hb_buffer_t* harfBuzzBuffer, | 189 bool HarfBuzzShaper::extractShapeResults(hb_buffer_t* harfBuzzBuffer, |
| 378 ShapeResult* shapeResult, | 190 ShapeResult* shapeResult, |
| 379 bool& fontCycleQueued, | 191 bool& fontCycleQueued, |
| 192 Deque<HolesQueueItem>* holesQueue, |
| 380 const HolesQueueItem& currentQueueItem, | 193 const HolesQueueItem& currentQueueItem, |
| 194 const Font* font, |
| 381 const SimpleFontData* currentFont, | 195 const SimpleFontData* currentFont, |
| 382 UScriptCode currentRunScript, | 196 UScriptCode currentRunScript, |
| 383 bool isLastResort) { | 197 bool isLastResort) { |
| 384 enum ClusterResult { Shaped, NotDef, Unknown }; | 198 enum ClusterResult { Shaped, NotDef, Unknown }; |
| 385 ClusterResult currentClusterResult = Unknown; | 199 ClusterResult currentClusterResult = Unknown; |
| 386 ClusterResult previousClusterResult = Unknown; | 200 ClusterResult previousClusterResult = Unknown; |
| 387 unsigned previousCluster = 0; | 201 unsigned previousCluster = 0; |
| 388 unsigned currentCluster = 0; | 202 unsigned currentCluster = 0; |
| 389 | 203 |
| 390 // Find first notdef glyph in harfBuzzBuffer. | 204 // Find first notdef glyph in harfBuzzBuffer. |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 } else { | 281 } else { |
| 468 numCharacters = glyphInfo[lastChangePosition - 1].cluster - | 282 numCharacters = glyphInfo[lastChangePosition - 1].cluster - |
| 469 glyphInfo[glyphIndex - 1].cluster; | 283 glyphInfo[glyphIndex - 1].cluster; |
| 470 } | 284 } |
| 471 numGlyphsToInsert = glyphIndex - lastChangePosition; | 285 numGlyphsToInsert = glyphIndex - lastChangePosition; |
| 472 } | 286 } |
| 473 | 287 |
| 474 if (currentClusterResult == Shaped && !isLastResort) { | 288 if (currentClusterResult == Shaped && !isLastResort) { |
| 475 // Now it's clear that we need to continue processing. | 289 // Now it's clear that we need to continue processing. |
| 476 if (!fontCycleQueued) { | 290 if (!fontCycleQueued) { |
| 477 appendToHolesQueue(HolesQueueNextFont, 0, 0); | 291 holesQueue->append(HolesQueueItem(HolesQueueNextFont, 0, 0)); |
| 478 fontCycleQueued = true; | 292 fontCycleQueued = true; |
| 479 } | 293 } |
| 480 | 294 |
| 481 // Here we need to put character positions. | 295 // Here we need to put character positions. |
| 482 ASSERT(numCharacters); | 296 ASSERT(numCharacters); |
| 483 appendToHolesQueue(HolesQueueRange, startIndex, numCharacters); | 297 holesQueue->append( |
| 298 HolesQueueItem(HolesQueueRange, startIndex, numCharacters)); |
| 484 } | 299 } |
| 485 | 300 |
| 486 // If numCharacters is 0, that means we hit a NotDef before shaping the | 301 // If numCharacters is 0, that means we hit a NotDef before shaping the |
| 487 // whole grapheme. We do not append it here. For the next glyph we | 302 // whole grapheme. We do not append it here. For the next glyph we |
| 488 // encounter, atChange will be true, and the characters corresponding to | 303 // encounter, atChange will be true, and the characters corresponding to |
| 489 // the grapheme will be added to the TODO queue again, attempting to | 304 // the grapheme will be added to the TODO queue again, attempting to |
| 490 // shape the whole grapheme with the next font. | 305 // shape the whole grapheme with the next font. |
| 491 // When we're getting here with the last resort font, we have no other | 306 // When we're getting here with the last resort font, we have no other |
| 492 // choice than adding boxes to the ShapeResult. | 307 // choice than adding boxes to the ShapeResult. |
| 493 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) { | 308 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) { |
| 494 hb_direction_t direction = TextDirectionToHBDirection( | 309 hb_direction_t direction = TextDirectionToHBDirection( |
| 495 m_textRun.direction(), m_font->getFontDescription().orientation(), | 310 m_textRun.direction(), font->getFontDescription().orientation(), |
| 496 currentFont); | 311 currentFont); |
| 497 // Here we need to specify glyph positions. | 312 // Here we need to specify glyph positions. |
| 498 ShapeResult::RunInfo* run = new ShapeResult::RunInfo( | 313 ShapeResult::RunInfo* run = new ShapeResult::RunInfo( |
| 499 currentFont, direction, ICUScriptToHBScript(currentRunScript), | 314 currentFont, direction, ICUScriptToHBScript(currentRunScript), |
| 500 startIndex, numGlyphsToInsert, numCharacters); | 315 startIndex, numGlyphsToInsert, numCharacters); |
| 501 shapeResult->insertRun(wrapUnique(run), lastChangePosition, | 316 shapeResult->insertRun(wrapUnique(run), lastChangePosition, |
| 502 numGlyphsToInsert, harfBuzzBuffer); | 317 numGlyphsToInsert, harfBuzzBuffer); |
| 503 } | 318 } |
| 504 lastChangePosition = glyphIndex; | 319 lastChangePosition = glyphIndex; |
| 505 } | 320 } |
| 506 return true; | 321 return true; |
| 507 } | 322 } |
| 508 | 323 |
| 509 static inline const SimpleFontData* fontDataAdjustedForOrientation( | 324 static inline const SimpleFontData* fontDataAdjustedForOrientation( |
| 510 const SimpleFontData* originalFont, | 325 const SimpleFontData* originalFont, |
| 511 FontOrientation runOrientation, | 326 FontOrientation runOrientation, |
| 512 OrientationIterator::RenderOrientation renderOrientation) { | 327 OrientationIterator::RenderOrientation renderOrientation) { |
| 513 if (!isVerticalBaseline(runOrientation)) | 328 if (!isVerticalBaseline(runOrientation)) |
| 514 return originalFont; | 329 return originalFont; |
| 515 | 330 |
| 516 if (runOrientation == FontOrientation::VerticalRotated || | 331 if (runOrientation == FontOrientation::VerticalRotated || |
| 517 (runOrientation == FontOrientation::VerticalMixed && | 332 (runOrientation == FontOrientation::VerticalMixed && |
| 518 renderOrientation == OrientationIterator::OrientationRotateSideways)) | 333 renderOrientation == OrientationIterator::OrientationRotateSideways)) |
| 519 return originalFont->verticalRightOrientationFontData().get(); | 334 return originalFont->verticalRightOrientationFontData().get(); |
| 520 | 335 |
| 521 return originalFont; | 336 return originalFont; |
| 522 } | 337 } |
| 523 | 338 |
| 524 bool HarfBuzzShaper::collectFallbackHintChars(Vector<UChar32>& hint) { | 339 bool HarfBuzzShaper::collectFallbackHintChars( |
| 525 if (!m_holesQueue.size()) | 340 const Deque<HolesQueueItem>& holesQueue, |
| 341 Vector<UChar32>& hint) { |
| 342 if (!holesQueue.size()) |
| 526 return false; | 343 return false; |
| 527 | 344 |
| 528 hint.clear(); | 345 hint.clear(); |
| 529 | 346 |
| 530 size_t numCharsAdded = 0; | 347 size_t numCharsAdded = 0; |
| 531 for (auto it = m_holesQueue.begin(); it != m_holesQueue.end(); ++it) { | 348 for (auto it = holesQueue.begin(); it != holesQueue.end(); ++it) { |
| 532 if (it->m_action == HolesQueueNextFont) | 349 if (it->m_action == HolesQueueNextFont) |
| 533 break; | 350 break; |
| 534 | 351 |
| 535 UChar32 hintChar; | 352 UChar32 hintChar; |
| 536 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <= | 353 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <= |
| 537 m_normalizedBufferLength); | 354 m_normalizedBufferLength); |
| 538 UTF16TextIterator iterator(m_normalizedBuffer.get() + it->m_startIndex, | 355 UTF16TextIterator iterator(m_normalizedBuffer.get() + it->m_startIndex, |
| 539 it->m_numCharacters); | 356 it->m_numCharacters); |
| 540 while (iterator.consume(hintChar)) { | 357 while (iterator.consume(hintChar)) { |
| 541 hint.append(hintChar); | 358 hint.append(hintChar); |
| 542 numCharsAdded++; | 359 numCharsAdded++; |
| 543 iterator.advance(); | 360 iterator.advance(); |
| 544 } | 361 } |
| 545 } | 362 } |
| 546 return numCharsAdded > 0; | 363 return numCharsAdded > 0; |
| 547 } | 364 } |
| 548 | 365 |
| 549 void HarfBuzzShaper::appendToHolesQueue(HolesQueueItemAction action, | 366 namespace { |
| 550 unsigned startIndex, | 367 using HolesQueueItem = HarfBuzzShaper::HolesQueueItem; |
| 551 unsigned numCharacters) { | 368 using HolesQueueItemAction = HarfBuzzShaper::HolesQueueItemAction; |
| 552 m_holesQueue.append(HolesQueueItem(action, startIndex, numCharacters)); | 369 |
| 553 } | 370 void splitUntilNextCaseChange( |
| 554 | 371 const UChar* normalizedBuffer, |
| 555 void HarfBuzzShaper::prependHolesQueue(HolesQueueItemAction action, | 372 Deque<HolesQueueItem>* queue, |
| 556 unsigned startIndex, | |
| 557 unsigned numCharacters) { | |
| 558 m_holesQueue.prepend(HolesQueueItem(action, startIndex, numCharacters)); | |
| 559 } | |
| 560 | |
| 561 void HarfBuzzShaper::splitUntilNextCaseChange( | |
| 562 HolesQueueItem& currentQueueItem, | 373 HolesQueueItem& currentQueueItem, |
| 563 SmallCapsIterator::SmallCapsBehavior& smallCapsBehavior) { | 374 SmallCapsIterator::SmallCapsBehavior& smallCapsBehavior) { |
| 564 unsigned numCharactersUntilCaseChange = 0; | 375 unsigned numCharactersUntilCaseChange = 0; |
| 565 SmallCapsIterator smallCapsIterator( | 376 SmallCapsIterator smallCapsIterator( |
| 566 m_normalizedBuffer.get() + currentQueueItem.m_startIndex, | 377 normalizedBuffer + currentQueueItem.m_startIndex, |
| 567 currentQueueItem.m_numCharacters); | 378 currentQueueItem.m_numCharacters); |
| 568 smallCapsIterator.consume(&numCharactersUntilCaseChange, &smallCapsBehavior); | 379 smallCapsIterator.consume(&numCharactersUntilCaseChange, &smallCapsBehavior); |
| 569 if (numCharactersUntilCaseChange > 0 && | 380 if (numCharactersUntilCaseChange > 0 && |
| 570 numCharactersUntilCaseChange < currentQueueItem.m_numCharacters) { | 381 numCharactersUntilCaseChange < currentQueueItem.m_numCharacters) { |
| 571 prependHolesQueue( | 382 unsigned startIndex = |
| 572 HolesQueueRange, | 383 currentQueueItem.m_startIndex + numCharactersUntilCaseChange; |
| 573 currentQueueItem.m_startIndex + numCharactersUntilCaseChange, | 384 unsigned numCharacters = |
| 574 currentQueueItem.m_numCharacters - numCharactersUntilCaseChange); | 385 currentQueueItem.m_numCharacters - numCharactersUntilCaseChange; |
| 386 queue->prepend(HolesQueueItem(HolesQueueItemAction::HolesQueueRange, |
| 387 startIndex, numCharacters)); |
| 575 currentQueueItem.m_numCharacters = numCharactersUntilCaseChange; | 388 currentQueueItem.m_numCharacters = numCharactersUntilCaseChange; |
| 576 } | 389 } |
| 577 } | 390 } |
| 578 | 391 |
| 579 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult() { | 392 hb_feature_t createFeature(uint8_t c1, |
| 393 uint8_t c2, |
| 394 uint8_t c3, |
| 395 uint8_t c4, |
| 396 uint32_t value = 0) { |
| 397 return {HB_TAG(c1, c2, c3, c4), value, 0 /* start */, |
| 398 static_cast<unsigned>(-1) /* end */}; |
| 399 } |
| 400 |
| 401 void setFontFeatures(const Font* font, |
| 402 HarfBuzzShaper::FeaturesVector* features) { |
| 403 const FontDescription& description = font->getFontDescription(); |
| 404 |
| 405 static hb_feature_t noKern = createFeature('k', 'e', 'r', 'n'); |
| 406 static hb_feature_t noVkrn = createFeature('v', 'k', 'r', 'n'); |
| 407 switch (description.getKerning()) { |
| 408 case FontDescription::NormalKerning: |
| 409 // kern/vkrn are enabled by default |
| 410 break; |
| 411 case FontDescription::NoneKerning: |
| 412 features->append(description.isVerticalAnyUpright() ? noVkrn : noKern); |
| 413 break; |
| 414 case FontDescription::AutoKerning: |
| 415 break; |
| 416 } |
| 417 |
| 418 static hb_feature_t noClig = createFeature('c', 'l', 'i', 'g'); |
| 419 static hb_feature_t noLiga = createFeature('l', 'i', 'g', 'a'); |
| 420 switch (description.commonLigaturesState()) { |
| 421 case FontDescription::DisabledLigaturesState: |
| 422 features->append(noLiga); |
| 423 features->append(noClig); |
| 424 break; |
| 425 case FontDescription::EnabledLigaturesState: |
| 426 // liga and clig are on by default |
| 427 break; |
| 428 case FontDescription::NormalLigaturesState: |
| 429 break; |
| 430 } |
| 431 static hb_feature_t dlig = createFeature('d', 'l', 'i', 'g', 1); |
| 432 switch (description.discretionaryLigaturesState()) { |
| 433 case FontDescription::DisabledLigaturesState: |
| 434 // dlig is off by default |
| 435 break; |
| 436 case FontDescription::EnabledLigaturesState: |
| 437 features->append(dlig); |
| 438 break; |
| 439 case FontDescription::NormalLigaturesState: |
| 440 break; |
| 441 } |
| 442 static hb_feature_t hlig = createFeature('h', 'l', 'i', 'g', 1); |
| 443 switch (description.historicalLigaturesState()) { |
| 444 case FontDescription::DisabledLigaturesState: |
| 445 // hlig is off by default |
| 446 break; |
| 447 case FontDescription::EnabledLigaturesState: |
| 448 features->append(hlig); |
| 449 break; |
| 450 case FontDescription::NormalLigaturesState: |
| 451 break; |
| 452 } |
| 453 static hb_feature_t noCalt = createFeature('c', 'a', 'l', 't'); |
| 454 switch (description.contextualLigaturesState()) { |
| 455 case FontDescription::DisabledLigaturesState: |
| 456 features->append(noCalt); |
| 457 break; |
| 458 case FontDescription::EnabledLigaturesState: |
| 459 // calt is on by default |
| 460 break; |
| 461 case FontDescription::NormalLigaturesState: |
| 462 break; |
| 463 } |
| 464 |
| 465 static hb_feature_t hwid = createFeature('h', 'w', 'i', 'd', 1); |
| 466 static hb_feature_t twid = createFeature('t', 'w', 'i', 'd', 1); |
| 467 static hb_feature_t qwid = createFeature('q', 'w', 'i', 'd', 1); |
| 468 switch (description.widthVariant()) { |
| 469 case HalfWidth: |
| 470 features->append(hwid); |
| 471 break; |
| 472 case ThirdWidth: |
| 473 features->append(twid); |
| 474 break; |
| 475 case QuarterWidth: |
| 476 features->append(qwid); |
| 477 break; |
| 478 case RegularWidth: |
| 479 break; |
| 480 } |
| 481 |
| 482 // font-variant-numeric: |
| 483 static hb_feature_t lnum = createFeature('l', 'n', 'u', 'm', 1); |
| 484 if (description.variantNumeric().numericFigureValue() == |
| 485 FontVariantNumeric::LiningNums) |
| 486 features->append(lnum); |
| 487 |
| 488 static hb_feature_t onum = createFeature('o', 'n', 'u', 'm', 1); |
| 489 if (description.variantNumeric().numericFigureValue() == |
| 490 FontVariantNumeric::OldstyleNums) |
| 491 features->append(onum); |
| 492 |
| 493 static hb_feature_t pnum = createFeature('p', 'n', 'u', 'm', 1); |
| 494 if (description.variantNumeric().numericSpacingValue() == |
| 495 FontVariantNumeric::ProportionalNums) |
| 496 features->append(pnum); |
| 497 static hb_feature_t tnum = createFeature('t', 'n', 'u', 'm', 1); |
| 498 if (description.variantNumeric().numericSpacingValue() == |
| 499 FontVariantNumeric::TabularNums) |
| 500 features->append(tnum); |
| 501 |
| 502 static hb_feature_t afrc = createFeature('a', 'f', 'r', 'c', 1); |
| 503 if (description.variantNumeric().numericFractionValue() == |
| 504 FontVariantNumeric::StackedFractions) |
| 505 features->append(afrc); |
| 506 static hb_feature_t frac = createFeature('f', 'r', 'a', 'c', 1); |
| 507 if (description.variantNumeric().numericFractionValue() == |
| 508 FontVariantNumeric::DiagonalFractions) |
| 509 features->append(frac); |
| 510 |
| 511 static hb_feature_t ordn = createFeature('o', 'r', 'd', 'n', 1); |
| 512 if (description.variantNumeric().ordinalValue() == |
| 513 FontVariantNumeric::OrdinalOn) |
| 514 features->append(ordn); |
| 515 |
| 516 static hb_feature_t zero = createFeature('z', 'e', 'r', 'o', 1); |
| 517 if (description.variantNumeric().slashedZeroValue() == |
| 518 FontVariantNumeric::SlashedZeroOn) |
| 519 features->append(zero); |
| 520 |
| 521 FontFeatureSettings* settings = description.featureSettings(); |
| 522 if (!settings) |
| 523 return; |
| 524 |
| 525 // TODO(drott): crbug.com/450619 Implement feature resolution instead of |
| 526 // just appending the font-feature-settings. |
| 527 unsigned numFeatures = settings->size(); |
| 528 for (unsigned i = 0; i < numFeatures; ++i) { |
| 529 hb_feature_t feature; |
| 530 const AtomicString& tag = settings->at(i).tag(); |
| 531 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); |
| 532 feature.value = settings->at(i).value(); |
| 533 feature.start = 0; |
| 534 feature.end = static_cast<unsigned>(-1); |
| 535 features->append(feature); |
| 536 } |
| 537 } |
| 538 |
| 539 class CapsFeatureSettingsScopedOverlay final { |
| 540 STACK_ALLOCATED() |
| 541 |
| 542 public: |
| 543 CapsFeatureSettingsScopedOverlay(HarfBuzzShaper::FeaturesVector*, |
| 544 FontDescription::FontVariantCaps); |
| 545 CapsFeatureSettingsScopedOverlay() = delete; |
| 546 ~CapsFeatureSettingsScopedOverlay(); |
| 547 |
| 548 private: |
| 549 void overlayCapsFeatures(FontDescription::FontVariantCaps); |
| 550 void prependCounting(const hb_feature_t&); |
| 551 HarfBuzzShaper::FeaturesVector* m_features; |
| 552 size_t m_countFeatures; |
| 553 }; |
| 554 |
| 555 CapsFeatureSettingsScopedOverlay::CapsFeatureSettingsScopedOverlay( |
| 556 HarfBuzzShaper::FeaturesVector* features, |
| 557 FontDescription::FontVariantCaps variantCaps) |
| 558 : m_features(features), m_countFeatures(0) { |
| 559 overlayCapsFeatures(variantCaps); |
| 560 } |
| 561 |
| 562 void CapsFeatureSettingsScopedOverlay::overlayCapsFeatures( |
| 563 FontDescription::FontVariantCaps variantCaps) { |
| 564 static hb_feature_t smcp = createFeature('s', 'm', 'c', 'p', 1); |
| 565 static hb_feature_t pcap = createFeature('p', 'c', 'a', 'p', 1); |
| 566 static hb_feature_t c2sc = createFeature('c', '2', 's', 'c', 1); |
| 567 static hb_feature_t c2pc = createFeature('c', '2', 'p', 'c', 1); |
| 568 static hb_feature_t unic = createFeature('u', 'n', 'i', 'c', 1); |
| 569 static hb_feature_t titl = createFeature('t', 'i', 't', 'l', 1); |
| 570 if (variantCaps == FontDescription::SmallCaps || |
| 571 variantCaps == FontDescription::AllSmallCaps) { |
| 572 prependCounting(smcp); |
| 573 if (variantCaps == FontDescription::AllSmallCaps) { |
| 574 prependCounting(c2sc); |
| 575 } |
| 576 } |
| 577 if (variantCaps == FontDescription::PetiteCaps || |
| 578 variantCaps == FontDescription::AllPetiteCaps) { |
| 579 prependCounting(pcap); |
| 580 if (variantCaps == FontDescription::AllPetiteCaps) { |
| 581 prependCounting(c2pc); |
| 582 } |
| 583 } |
| 584 if (variantCaps == FontDescription::Unicase) { |
| 585 prependCounting(unic); |
| 586 } |
| 587 if (variantCaps == FontDescription::TitlingCaps) { |
| 588 prependCounting(titl); |
| 589 } |
| 590 } |
| 591 |
| 592 void CapsFeatureSettingsScopedOverlay::prependCounting( |
| 593 const hb_feature_t& feature) { |
| 594 m_features->prepend(feature); |
| 595 m_countFeatures++; |
| 596 } |
| 597 |
| 598 CapsFeatureSettingsScopedOverlay::~CapsFeatureSettingsScopedOverlay() { |
| 599 m_features->remove(0, m_countFeatures); |
| 600 } |
| 601 |
| 602 } // namespace |
| 603 |
| 604 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult(const Font* font) { |
| 580 RefPtr<ShapeResult> result = ShapeResult::create( | 605 RefPtr<ShapeResult> result = ShapeResult::create( |
| 581 m_font, m_normalizedBufferLength, m_textRun.direction()); | 606 font, m_normalizedBufferLength, m_textRun.direction()); |
| 582 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), | 607 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), |
| 583 hb_buffer_destroy); | 608 hb_buffer_destroy); |
| 584 | 609 FeaturesVector fontFeatures; |
| 585 const FontDescription& fontDescription = m_font->getFontDescription(); | 610 setFontFeatures(font, &fontFeatures); |
| 611 const FontDescription& fontDescription = font->getFontDescription(); |
| 586 const hb_language_t language = | 612 const hb_language_t language = |
| 587 fontDescription.localeOrDefault().harfbuzzLanguage(); | 613 fontDescription.localeOrDefault().harfbuzzLanguage(); |
| 588 | 614 |
| 589 bool needsCapsHandling = | 615 bool needsCapsHandling = |
| 590 fontDescription.variantCaps() != FontDescription::CapsNormal; | 616 fontDescription.variantCaps() != FontDescription::CapsNormal; |
| 591 OpenTypeCapsSupport capsSupport; | 617 OpenTypeCapsSupport capsSupport; |
| 592 | 618 |
| 593 RunSegmenter::RunSegmenterRange segmentRange = { | 619 RunSegmenter::RunSegmenterRange segmentRange = { |
| 594 0, 0, USCRIPT_INVALID_CODE, OrientationIterator::OrientationInvalid, | 620 0, 0, USCRIPT_INVALID_CODE, OrientationIterator::OrientationInvalid, |
| 595 FontFallbackPriority::Invalid}; | 621 FontFallbackPriority::Invalid}; |
| 596 RunSegmenter runSegmenter(m_normalizedBuffer.get(), m_normalizedBufferLength, | 622 RunSegmenter runSegmenter(m_normalizedBuffer.get(), m_normalizedBufferLength, |
| 597 m_font->getFontDescription().orientation()); | 623 font->getFontDescription().orientation()); |
| 598 | 624 |
| 599 Vector<UChar32> fallbackCharsHint; | 625 Vector<UChar32> fallbackCharsHint; |
| 600 | 626 |
| 601 // TODO: Check whether this treatAsZerowidthspace from the previous script | 627 // TODO: Check whether this treatAsZerowidthspace from the previous script |
| 602 // segmentation plays a role here, does the new scriptRuniterator handle that | 628 // segmentation plays a role here, does the new scriptRuniterator handle that |
| 603 // correctly? | 629 // correctly? |
| 630 Deque<HolesQueueItem> holesQueue; |
| 604 while (runSegmenter.consume(&segmentRange)) { | 631 while (runSegmenter.consume(&segmentRange)) { |
| 605 RefPtr<FontFallbackIterator> fallbackIterator = | 632 RefPtr<FontFallbackIterator> fallbackIterator = |
| 606 m_font->createFontFallbackIterator(segmentRange.fontFallbackPriority); | 633 font->createFontFallbackIterator(segmentRange.fontFallbackPriority); |
| 607 | 634 |
| 608 appendToHolesQueue(HolesQueueNextFont, 0, 0); | 635 holesQueue.append(HolesQueueItem(HolesQueueNextFont, 0, 0)); |
| 609 appendToHolesQueue(HolesQueueRange, segmentRange.start, | 636 holesQueue.append(HolesQueueItem(HolesQueueRange, segmentRange.start, |
| 610 segmentRange.end - segmentRange.start); | 637 segmentRange.end - segmentRange.start)); |
| 611 | 638 |
| 612 RefPtr<FontDataForRangeSet> currentFontDataForRangeSet; | 639 RefPtr<FontDataForRangeSet> currentFontDataForRangeSet; |
| 613 | 640 |
| 614 bool fontCycleQueued = false; | 641 bool fontCycleQueued = false; |
| 615 while (m_holesQueue.size()) { | 642 while (holesQueue.size()) { |
| 616 HolesQueueItem currentQueueItem = m_holesQueue.takeFirst(); | 643 HolesQueueItem currentQueueItem = holesQueue.takeFirst(); |
| 617 | 644 |
| 618 if (currentQueueItem.m_action == HolesQueueNextFont) { | 645 if (currentQueueItem.m_action == HolesQueueNextFont) { |
| 619 // For now, we're building a character list with which we probe | 646 // For now, we're building a character list with which we probe |
| 620 // for needed fonts depending on the declared unicode-range of a | 647 // for needed fonts depending on the declared unicode-range of a |
| 621 // segmented CSS font. Alternatively, we can build a fake font | 648 // segmented CSS font. Alternatively, we can build a fake font |
| 622 // for the shaper and check whether any glyphs were found, or | 649 // for the shaper and check whether any glyphs were found, or |
| 623 // define a new API on the shaper which will give us coverage | 650 // define a new API on the shaper which will give us coverage |
| 624 // information? | 651 // information? |
| 625 if (!collectFallbackHintChars(fallbackCharsHint)) { | 652 if (!collectFallbackHintChars(holesQueue, fallbackCharsHint)) { |
| 626 // Give up shaping since we cannot retrieve a font fallback | 653 // Give up shaping since we cannot retrieve a font fallback |
| 627 // font without a hintlist. | 654 // font without a hintlist. |
| 628 m_holesQueue.clear(); | 655 holesQueue.clear(); |
| 629 break; | 656 break; |
| 630 } | 657 } |
| 631 | 658 |
| 632 currentFontDataForRangeSet = fallbackIterator->next(fallbackCharsHint); | 659 currentFontDataForRangeSet = fallbackIterator->next(fallbackCharsHint); |
| 633 | 660 |
| 634 if (!currentFontDataForRangeSet->fontData()) { | 661 if (!currentFontDataForRangeSet->fontData()) { |
| 635 ASSERT(!m_holesQueue.size()); | 662 DCHECK(!holesQueue.size()); |
| 636 break; | 663 break; |
| 637 } | 664 } |
| 638 fontCycleQueued = false; | 665 fontCycleQueued = false; |
| 639 continue; | 666 continue; |
| 640 } | 667 } |
| 641 | 668 |
| 642 SmallCapsIterator::SmallCapsBehavior smallCapsBehavior = | 669 SmallCapsIterator::SmallCapsBehavior smallCapsBehavior = |
| 643 SmallCapsIterator::SmallCapsSameCase; | 670 SmallCapsIterator::SmallCapsSameCase; |
| 644 if (needsCapsHandling) { | 671 if (needsCapsHandling) { |
| 645 capsSupport = | 672 capsSupport = |
| 646 OpenTypeCapsSupport(currentFontDataForRangeSet->fontData() | 673 OpenTypeCapsSupport(currentFontDataForRangeSet->fontData() |
| 647 ->platformData() | 674 ->platformData() |
| 648 .harfBuzzFace(), | 675 .harfBuzzFace(), |
| 649 fontDescription.variantCaps(), | 676 fontDescription.variantCaps(), |
| 650 ICUScriptToHBScript(segmentRange.script)); | 677 ICUScriptToHBScript(segmentRange.script)); |
| 651 if (capsSupport.needsRunCaseSplitting()) | 678 if (capsSupport.needsRunCaseSplitting()) { |
| 652 splitUntilNextCaseChange(currentQueueItem, smallCapsBehavior); | 679 splitUntilNextCaseChange(m_normalizedBuffer.get(), &holesQueue, |
| 680 currentQueueItem, smallCapsBehavior); |
| 681 } |
| 653 } | 682 } |
| 654 | 683 |
| 655 ASSERT(currentQueueItem.m_numCharacters); | 684 ASSERT(currentQueueItem.m_numCharacters); |
| 656 | 685 |
| 657 const SimpleFontData* smallcapsAdjustedFont = | 686 const SimpleFontData* smallcapsAdjustedFont = |
| 658 needsCapsHandling && capsSupport.needsSyntheticFont(smallCapsBehavior) | 687 needsCapsHandling && capsSupport.needsSyntheticFont(smallCapsBehavior) |
| 659 ? currentFontDataForRangeSet->fontData() | 688 ? currentFontDataForRangeSet->fontData() |
| 660 ->smallCapsFontData(fontDescription) | 689 ->smallCapsFontData(fontDescription) |
| 661 .get() | 690 .get() |
| 662 : currentFontDataForRangeSet->fontData(); | 691 : currentFontDataForRangeSet->fontData(); |
| 663 | 692 |
| 664 // Compatibility with SimpleFontData approach of keeping a flag for | 693 // Compatibility with SimpleFontData approach of keeping a flag for |
| 665 // overriding drawing direction. | 694 // overriding drawing direction. |
| 666 // TODO: crbug.com/506224 This should go away in favor of storing that | 695 // TODO: crbug.com/506224 This should go away in favor of storing that |
| 667 // information elsewhere, for example in ShapeResult. | 696 // information elsewhere, for example in ShapeResult. |
| 668 const SimpleFontData* directionAndSmallCapsAdjustedFont = | 697 const SimpleFontData* directionAndSmallCapsAdjustedFont = |
| 669 fontDataAdjustedForOrientation( | 698 fontDataAdjustedForOrientation( |
| 670 smallcapsAdjustedFont, m_font->getFontDescription().orientation(), | 699 smallcapsAdjustedFont, font->getFontDescription().orientation(), |
| 671 segmentRange.renderOrientation); | 700 segmentRange.renderOrientation); |
| 672 | 701 |
| 673 CaseMapIntend caseMapIntend = CaseMapIntend::KeepSameCase; | 702 CaseMapIntend caseMapIntend = CaseMapIntend::KeepSameCase; |
| 674 if (needsCapsHandling) { | 703 if (needsCapsHandling) { |
| 675 caseMapIntend = capsSupport.needsCaseChange(smallCapsBehavior); | 704 caseMapIntend = capsSupport.needsCaseChange(smallCapsBehavior); |
| 676 } | 705 } |
| 677 | 706 |
| 678 CaseMappingHarfBuzzBufferFiller( | 707 CaseMappingHarfBuzzBufferFiller( |
| 679 caseMapIntend, fontDescription.localeOrDefault(), | 708 caseMapIntend, fontDescription.localeOrDefault(), |
| 680 harfBuzzBuffer.get(), m_normalizedBuffer.get(), | 709 harfBuzzBuffer.get(), m_normalizedBuffer.get(), |
| 681 m_normalizedBufferLength, currentQueueItem.m_startIndex, | 710 m_normalizedBufferLength, currentQueueItem.m_startIndex, |
| 682 currentQueueItem.m_numCharacters); | 711 currentQueueItem.m_numCharacters); |
| 683 | 712 |
| 684 CapsFeatureSettingsScopedOverlay capsOverlay( | 713 CapsFeatureSettingsScopedOverlay capsOverlay( |
| 685 m_features, capsSupport.fontFeatureToUse(smallCapsBehavior)); | 714 &fontFeatures, capsSupport.fontFeatureToUse(smallCapsBehavior)); |
| 686 | 715 |
| 687 if (!shapeRange(harfBuzzBuffer.get(), directionAndSmallCapsAdjustedFont, | 716 if (!shapeRange(harfBuzzBuffer.get(), font, fontFeatures, |
| 717 directionAndSmallCapsAdjustedFont, |
| 688 currentFontDataForRangeSet->ranges(), segmentRange.script, | 718 currentFontDataForRangeSet->ranges(), segmentRange.script, |
| 689 language)) | 719 language)) |
| 690 DLOG(ERROR) << "Shaping range failed."; | 720 DLOG(ERROR) << "Shaping range failed."; |
| 691 | 721 |
| 692 if (!extractShapeResults( | 722 if (!extractShapeResults( |
| 693 harfBuzzBuffer.get(), result.get(), fontCycleQueued, | 723 harfBuzzBuffer.get(), result.get(), fontCycleQueued, &holesQueue, |
| 694 currentQueueItem, directionAndSmallCapsAdjustedFont, | 724 currentQueueItem, font, directionAndSmallCapsAdjustedFont, |
| 695 segmentRange.script, !fallbackIterator->hasNext())) | 725 segmentRange.script, !fallbackIterator->hasNext())) |
| 696 DLOG(ERROR) << "Shape result extraction failed."; | 726 DLOG(ERROR) << "Shape result extraction failed."; |
| 697 | 727 |
| 698 hb_buffer_reset(harfBuzzBuffer.get()); | 728 hb_buffer_reset(harfBuzzBuffer.get()); |
| 699 } | 729 } |
| 700 } | 730 } |
| 701 return result.release(); | 731 return result.release(); |
| 702 } | 732 } |
| 703 | 733 |
| 704 } // namespace blink | 734 } // namespace blink |
| OLD | NEW |