| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkTypes.h" | 8 #include "SkTypes.h" |
| 9 #if defined(SK_BUILD_FOR_WIN32) | 9 #if defined(SK_BUILD_FOR_WIN32) |
| 10 | 10 |
| 11 #undef GetGlyphIndices | 11 #undef GetGlyphIndices |
| 12 | 12 |
| 13 #include "SkDraw.h" | 13 #include "SkDraw.h" |
| 14 #include "SkDWrite.h" | 14 #include "SkDWrite.h" |
| 15 #include "SkDWriteGeometrySink.h" | 15 #include "SkDWriteGeometrySink.h" |
| 16 #include "SkEndian.h" | 16 #include "SkEndian.h" |
| 17 #include "SkGlyph.h" | 17 #include "SkGlyph.h" |
| 18 #include "SkHRESULT.h" | 18 #include "SkHRESULT.h" |
| 19 #include "SkMaskGamma.h" | 19 #include "SkMaskGamma.h" |
| 20 #include "SkMatrix22.h" | 20 #include "SkMatrix22.h" |
| 21 #include "SkMutex.h" | |
| 22 #include "SkOTTable_EBLC.h" | 21 #include "SkOTTable_EBLC.h" |
| 23 #include "SkOTTable_EBSC.h" | 22 #include "SkOTTable_EBSC.h" |
| 24 #include "SkOTTable_gasp.h" | 23 #include "SkOTTable_gasp.h" |
| 25 #include "SkOTTable_maxp.h" | 24 #include "SkOTTable_maxp.h" |
| 26 #include "SkPath.h" | 25 #include "SkPath.h" |
| 27 #include "SkRasterClip.h" | 26 #include "SkRasterClip.h" |
| 28 #include "SkScalerContext.h" | 27 #include "SkScalerContext.h" |
| 29 #include "SkScalerContext_win_dw.h" | 28 #include "SkScalerContext_win_dw.h" |
| 30 #include "SkSharedMutex.h" | |
| 31 #include "SkTScopedComPtr.h" | 29 #include "SkTScopedComPtr.h" |
| 32 #include "SkTypeface_win_dw.h" | 30 #include "SkTypeface_win_dw.h" |
| 33 | 31 |
| 34 #include <dwrite.h> | 32 #include <dwrite.h> |
| 35 #if SK_HAS_DWRITE_1_H | 33 #if SK_HAS_DWRITE_1_H |
| 36 # include <dwrite_1.h> | 34 # include <dwrite_1.h> |
| 37 #endif | 35 #endif |
| 38 | 36 |
| 39 /* Note: | |
| 40 * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe. | |
| 41 * The DWriteFactoryMutex protects the calls that are problematic. | |
| 42 */ | |
| 43 static SkSharedMutex DWriteFactoryMutex; | |
| 44 | |
| 45 typedef SkAutoSharedMutexShared Shared; | |
| 46 | |
| 47 static bool isLCD(const SkScalerContext::Rec& rec) { | 37 static bool isLCD(const SkScalerContext::Rec& rec) { |
| 48 return SkMask::kLCD16_Format == rec.fMaskFormat; | 38 return SkMask::kLCD16_Format == rec.fMaskFormat; |
| 49 } | 39 } |
| 50 | 40 |
| 51 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { | 41 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { |
| 52 SkAutoExclusive l(DWriteFactoryMutex); | |
| 53 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get
()); | 42 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get
()); |
| 54 if (!maxp.fExists) { | 43 if (!maxp.fExists) { |
| 55 return false; | 44 return false; |
| 56 } | 45 } |
| 57 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) { | 46 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) { |
| 58 return false; | 47 return false; |
| 59 } | 48 } |
| 60 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION)
{ | 49 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION)
{ |
| 61 return false; | 50 return false; |
| 62 } | 51 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 { | 101 { |
| 113 range->min = minPPEM + 1; | 102 range->min = minPPEM + 1; |
| 114 range->max = maxPPEM; | 103 range->max = maxPPEM; |
| 115 return; | 104 return; |
| 116 } | 105 } |
| 117 minPPEM = maxPPEM; | 106 minPPEM = maxPPEM; |
| 118 } | 107 } |
| 119 } | 108 } |
| 120 | 109 |
| 121 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { | 110 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { |
| 122 SkAutoExclusive l(DWriteFactoryMutex); | |
| 123 { | 111 { |
| 124 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWrite
FontFace.get()); | 112 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWrite
FontFace.get()); |
| 125 if (!eblc.fExists) { | 113 if (!eblc.fExists) { |
| 126 return false; | 114 return false; |
| 127 } | 115 } |
| 128 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { | 116 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { |
| 129 return false; | 117 return false; |
| 130 } | 118 } |
| 131 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { | 119 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { |
| 132 return false; | 120 return false; |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 | 343 |
| 356 glyph->fAdvanceX = 0; | 344 glyph->fAdvanceX = 0; |
| 357 glyph->fAdvanceY = 0; | 345 glyph->fAdvanceY = 0; |
| 358 | 346 |
| 359 uint16_t glyphId = glyph->getGlyphID(); | 347 uint16_t glyphId = glyph->getGlyphID(); |
| 360 DWRITE_GLYPH_METRICS gm; | 348 DWRITE_GLYPH_METRICS gm; |
| 361 | 349 |
| 362 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || | 350 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || |
| 363 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) | 351 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) |
| 364 { | 352 { |
| 365 SkAutoExclusive l(DWriteFactoryMutex); | |
| 366 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( | 353 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( |
| 367 fTextSizeMeasure, | 354 fTextSizeMeasure, |
| 368 1.0f, // pixelsPerDip | 355 1.0f, // pixelsPerDip |
| 369 &fGsA, | 356 &fGsA, |
| 370 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, | 357 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, |
| 371 &glyphId, 1, | 358 &glyphId, 1, |
| 372 &gm), | 359 &gm), |
| 373 "Could not get gdi compatible glyph metrics."); | 360 "Could not get gdi compatible glyph metrics."); |
| 374 } else { | 361 } else { |
| 375 SkAutoExclusive l(DWriteFactoryMutex); | |
| 376 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm)
, | 362 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm)
, |
| 377 "Could not get design metrics."); | 363 "Could not get design metrics."); |
| 378 } | 364 } |
| 379 | 365 |
| 380 DWRITE_FONT_METRICS dwfm; | 366 DWRITE_FONT_METRICS dwfm; |
| 381 { | 367 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); |
| 382 Shared l(DWriteFactoryMutex); | |
| 383 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); | |
| 384 } | |
| 385 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, | 368 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, |
| 386 SkIntToScalar(gm.advanceWidth), | 369 SkIntToScalar(gm.advanceWidth), |
| 387 SkIntToScalar(dwfm.designUnitsPerEm)); | 370 SkIntToScalar(dwfm.designUnitsPerEm)); |
| 388 | 371 |
| 389 SkVector vecs[1] = { { advanceX, 0 } }; | 372 SkVector vecs[1] = { { advanceX, 0 } }; |
| 390 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || | 373 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || |
| 391 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) | 374 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) |
| 392 { | 375 { |
| 393 // DirectWrite produced 'compatible' metrics, but while close, | 376 // DirectWrite produced 'compatible' metrics, but while close, |
| 394 // the end result is not always an integer as it would be with GDI. | 377 // the end result is not always an integer as it would be with GDI. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 423 run.glyphCount = 1; | 406 run.glyphCount = 1; |
| 424 run.glyphAdvances = &advance; | 407 run.glyphAdvances = &advance; |
| 425 run.fontFace = fTypeface->fDWriteFontFace.get(); | 408 run.fontFace = fTypeface->fDWriteFontFace.get(); |
| 426 run.fontEmSize = SkScalarToFloat(fTextSizeRender); | 409 run.fontEmSize = SkScalarToFloat(fTextSizeRender); |
| 427 run.bidiLevel = 0; | 410 run.bidiLevel = 0; |
| 428 run.glyphIndices = &glyphId; | 411 run.glyphIndices = &glyphId; |
| 429 run.isSideways = FALSE; | 412 run.isSideways = FALSE; |
| 430 run.glyphOffsets = &offset; | 413 run.glyphOffsets = &offset; |
| 431 | 414 |
| 432 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; | 415 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; |
| 433 { | 416 HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( |
| 434 SkAutoExclusive l(DWriteFactoryMutex); | 417 &run, |
| 435 HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( | 418 1.0f, // pixelsPerDip, |
| 436 &run, | 419 &fXform, |
| 437 1.0f, // pixelsPerDip, | 420 renderingMode, |
| 438 &fXform, | 421 fMeasuringMode, |
| 439 renderingMode, | 422 0.0f, // baselineOriginX, |
| 440 fMeasuringMode, | 423 0.0f, // baselineOriginY, |
| 441 0.0f, // baselineOriginX, | 424 &glyphRunAnalysis), |
| 442 0.0f, // baselineOriginY, | 425 "Could not create glyph run analysis."); |
| 443 &glyphRunAnalysis), | 426 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), |
| 444 "Could not create glyph run analysis."); | 427 "Could not get texture bounds."); |
| 445 } | |
| 446 { | |
| 447 Shared l(DWriteFactoryMutex); | |
| 448 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), | |
| 449 "Could not get texture bounds."); | |
| 450 } | |
| 451 return S_OK; | 428 return S_OK; |
| 452 } | 429 } |
| 453 | 430 |
| 454 /** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like | 431 /** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like |
| 455 * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } | 432 * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } |
| 456 * for small, but not quite zero, sized glyphs. | 433 * for small, but not quite zero, sized glyphs. |
| 457 * Only set as non-empty if the returned bounds are non-empty. | 434 * Only set as non-empty if the returned bounds are non-empty. |
| 458 */ | 435 */ |
| 459 static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { | 436 static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { |
| 460 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { | 437 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 run.glyphAdvances = &advance; | 705 run.glyphAdvances = &advance; |
| 729 run.fontFace = fTypeface->fDWriteFontFace.get(); | 706 run.fontFace = fTypeface->fDWriteFontFace.get(); |
| 730 run.fontEmSize = SkScalarToFloat(fTextSizeRender); | 707 run.fontEmSize = SkScalarToFloat(fTextSizeRender); |
| 731 run.bidiLevel = 0; | 708 run.bidiLevel = 0; |
| 732 run.glyphIndices = &index; | 709 run.glyphIndices = &index; |
| 733 run.isSideways = FALSE; | 710 run.isSideways = FALSE; |
| 734 run.glyphOffsets = &offset; | 711 run.glyphOffsets = &offset; |
| 735 { | 712 { |
| 736 | 713 |
| 737 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; | 714 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; |
| 738 { | 715 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, |
| 739 SkAutoExclusive l(DWriteFactoryMutex); | 716 1.0f, // pixelsPerDip, |
| 740 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, | 717 &fXform, |
| 741 1.0f, // pixelsPerDip, | 718 renderingMode, |
| 742 &fXform, | 719 fMeasuringMode, |
| 743 renderingMode, | 720 0.0f, // baselineOriginX, |
| 744 fMeasuringMode, | 721 0.0f, // baselineOriginY, |
| 745 0.0f, // baselineOriginX, | 722 &glyphRunAnalysis), |
| 746 0.0f, // baselineOriginY, | 723 "Could not create glyph run analysis."); |
| 747 &glyphRunAnalysis), | |
| 748 "Could not create glyph run analysis."); | |
| 749 } | |
| 750 //NOTE: this assumes that the glyph has already been measured | 724 //NOTE: this assumes that the glyph has already been measured |
| 751 //with an exact same glyph run analysis. | 725 //with an exact same glyph run analysis. |
| 752 RECT bbox; | 726 RECT bbox; |
| 753 bbox.left = glyph.fLeft; | 727 bbox.left = glyph.fLeft; |
| 754 bbox.top = glyph.fTop; | 728 bbox.top = glyph.fTop; |
| 755 bbox.right = glyph.fLeft + glyph.fWidth; | 729 bbox.right = glyph.fLeft + glyph.fWidth; |
| 756 bbox.bottom = glyph.fTop + glyph.fHeight; | 730 bbox.bottom = glyph.fTop + glyph.fHeight; |
| 757 { | 731 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, |
| 758 Shared l(DWriteFactoryMutex); | 732 &bbox, |
| 759 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, | 733 fBits.begin(), |
| 760 &bbox, | 734 sizeNeeded), |
| 761 fBits.begin(), | 735 "Could not draw mask."); |
| 762 sizeNeeded), | |
| 763 "Could not draw mask."); | |
| 764 } | |
| 765 } | 736 } |
| 766 return fBits.begin(); | 737 return fBits.begin(); |
| 767 } | 738 } |
| 768 | 739 |
| 769 #if SK_HAS_DWRITE_2_H | 740 #if SK_HAS_DWRITE_2_H |
| 770 void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { | 741 void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { |
| 771 SkASSERT(isColorGlyph(glyph)); | 742 SkASSERT(isColorGlyph(glyph)); |
| 772 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format); | 743 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format); |
| 773 | 744 |
| 774 memset(glyph.fImage, 0, glyph.computeImageSize()); | 745 memset(glyph.fImage, 0, glyph.computeImageSize()); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 812 // If this assert ever fires, we should verify that the color is ren
dered properly. | 783 // If this assert ever fires, we should verify that the color is ren
dered properly. |
| 813 SkASSERT(false); | 784 SkASSERT(false); |
| 814 color = fRec.getLuminanceColor(); | 785 color = fRec.getLuminanceColor(); |
| 815 } | 786 } |
| 816 paint.setColor(color); | 787 paint.setColor(color); |
| 817 | 788 |
| 818 SkPath path; | 789 SkPath path; |
| 819 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; | 790 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; |
| 820 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), | 791 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), |
| 821 "Could not create geometry to path converter."); | 792 "Could not create geometry to path converter."); |
| 822 { | 793 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( |
| 823 SkAutoExclusive l(DWriteFactoryMutex); | 794 colorGlyph->glyphRun.fontEmSize, |
| 824 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( | 795 colorGlyph->glyphRun.glyphIndices, |
| 825 colorGlyph->glyphRun.fontEmSize, | 796 colorGlyph->glyphRun.glyphAdvances, |
| 826 colorGlyph->glyphRun.glyphIndices, | 797 colorGlyph->glyphRun.glyphOffsets, |
| 827 colorGlyph->glyphRun.glyphAdvances, | 798 colorGlyph->glyphRun.glyphCount, |
| 828 colorGlyph->glyphRun.glyphOffsets, | 799 colorGlyph->glyphRun.isSideways, |
| 829 colorGlyph->glyphRun.glyphCount, | 800 colorGlyph->glyphRun.bidiLevel % 2, //rtl |
| 830 colorGlyph->glyphRun.isSideways, | 801 geometryToPath.get()), |
| 831 colorGlyph->glyphRun.bidiLevel % 2, //rtl | 802 "Could not create glyph outline."); |
| 832 geometryToPath.get()), | |
| 833 "Could not create glyph outline."); | |
| 834 } | |
| 835 draw.drawPath(path, paint, nullptr, true /* pathIsMutable */); | 803 draw.drawPath(path, paint, nullptr, true /* pathIsMutable */); |
| 836 } | 804 } |
| 837 } | 805 } |
| 838 #endif | 806 #endif |
| 839 | 807 |
| 840 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { | 808 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { |
| 841 //Create the mask. | 809 //Create the mask. |
| 842 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; | 810 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; |
| 843 DWRITE_TEXTURE_TYPE textureType = fTextureType; | 811 DWRITE_TEXTURE_TYPE textureType = fTextureType; |
| 844 if (glyph.fForceBW) { | 812 if (glyph.fForceBW) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 | 858 |
| 891 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { | 859 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { |
| 892 SkASSERT(path); | 860 SkASSERT(path); |
| 893 | 861 |
| 894 path->reset(); | 862 path->reset(); |
| 895 | 863 |
| 896 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; | 864 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; |
| 897 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), | 865 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), |
| 898 "Could not create geometry to path converter."); | 866 "Could not create geometry to path converter."); |
| 899 uint16_t glyphId = glyph.getGlyphID(); | 867 uint16_t glyphId = glyph.getGlyphID(); |
| 900 { | 868 //TODO: convert to<->from DIUs? This would make a difference if hinting. |
| 901 SkAutoExclusive l(DWriteFactoryMutex); | 869 //It may not be needed, it appears that DirectWrite only hints at em size. |
| 902 //TODO: convert to<->from DIUs? This would make a difference if hinting. | 870 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSiz
eRender), |
| 903 //It may not be needed, it appears that DirectWrite only hints at em siz
e. | 871 &glyphId, |
| 904 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTex
tSizeRender), | 872 nullptr, //advances |
| 905 &glyphId, | 873 nullptr, //offsets |
| 906 nullptr, //advances | 874 1, //num glyphs |
| 907 nullptr, //offsets | 875 FALSE, //sideways |
| 908 1, //num glyphs | 876 FALSE, //rtl |
| 909 FALSE, //sideways | 877 geometryToPath.get()), |
| 910 FALSE, //rtl | 878 "Could not create glyph outline."); |
| 911 geometryToPath.get()), | |
| 912 "Could not create glyph outline."); | |
| 913 } | |
| 914 | 879 |
| 915 path->transform(fSkXform); | 880 path->transform(fSkXform); |
| 916 } | 881 } |
| 917 | 882 |
| 918 #endif//defined(SK_BUILD_FOR_WIN32) | 883 #endif//defined(SK_BUILD_FOR_WIN32) |
| OLD | NEW |