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 31static bool isLCD(const SkScalerContext::Rec& rec) { 32 return SkMask::kLCD16_Format == rec.fMaskFormat || 33 SkMask::kLCD32_Format == rec.fMaskFormat; 34} 35 36static 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]. */ 58struct 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 */ 66static 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 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 if (!this->isSubpixel()) { 388 advanceX = SkScalarRoundToScalar(advanceX); 389 } 390 391 SkVector vecs[1] = { { advanceX, 0 } }; 392 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 393 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 394 { 395 // DirectWrite produced 'compatible' metrics, but while close, 396 // the end result is not always an integer as it would be with GDI. 397 vecs[0].fX = SkScalarRoundToScalar(advanceX); 398 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); 399 } else { 400 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); 401 } 402 403 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX); 404 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY); 405} 406 407void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { 408 glyph->fWidth = 0; 409 410 this->generateAdvance(glyph); 411 412 //Measure raster size. 413 fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); 414 fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); 415 416 FLOAT advance = 0; 417 418 UINT16 glyphId = glyph->getGlyphID(); 419 420 DWRITE_GLYPH_OFFSET offset; 421 offset.advanceOffset = 0.0f; 422 offset.ascenderOffset = 0.0f; 423 424 DWRITE_GLYPH_RUN run; 425 run.glyphCount = 1; 426 run.glyphAdvances = &advance; 427 run.fontFace = fTypeface->fDWriteFontFace.get(); 428 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 429 run.bidiLevel = 0; 430 run.glyphIndices = &glyphId; 431 run.isSideways = FALSE; 432 run.glyphOffsets = &offset; 433 434 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 435 HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis( 436 &run, 437 1.0f, // pixelsPerDip, 438 &fXform, 439 fRenderingMode, 440 fMeasuringMode, 441 0.0f, // baselineOriginX, 442 0.0f, // baselineOriginY, 443 &glyphRunAnalysis), 444 "Could not create glyph run analysis."); 445 446 RECT bbox; 447 HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox), 448 "Could not get texture bounds."); 449 450 glyph->fWidth = SkToU16(bbox.right - bbox.left); 451 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); 452 glyph->fLeft = SkToS16(bbox.left); 453 glyph->fTop = SkToS16(bbox.top); 454} 455 456void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx, 457 SkPaint::FontMetrics* my) { 458 if (!(mx || my)) 459 return; 460 461 if (mx) { 462 sk_bzero(mx, sizeof(*mx)); 463 } 464 if (my) { 465 sk_bzero(my, sizeof(*my)); 466 } 467 468 DWRITE_FONT_METRICS dwfm; 469 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 470 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 471 { 472 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics( 473 fTextSizeRender, 474 1.0f, // pixelsPerDip 475 &fXform, 476 &dwfm); 477 } else { 478 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); 479 } 480 481 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); 482 if (mx) { 483 mx->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 484 mx->fAscent = mx->fTop; 485 mx->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 486 mx->fBottom = mx->fDescent; 487 mx->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 488 mx->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 489 mx->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 490 mx->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 491 492 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; 493 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 494 } 495 496 if (my) { 497 my->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 498 my->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 499 my->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 500 my->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 501 my->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 502 my->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 503 504 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; 505 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 506 507 if (NULL != fTypeface->fDWriteFontFace1.get()) { 508 DWRITE_FONT_METRICS1 dwfm1; 509 fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1); 510 my->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; 511 my->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; 512 my->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; 513 my->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; 514 515 my->fMaxCharWidth = my->fXMax - my->fXMin; 516 } else { 517 AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get()); 518 if (head.fExists && 519 head.fSize >= sizeof(SkOTTableHead) && 520 head->version == SkOTTableHead::version1) 521 { 522 my->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; 523 my->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; 524 my->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; 525 my->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; 526 527 my->fMaxCharWidth = my->fXMax - my->fXMin; 528 } else { 529 my->fTop = my->fAscent; 530 my->fBottom = my->fDescent; 531 } 532 } 533 } 534} 535 536/////////////////////////////////////////////////////////////////////////////// 537 538#include "SkColorPriv.h" 539 540static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { 541 const int width = glyph.fWidth; 542 const size_t dstRB = (width + 7) >> 3; 543 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 544 545 int byteCount = width >> 3; 546 int bitCount = width & 7; 547 548 for (int y = 0; y < glyph.fHeight; ++y) { 549 if (byteCount > 0) { 550 for (int i = 0; i < byteCount; ++i) { 551 unsigned byte = 0; 552 byte |= src[0] & (1 << 7); 553 byte |= src[1] & (1 << 6); 554 byte |= src[2] & (1 << 5); 555 byte |= src[3] & (1 << 4); 556 byte |= src[4] & (1 << 3); 557 byte |= src[5] & (1 << 2); 558 byte |= src[6] & (1 << 1); 559 byte |= src[7] & (1 << 0); 560 dst[i] = byte; 561 src += 8; 562 } 563 } 564 if (bitCount > 0) { 565 unsigned byte = 0; 566 unsigned mask = 0x80; 567 for (int i = 0; i < bitCount; i++) { 568 byte |= (src[i]) & mask; 569 mask >>= 1; 570 } 571 dst[byteCount] = byte; 572 } 573 src += bitCount; 574 dst += dstRB; 575 } 576} 577 578template<bool APPLY_PREBLEND> 579static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { 580 const size_t dstRB = glyph.rowBytes(); 581 const U16CPU width = glyph.fWidth; 582 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 583 584 for (U16CPU y = 0; y < glyph.fHeight; y++) { 585 for (U16CPU i = 0; i < width; i++) { 586 U8CPU r = *(src++); 587 U8CPU g = *(src++); 588 U8CPU b = *(src++); 589 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8); 590 } 591 dst = (uint8_t*)((char*)dst + dstRB); 592 } 593} 594 595template<bool APPLY_PREBLEND> 596static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 597 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 598 const size_t dstRB = glyph.rowBytes(); 599 const U16CPU width = glyph.fWidth; 600 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage); 601 602 for (U16CPU y = 0; y < glyph.fHeight; y++) { 603 for (U16CPU i = 0; i < width; i++) { 604 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 605 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 606 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 607 dst[i] = SkPack888ToRGB16(r, g, b); 608 } 609 dst = (uint16_t*)((char*)dst + dstRB); 610 } 611} 612 613template<bool APPLY_PREBLEND> 614static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 615 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 616 const size_t dstRB = glyph.rowBytes(); 617 const U16CPU width = glyph.fWidth; 618 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage); 619 620 for (U16CPU y = 0; y < glyph.fHeight; y++) { 621 for (U16CPU i = 0; i < width; i++) { 622 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 623 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 624 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 625 dst[i] = SkPackARGB32(0xFF, r, g, b); 626 } 627 dst = (SkPMColor*)((char*)dst + dstRB); 628 } 629} 630 631const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) { 632 int sizeNeeded = glyph.fWidth * glyph.fHeight; 633 if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) { 634 sizeNeeded *= 3; 635 } 636 if (sizeNeeded > fBits.count()) { 637 fBits.setCount(sizeNeeded); 638 } 639 640 // erase 641 memset(fBits.begin(), 0, sizeNeeded); 642 643 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 644 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 645 646 FLOAT advance = 0.0f; 647 648 UINT16 index = glyph.getGlyphID(); 649 650 DWRITE_GLYPH_OFFSET offset; 651 offset.advanceOffset = 0.0f; 652 offset.ascenderOffset = 0.0f; 653 654 DWRITE_GLYPH_RUN run; 655 run.glyphCount = 1; 656 run.glyphAdvances = &advance; 657 run.fontFace = fTypeface->fDWriteFontFace.get(); 658 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 659 run.bidiLevel = 0; 660 run.glyphIndices = &index; 661 run.isSideways = FALSE; 662 run.glyphOffsets = &offset; 663 664 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 665 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, 666 1.0f, // pixelsPerDip, 667 &fXform, 668 fRenderingMode, 669 fMeasuringMode, 670 0.0f, // baselineOriginX, 671 0.0f, // baselineOriginY, 672 &glyphRunAnalysis), 673 "Could not create glyph run analysis."); 674 675 //NOTE: this assumes that the glyph has already been measured 676 //with an exact same glyph run analysis. 677 RECT bbox; 678 bbox.left = glyph.fLeft; 679 bbox.top = glyph.fTop; 680 bbox.right = glyph.fLeft + glyph.fWidth; 681 bbox.bottom = glyph.fTop + glyph.fHeight; 682 HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType, 683 &bbox, 684 fBits.begin(), 685 sizeNeeded), 686 "Could not draw mask."); 687 return fBits.begin(); 688} 689 690void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { 691 //Create the mask. 692 const void* bits = this->drawDWMask(glyph); 693 if (!bits) { 694 sk_bzero(glyph.fImage, glyph.computeImageSize()); 695 return; 696 } 697 698 //Copy the mask into the glyph. 699 const uint8_t* src = (const uint8_t*)bits; 700 if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) { 701 bilevel_to_bw(src, glyph); 702 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; 703 } else if (!isLCD(fRec)) { 704 if (fPreBlend.isApplicable()) { 705 rgb_to_a8<true>(src, glyph, fPreBlend.fG); 706 } else { 707 rgb_to_a8<false>(src, glyph, fPreBlend.fG); 708 } 709 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { 710 if (fPreBlend.isApplicable()) { 711 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 712 } else { 713 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 714 } 715 } else { 716 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); 717 if (fPreBlend.isApplicable()) { 718 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 719 } else { 720 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 721 } 722 } 723} 724 725void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { 726 SkASSERT(&glyph && path); 727 728 path->reset(); 729 730 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 731 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), 732 "Could not create geometry to path converter."); 733 uint16_t glyphId = glyph.getGlyphID(); 734 //TODO: convert to<->from DIUs? This would make a difference if hinting. 735 //It may not be needed, it appears that DirectWrite only hints at em size. 736 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), 737 &glyphId, 738 NULL, //advances 739 NULL, //offsets 740 1, //num glyphs 741 FALSE, //sideways 742 FALSE, //rtl 743 geometryToPath.get()), 744 "Could not create glyph outline."); 745 746 path->transform(fSkXform); 747} 748