1/* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkTypes.h" 9#if defined(SK_BUILD_FOR_WIN32) 10 11#undef GetGlyphIndices 12 13#include "SkDWrite.h" 14#include "SkDWriteGeometrySink.h" 15#include "SkEndian.h" 16#include "SkGlyph.h" 17#include "SkHRESULT.h" 18#include "SkMaskGamma.h" 19#include "SkMatrix22.h" 20#include "SkMutex.h" 21#include "SkOTTable_EBLC.h" 22#include "SkOTTable_EBSC.h" 23#include "SkOTTable_gasp.h" 24#include "SkOTTable_maxp.h" 25#include "SkPath.h" 26#include "SkScalerContext.h" 27#include "SkScalerContext_win_dw.h" 28#include "SkSharedMutex.h" 29#include "SkTScopedComPtr.h" 30#include "SkTypeface_win_dw.h" 31 32#include <dwrite.h> 33#if SK_HAS_DWRITE_1_H 34# include <dwrite_1.h> 35#endif 36 37/* Note: 38 * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe. 39 * The DWriteFactoryMutex protects the calls that are problematic. 40 */ 41static SkSharedMutex DWriteFactoryMutex; 42 43typedef SkAutoTExclusive<SkSharedMutex> Exclusive; 44typedef SkAutoSharedMutexShared Shared; 45 46static bool isLCD(const SkScalerContext::Rec& rec) { 47 return SkMask::kLCD16_Format == rec.fMaskFormat; 48} 49 50static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { 51 Exclusive l(DWriteFactoryMutex); 52 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get()); 53 if (!maxp.fExists) { 54 return false; 55 } 56 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) { 57 return false; 58 } 59 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) { 60 return false; 61 } 62 63 if (0 == maxp->version.tt.maxSizeOfInstructions) { 64 // No hints. 65 return false; 66 } 67 68 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 69 return !gasp.fExists; 70} 71 72/** A PPEMRange is inclusive, [min, max]. */ 73struct PPEMRange { 74 int min; 75 int max; 76}; 77 78/** If the rendering mode for the specified 'size' is gridfit, then place 79 * the gridfit range into 'range'. Otherwise, leave 'range' alone. 80 */ 81static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) { 82 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 83 if (!gasp.fExists) { 84 return; 85 } 86 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { 87 return; 88 } 89 if (gasp->version != SkOTTableGridAndScanProcedure::version0 && 90 gasp->version != SkOTTableGridAndScanProcedure::version1) 91 { 92 return; 93 } 94 95 uint16_t numRanges = SkEndianSwap16(gasp->numRanges); 96 if (numRanges > 1024 || 97 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + 98 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges) 99 { 100 return; 101 } 102 103 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = 104 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get()); 105 int minPPEM = -1; 106 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { 107 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); 108 // Test that the size is in range and the range is gridfit only. 109 if (minPPEM < size && size <= maxPPEM && 110 rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask) 111 { 112 range->min = minPPEM + 1; 113 range->max = maxPPEM; 114 return; 115 } 116 minPPEM = maxPPEM; 117 } 118} 119 120static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { 121 Exclusive l(DWriteFactoryMutex); 122 { 123 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get()); 124 if (!eblc.fExists) { 125 return false; 126 } 127 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { 128 return false; 129 } 130 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { 131 return false; 132 } 133 134 uint32_t numSizes = SkEndianSwap32(eblc->numSizes); 135 if (numSizes > 1024 || 136 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) + 137 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes) 138 { 139 return false; 140 } 141 142 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable = 143 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get()); 144 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { 145 if (sizeTable->ppemX == sizeTable->ppemY && 146 range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max) 147 { 148 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable 149 // to determine the actual number of glyphs with bitmaps. 150 151 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike. 152 153 // TODO: Ensure that the bitmaps are bi-level? 154 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) { 155 return true; 156 } 157 } 158 } 159 } 160 161 { 162 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get()); 163 if (!ebsc.fExists) { 164 return false; 165 } 166 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) { 167 return false; 168 } 169 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) { 170 return false; 171 } 172 173 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes); 174 if (numSizes > 1024 || 175 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) + 176 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes) 177 { 178 return false; 179 } 180 181 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable = 182 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get()); 183 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { 184 if (scaleTable->ppemX == scaleTable->ppemY && 185 range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) { 186 // EBSC tables are normally only found in bitmap only fonts. 187 return true; 188 } 189 } 190 } 191 192 return false; 193} 194 195static bool both_zero(SkScalar a, SkScalar b) { 196 return 0 == a && 0 == b; 197} 198 199// returns false if there is any non-90-rotation or skew 200static bool is_axis_aligned(const SkScalerContext::Rec& rec) { 201 return 0 == rec.fPreSkewX && 202 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || 203 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); 204} 205 206SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, 207 const SkDescriptor* desc) 208 : SkScalerContext(typeface, desc) 209 , fTypeface(SkRef(typeface)) 210 , fGlyphCount(-1) { 211 212 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC 213 // except when bi-level rendering is requested or there are embedded 214 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). 215 // 216 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do 217 // this. As a result, determine the actual size of the text and then see if 218 // there are any embedded bi-level bitmaps of that size. If there are, then 219 // force bitmaps by requesting bi-level rendering. 220 // 221 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes 222 // square pixels and only uses ppemY. Therefore the transform must track any 223 // non-uniform x-scale. 224 // 225 // Also, rotated glyphs should have the same absolute advance widths as 226 // horizontal glyphs and the subpixel flag should not affect glyph shapes. 227 228 SkVector scale; 229 SkMatrix GsA; 230 fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, 231 &scale, &fSkXform, &GsA, &fG_inv); 232 233 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX()); 234 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY()); 235 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX()); 236 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY()); 237 fXform.dx = 0; 238 fXform.dy = 0; 239 240 fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX)); 241 fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0. 242 fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX)); 243 fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY)); 244 fGsA.dx = 0; 245 fGsA.dy = 0; 246 247 // realTextSize is the actual device size we want (as opposed to the size the user requested). 248 // gdiTextSize is the size we request when GDI compatible. 249 // If the scale is negative, this means the matrix will do the flip anyway. 250 const SkScalar realTextSize = scale.fY; 251 // Due to floating point math, the lower bits are suspect. Round carefully. 252 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f; 253 if (gdiTextSize == 0) { 254 gdiTextSize = SK_Scalar1; 255 } 256 257 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag); 258 bool treatLikeBitmap = false; 259 bool axisAlignedBitmap = false; 260 if (bitmapRequested) { 261 // When embedded bitmaps are requested, treat the entire range like 262 // a bitmap strike if the range is gridfit only and contains a bitmap. 263 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize); 264 PPEMRange range = { bitmapPPEM, bitmapPPEM }; 265 expand_range_if_gridfit_only(typeface, bitmapPPEM, &range); 266 treatLikeBitmap = has_bitmap_strike(typeface, range); 267 268 axisAlignedBitmap = is_axis_aligned(fRec); 269 } 270 271 // If the user requested aliased, do so with aliased compatible metrics. 272 if (SkMask::kBW_Format == fRec.fMaskFormat) { 273 fTextSizeRender = gdiTextSize; 274 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; 275 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; 276 fTextSizeMeasure = gdiTextSize; 277 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 278 279 // If we can use a bitmap, use gdi classic rendering and measurement. 280 // This will not always provide a bitmap, but matches expected behavior. 281 } else if (treatLikeBitmap && axisAlignedBitmap) { 282 fTextSizeRender = gdiTextSize; 283 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; 284 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 285 fTextSizeMeasure = gdiTextSize; 286 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 287 288 // If rotated but the horizontal text could have used a bitmap, 289 // render high quality rotated glyphs but measure using bitmap metrics. 290 } else if (treatLikeBitmap) { 291 fTextSizeRender = gdiTextSize; 292 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; 293 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 294 fTextSizeMeasure = gdiTextSize; 295 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 296 297 // Fonts that have hints but no gasp table get non-symmetric rendering. 298 // Usually such fonts have low quality hints which were never tested 299 // with anything but GDI ClearType classic. Such fonts often rely on 300 // drop out control in the y direction in order to be legible. 301 } else if (is_hinted_without_gasp(typeface)) { 302 fTextSizeRender = gdiTextSize; 303 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; 304 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 305 fTextSizeMeasure = realTextSize; 306 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 307 308 // The normal case is to use natural symmetric rendering and linear metrics. 309 } else { 310 fTextSizeRender = realTextSize; 311 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; 312 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 313 fTextSizeMeasure = realTextSize; 314 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 315 } 316 317 if (this->isSubpixel()) { 318 fTextSizeMeasure = realTextSize; 319 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 320 } 321} 322 323SkScalerContext_DW::~SkScalerContext_DW() { 324} 325 326unsigned SkScalerContext_DW::generateGlyphCount() { 327 if (fGlyphCount < 0) { 328 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount(); 329 } 330 return fGlyphCount; 331} 332 333uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) { 334 uint16_t index = 0; 335 fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index); 336 return index; 337} 338 339void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { 340 //Delta is the difference between the right/left side bearing metric 341 //and where the right/left side bearing ends up after hinting. 342 //DirectWrite does not provide this information. 343 glyph->fRsbDelta = 0; 344 glyph->fLsbDelta = 0; 345 346 glyph->fAdvanceX = 0; 347 glyph->fAdvanceY = 0; 348 349 uint16_t glyphId = glyph->getGlyphID(); 350 DWRITE_GLYPH_METRICS gm; 351 352 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 353 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 354 { 355 Exclusive l(DWriteFactoryMutex); 356 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( 357 fTextSizeMeasure, 358 1.0f, // pixelsPerDip 359 &fGsA, 360 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, 361 &glyphId, 1, 362 &gm), 363 "Could not get gdi compatible glyph metrics."); 364 } else { 365 Exclusive l(DWriteFactoryMutex); 366 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), 367 "Could not get design metrics."); 368 } 369 370 DWRITE_FONT_METRICS dwfm; 371 { 372 Shared l(DWriteFactoryMutex); 373 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); 374 } 375 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, 376 SkIntToScalar(gm.advanceWidth), 377 SkIntToScalar(dwfm.designUnitsPerEm)); 378 379 SkVector vecs[1] = { { advanceX, 0 } }; 380 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 381 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 382 { 383 // DirectWrite produced 'compatible' metrics, but while close, 384 // the end result is not always an integer as it would be with GDI. 385 vecs[0].fX = SkScalarRoundToScalar(advanceX); 386 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); 387 } else { 388 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); 389 } 390 391 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX); 392 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY); 393} 394 395HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, 396 DWRITE_RENDERING_MODE renderingMode, 397 DWRITE_TEXTURE_TYPE textureType, 398 RECT* bbox) 399{ 400 //Measure raster size. 401 fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); 402 fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); 403 404 FLOAT advance = 0; 405 406 UINT16 glyphId = glyph->getGlyphID(); 407 408 DWRITE_GLYPH_OFFSET offset; 409 offset.advanceOffset = 0.0f; 410 offset.ascenderOffset = 0.0f; 411 412 DWRITE_GLYPH_RUN run; 413 run.glyphCount = 1; 414 run.glyphAdvances = &advance; 415 run.fontFace = fTypeface->fDWriteFontFace.get(); 416 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 417 run.bidiLevel = 0; 418 run.glyphIndices = &glyphId; 419 run.isSideways = FALSE; 420 run.glyphOffsets = &offset; 421 422 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 423 { 424 Exclusive l(DWriteFactoryMutex); 425 HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( 426 &run, 427 1.0f, // pixelsPerDip, 428 &fXform, 429 renderingMode, 430 fMeasuringMode, 431 0.0f, // baselineOriginX, 432 0.0f, // baselineOriginY, 433 &glyphRunAnalysis), 434 "Could not create glyph run analysis."); 435 } 436 { 437 Shared l(DWriteFactoryMutex); 438 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), 439 "Could not get texture bounds."); 440 } 441 return S_OK; 442} 443 444/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like 445 * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } 446 * for small, but not quite zero, sized glyphs. 447 * Only set as non-empty if the returned bounds are non-empty. 448 */ 449static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { 450 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { 451 return false; 452 } 453 glyph->fWidth = SkToU16(bbox.right - bbox.left); 454 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); 455 glyph->fLeft = SkToS16(bbox.left); 456 glyph->fTop = SkToS16(bbox.top); 457 return true; 458} 459 460void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { 461 glyph->fWidth = 0; 462 glyph->fHeight = 0; 463 glyph->fLeft = 0; 464 glyph->fTop = 0; 465 466 this->generateAdvance(glyph); 467 468 RECT bbox; 469 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), 470 "Requested bounding box could not be determined."); 471 472 if (glyph_check_and_set_bounds(glyph, bbox)) { 473 return; 474 } 475 476 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no 477 // glyphs of the specified texture type. When this happens, try with the 478 // alternate texture type. 479 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) { 480 HRVM(this->getBoundingBox(glyph, 481 DWRITE_RENDERING_MODE_ALIASED, 482 DWRITE_TEXTURE_ALIASED_1x1, 483 &bbox), 484 "Fallback bounding box could not be determined."); 485 if (glyph_check_and_set_bounds(glyph, bbox)) { 486 glyph->fForceBW = 1; 487 } 488 } 489 // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1 490 // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1. 491} 492 493void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { 494 if (nullptr == metrics) { 495 return; 496 } 497 498 sk_bzero(metrics, sizeof(*metrics)); 499 500 DWRITE_FONT_METRICS dwfm; 501 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 502 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 503 { 504 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics( 505 fTextSizeRender, 506 1.0f, // pixelsPerDip 507 &fXform, 508 &dwfm); 509 } else { 510 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); 511 } 512 513 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); 514 515 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 516 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 517 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 518 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 519 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 520 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 521 522 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; 523 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 524 525#if SK_HAS_DWRITE_1_H 526 if (fTypeface->fDWriteFontFace1.get()) { 527 DWRITE_FONT_METRICS1 dwfm1; 528 fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1); 529 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; 530 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; 531 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; 532 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; 533 534 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 535 return; 536 } 537#else 538# pragma message("No dwrite_1.h is available, font metrics may be affected.") 539#endif 540 541 AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get()); 542 if (head.fExists && 543 head.fSize >= sizeof(SkOTTableHead) && 544 head->version == SkOTTableHead::version1) 545 { 546 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; 547 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; 548 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; 549 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; 550 551 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 552 return; 553 } 554 555 metrics->fTop = metrics->fAscent; 556 metrics->fBottom = metrics->fDescent; 557} 558 559/////////////////////////////////////////////////////////////////////////////// 560 561#include "SkColorPriv.h" 562 563static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { 564 const int width = glyph.fWidth; 565 const size_t dstRB = (width + 7) >> 3; 566 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 567 568 int byteCount = width >> 3; 569 int bitCount = width & 7; 570 571 for (int y = 0; y < glyph.fHeight; ++y) { 572 if (byteCount > 0) { 573 for (int i = 0; i < byteCount; ++i) { 574 unsigned byte = 0; 575 byte |= src[0] & (1 << 7); 576 byte |= src[1] & (1 << 6); 577 byte |= src[2] & (1 << 5); 578 byte |= src[3] & (1 << 4); 579 byte |= src[4] & (1 << 3); 580 byte |= src[5] & (1 << 2); 581 byte |= src[6] & (1 << 1); 582 byte |= src[7] & (1 << 0); 583 dst[i] = byte; 584 src += 8; 585 } 586 } 587 if (bitCount > 0) { 588 unsigned byte = 0; 589 unsigned mask = 0x80; 590 for (int i = 0; i < bitCount; i++) { 591 byte |= (src[i]) & mask; 592 mask >>= 1; 593 } 594 dst[byteCount] = byte; 595 } 596 src += bitCount; 597 dst += dstRB; 598 } 599} 600 601template<bool APPLY_PREBLEND> 602static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { 603 const size_t dstRB = glyph.rowBytes(); 604 const U16CPU width = glyph.fWidth; 605 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 606 607 for (U16CPU y = 0; y < glyph.fHeight; y++) { 608 for (U16CPU i = 0; i < width; i++) { 609 U8CPU r = *(src++); 610 U8CPU g = *(src++); 611 U8CPU b = *(src++); 612 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8); 613 } 614 dst = (uint8_t*)((char*)dst + dstRB); 615 } 616} 617 618template<bool APPLY_PREBLEND, bool RGB> 619static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 620 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 621 const size_t dstRB = glyph.rowBytes(); 622 const U16CPU width = glyph.fWidth; 623 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage); 624 625 for (U16CPU y = 0; y < glyph.fHeight; y++) { 626 for (U16CPU i = 0; i < width; i++) { 627 U8CPU r, g, b; 628 if (RGB) { 629 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 630 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 631 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 632 } else { 633 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 634 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 635 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 636 } 637 dst[i] = SkPack888ToRGB16(r, g, b); 638 } 639 dst = (uint16_t*)((char*)dst + dstRB); 640 } 641} 642 643const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, 644 DWRITE_RENDERING_MODE renderingMode, 645 DWRITE_TEXTURE_TYPE textureType) 646{ 647 int sizeNeeded = glyph.fWidth * glyph.fHeight; 648 if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) { 649 sizeNeeded *= 3; 650 } 651 if (sizeNeeded > fBits.count()) { 652 fBits.setCount(sizeNeeded); 653 } 654 655 // erase 656 memset(fBits.begin(), 0, sizeNeeded); 657 658 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 659 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 660 661 FLOAT advance = 0.0f; 662 663 UINT16 index = glyph.getGlyphID(); 664 665 DWRITE_GLYPH_OFFSET offset; 666 offset.advanceOffset = 0.0f; 667 offset.ascenderOffset = 0.0f; 668 669 DWRITE_GLYPH_RUN run; 670 run.glyphCount = 1; 671 run.glyphAdvances = &advance; 672 run.fontFace = fTypeface->fDWriteFontFace.get(); 673 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 674 run.bidiLevel = 0; 675 run.glyphIndices = &index; 676 run.isSideways = FALSE; 677 run.glyphOffsets = &offset; 678 { 679 680 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 681 { 682 Exclusive l(DWriteFactoryMutex); 683 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, 684 1.0f, // pixelsPerDip, 685 &fXform, 686 renderingMode, 687 fMeasuringMode, 688 0.0f, // baselineOriginX, 689 0.0f, // baselineOriginY, 690 &glyphRunAnalysis), 691 "Could not create glyph run analysis."); 692 } 693 //NOTE: this assumes that the glyph has already been measured 694 //with an exact same glyph run analysis. 695 RECT bbox; 696 bbox.left = glyph.fLeft; 697 bbox.top = glyph.fTop; 698 bbox.right = glyph.fLeft + glyph.fWidth; 699 bbox.bottom = glyph.fTop + glyph.fHeight; 700 { 701 Shared l(DWriteFactoryMutex); 702 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, 703 &bbox, 704 fBits.begin(), 705 sizeNeeded), 706 "Could not draw mask."); 707 } 708 } 709 return fBits.begin(); 710} 711 712void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { 713 //Create the mask. 714 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; 715 DWRITE_TEXTURE_TYPE textureType = fTextureType; 716 if (glyph.fForceBW) { 717 renderingMode = DWRITE_RENDERING_MODE_ALIASED; 718 textureType = DWRITE_TEXTURE_ALIASED_1x1; 719 } 720 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); 721 if (!bits) { 722 sk_bzero(glyph.fImage, glyph.computeImageSize()); 723 return; 724 } 725 726 //Copy the mask into the glyph. 727 const uint8_t* src = (const uint8_t*)bits; 728 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { 729 bilevel_to_bw(src, glyph); 730 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; 731 } else if (!isLCD(fRec)) { 732 if (fPreBlend.isApplicable()) { 733 rgb_to_a8<true>(src, glyph, fPreBlend.fG); 734 } else { 735 rgb_to_a8<false>(src, glyph, fPreBlend.fG); 736 } 737 } else { 738 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat); 739 if (fPreBlend.isApplicable()) { 740 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 741 rgb_to_lcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 742 } else { 743 rgb_to_lcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 744 } 745 } else { 746 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 747 rgb_to_lcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 748 } else { 749 rgb_to_lcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 750 } 751 } 752 } 753} 754 755void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { 756 SkASSERT(path); 757 758 path->reset(); 759 760 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 761 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), 762 "Could not create geometry to path converter."); 763 uint16_t glyphId = glyph.getGlyphID(); 764 { 765 Exclusive l(DWriteFactoryMutex); 766 //TODO: convert to<->from DIUs? This would make a difference if hinting. 767 //It may not be needed, it appears that DirectWrite only hints at em size. 768 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), 769 &glyphId, 770 nullptr, //advances 771 nullptr, //offsets 772 1, //num glyphs 773 FALSE, //sideways 774 FALSE, //rtl 775 geometryToPath.get()), 776 "Could not create glyph outline."); 777 } 778 779 path->transform(fSkXform); 780} 781 782#endif//defined(SK_BUILD_FOR_WIN32) 783