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