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#if SK_HAS_DWRITE_1_H 30# include <dwrite_1.h> 31#endif 32 33static bool isLCD(const SkScalerContext::Rec& rec) { 34 return SkMask::kLCD16_Format == rec.fMaskFormat || 35 SkMask::kLCD32_Format == rec.fMaskFormat; 36} 37 38static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { 39 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get()); 40 if (!maxp.fExists) { 41 return false; 42 } 43 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) { 44 return false; 45 } 46 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) { 47 return false; 48 } 49 50 if (0 == maxp->version.tt.maxSizeOfInstructions) { 51 // No hints. 52 return false; 53 } 54 55 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 56 return !gasp.fExists; 57} 58 59/** A PPEMRange is inclusive, [min, max]. */ 60struct PPEMRange { 61 int min; 62 int max; 63}; 64 65/** If the rendering mode for the specified 'size' is gridfit, then place 66 * the gridfit range into 'range'. Otherwise, leave 'range' alone. 67 */ 68static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) { 69 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 70 if (!gasp.fExists) { 71 return; 72 } 73 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { 74 return; 75 } 76 if (gasp->version != SkOTTableGridAndScanProcedure::version0 && 77 gasp->version != SkOTTableGridAndScanProcedure::version1) 78 { 79 return; 80 } 81 82 uint16_t numRanges = SkEndianSwap16(gasp->numRanges); 83 if (numRanges > 1024 || 84 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + 85 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges) 86 { 87 return; 88 } 89 90 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = 91 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get()); 92 int minPPEM = -1; 93 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { 94 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); 95 // Test that the size is in range and the range is gridfit only. 96 if (minPPEM < size && size <= maxPPEM && 97 rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask) 98 { 99 range->min = minPPEM + 1; 100 range->max = maxPPEM; 101 return; 102 } 103 minPPEM = maxPPEM; 104 } 105} 106 107static 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 181static 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 186static 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 192SkScalerContext_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 336SkScalerContext_DW::~SkScalerContext_DW() { 337} 338 339unsigned SkScalerContext_DW::generateGlyphCount() { 340 if (fGlyphCount < 0) { 341 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount(); 342 } 343 return fGlyphCount; 344} 345 346uint16_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 352void 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 403HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, 404 DWRITE_RENDERING_MODE renderingMode, 405 DWRITE_TEXTURE_TYPE textureType, 406 RECT* bbox) 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 HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( 432 &run, 433 1.0f, // pixelsPerDip, 434 &fXform, 435 renderingMode, 436 fMeasuringMode, 437 0.0f, // baselineOriginX, 438 0.0f, // baselineOriginY, 439 &glyphRunAnalysis), 440 "Could not create glyph run analysis."); 441 442 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), 443 "Could not get texture bounds."); 444 445 return S_OK; 446} 447 448/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like 449 * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } 450 * for small, but not quite zero, sized glyphs. 451 * Only set as non-empty if the returned bounds are non-empty. 452 */ 453static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { 454 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { 455 return false; 456 } 457 glyph->fWidth = SkToU16(bbox.right - bbox.left); 458 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); 459 glyph->fLeft = SkToS16(bbox.left); 460 glyph->fTop = SkToS16(bbox.top); 461 return true; 462} 463 464void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { 465 glyph->fWidth = 0; 466 glyph->fHeight = 0; 467 glyph->fLeft = 0; 468 glyph->fTop = 0; 469 470 this->generateAdvance(glyph); 471 472 RECT bbox; 473 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), 474 "Requested bounding box could not be determined."); 475 476 if (glyph_check_and_set_bounds(glyph, bbox)) { 477 return; 478 } 479 480 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no 481 // glyphs of the specified texture type. When this happens, try with the 482 // alternate texture type. 483 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) { 484 HRVM(this->getBoundingBox(glyph, 485 DWRITE_RENDERING_MODE_ALIASED, 486 DWRITE_TEXTURE_ALIASED_1x1, 487 &bbox), 488 "Fallback bounding box could not be determined."); 489 if (glyph_check_and_set_bounds(glyph, bbox)) { 490 glyph->fForceBW = 1; 491 } 492 } 493 // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1 494 // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1. 495} 496 497void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { 498 if (NULL == metrics) { 499 return; 500 } 501 502 sk_bzero(metrics, sizeof(*metrics)); 503 504 DWRITE_FONT_METRICS dwfm; 505 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 506 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 507 { 508 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics( 509 fTextSizeRender, 510 1.0f, // pixelsPerDip 511 &fXform, 512 &dwfm); 513 } else { 514 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); 515 } 516 517 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); 518 519 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 520 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 521 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 522 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 523 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 524 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 525 526 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; 527 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 528 529#if SK_HAS_DWRITE_1_H 530 if (fTypeface->fDWriteFontFace1.get()) { 531 DWRITE_FONT_METRICS1 dwfm1; 532 fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1); 533 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; 534 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; 535 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; 536 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; 537 538 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 539 return; 540 } 541#else 542# pragma message("No dwrite_1.h is available, font metrics may be affected.") 543#endif 544 545 AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get()); 546 if (head.fExists && 547 head.fSize >= sizeof(SkOTTableHead) && 548 head->version == SkOTTableHead::version1) 549 { 550 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; 551 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; 552 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; 553 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; 554 555 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 556 return; 557 } 558 559 metrics->fTop = metrics->fAscent; 560 metrics->fBottom = metrics->fDescent; 561} 562 563/////////////////////////////////////////////////////////////////////////////// 564 565#include "SkColorPriv.h" 566 567static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { 568 const int width = glyph.fWidth; 569 const size_t dstRB = (width + 7) >> 3; 570 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 571 572 int byteCount = width >> 3; 573 int bitCount = width & 7; 574 575 for (int y = 0; y < glyph.fHeight; ++y) { 576 if (byteCount > 0) { 577 for (int i = 0; i < byteCount; ++i) { 578 unsigned byte = 0; 579 byte |= src[0] & (1 << 7); 580 byte |= src[1] & (1 << 6); 581 byte |= src[2] & (1 << 5); 582 byte |= src[3] & (1 << 4); 583 byte |= src[4] & (1 << 3); 584 byte |= src[5] & (1 << 2); 585 byte |= src[6] & (1 << 1); 586 byte |= src[7] & (1 << 0); 587 dst[i] = byte; 588 src += 8; 589 } 590 } 591 if (bitCount > 0) { 592 unsigned byte = 0; 593 unsigned mask = 0x80; 594 for (int i = 0; i < bitCount; i++) { 595 byte |= (src[i]) & mask; 596 mask >>= 1; 597 } 598 dst[byteCount] = byte; 599 } 600 src += bitCount; 601 dst += dstRB; 602 } 603} 604 605template<bool APPLY_PREBLEND> 606static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { 607 const size_t dstRB = glyph.rowBytes(); 608 const U16CPU width = glyph.fWidth; 609 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 610 611 for (U16CPU y = 0; y < glyph.fHeight; y++) { 612 for (U16CPU i = 0; i < width; i++) { 613 U8CPU r = *(src++); 614 U8CPU g = *(src++); 615 U8CPU b = *(src++); 616 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8); 617 } 618 dst = (uint8_t*)((char*)dst + dstRB); 619 } 620} 621 622template<bool APPLY_PREBLEND> 623static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 624 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 625 const size_t dstRB = glyph.rowBytes(); 626 const U16CPU width = glyph.fWidth; 627 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage); 628 629 for (U16CPU y = 0; y < glyph.fHeight; y++) { 630 for (U16CPU i = 0; i < width; i++) { 631 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 632 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 633 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 634 dst[i] = SkPack888ToRGB16(r, g, b); 635 } 636 dst = (uint16_t*)((char*)dst + dstRB); 637 } 638} 639 640template<bool APPLY_PREBLEND> 641static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 642 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 643 const size_t dstRB = glyph.rowBytes(); 644 const U16CPU width = glyph.fWidth; 645 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage); 646 647 for (U16CPU y = 0; y < glyph.fHeight; y++) { 648 for (U16CPU i = 0; i < width; i++) { 649 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 650 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 651 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 652 dst[i] = SkPackARGB32(0xFF, r, g, b); 653 } 654 dst = (SkPMColor*)((char*)dst + dstRB); 655 } 656} 657 658const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, 659 DWRITE_RENDERING_MODE renderingMode, 660 DWRITE_TEXTURE_TYPE textureType) 661{ 662 int sizeNeeded = glyph.fWidth * glyph.fHeight; 663 if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) { 664 sizeNeeded *= 3; 665 } 666 if (sizeNeeded > fBits.count()) { 667 fBits.setCount(sizeNeeded); 668 } 669 670 // erase 671 memset(fBits.begin(), 0, sizeNeeded); 672 673 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 674 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 675 676 FLOAT advance = 0.0f; 677 678 UINT16 index = glyph.getGlyphID(); 679 680 DWRITE_GLYPH_OFFSET offset; 681 offset.advanceOffset = 0.0f; 682 offset.ascenderOffset = 0.0f; 683 684 DWRITE_GLYPH_RUN run; 685 run.glyphCount = 1; 686 run.glyphAdvances = &advance; 687 run.fontFace = fTypeface->fDWriteFontFace.get(); 688 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 689 run.bidiLevel = 0; 690 run.glyphIndices = &index; 691 run.isSideways = FALSE; 692 run.glyphOffsets = &offset; 693 694 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 695 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, 696 1.0f, // pixelsPerDip, 697 &fXform, 698 renderingMode, 699 fMeasuringMode, 700 0.0f, // baselineOriginX, 701 0.0f, // baselineOriginY, 702 &glyphRunAnalysis), 703 "Could not create glyph run analysis."); 704 705 //NOTE: this assumes that the glyph has already been measured 706 //with an exact same glyph run analysis. 707 RECT bbox; 708 bbox.left = glyph.fLeft; 709 bbox.top = glyph.fTop; 710 bbox.right = glyph.fLeft + glyph.fWidth; 711 bbox.bottom = glyph.fTop + glyph.fHeight; 712 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, 713 &bbox, 714 fBits.begin(), 715 sizeNeeded), 716 "Could not draw mask."); 717 return fBits.begin(); 718} 719 720void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { 721 //Create the mask. 722 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; 723 DWRITE_TEXTURE_TYPE textureType = fTextureType; 724 if (glyph.fForceBW) { 725 renderingMode = DWRITE_RENDERING_MODE_ALIASED; 726 textureType = DWRITE_TEXTURE_ALIASED_1x1; 727 } 728 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); 729 if (!bits) { 730 sk_bzero(glyph.fImage, glyph.computeImageSize()); 731 return; 732 } 733 734 //Copy the mask into the glyph. 735 const uint8_t* src = (const uint8_t*)bits; 736 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { 737 bilevel_to_bw(src, glyph); 738 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; 739 } else if (!isLCD(fRec)) { 740 if (fPreBlend.isApplicable()) { 741 rgb_to_a8<true>(src, glyph, fPreBlend.fG); 742 } else { 743 rgb_to_a8<false>(src, glyph, fPreBlend.fG); 744 } 745 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { 746 if (fPreBlend.isApplicable()) { 747 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 748 } else { 749 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 750 } 751 } else { 752 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); 753 if (fPreBlend.isApplicable()) { 754 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 755 } else { 756 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 757 } 758 } 759} 760 761void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { 762 SkASSERT(&glyph && path); 763 764 path->reset(); 765 766 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 767 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), 768 "Could not create geometry to path converter."); 769 uint16_t glyphId = glyph.getGlyphID(); 770 //TODO: convert to<->from DIUs? This would make a difference if hinting. 771 //It may not be needed, it appears that DirectWrite only hints at em size. 772 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), 773 &glyphId, 774 NULL, //advances 775 NULL, //offsets 776 1, //num glyphs 777 FALSE, //sideways 778 FALSE, //rtl 779 geometryToPath.get()), 780 "Could not create glyph outline."); 781 782 path->transform(fSkXform); 783} 784