Chromium Code Reviews| 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 |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 203 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); | 203 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); |
| 204 } | 204 } |
| 205 | 205 |
| 206 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, | 206 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, |
| 207 const SkScalerContextEffects& effects, | 207 const SkScalerContextEffects& effects, |
| 208 const SkDescriptor* desc) | 208 const SkDescriptor* desc) |
| 209 : SkScalerContext(typeface, effects, desc) | 209 : SkScalerContext(typeface, effects, desc) |
| 210 , fTypeface(SkRef(typeface)) | 210 , fTypeface(SkRef(typeface)) |
| 211 , fGlyphCount(-1) { | 211 , fGlyphCount(-1) { |
| 212 | 212 |
| 213 #if SK_HAS_DWRITE_2_H | |
| 214 SkTScopedComPtr<IDWriteFactory> factory(SkSafeRefComPtr(sk_get_dwrite_factor y())); | |
|
bungeman-skia
2016/05/18 14:50:55
You cannot create a factory here, you must use the
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 215 factory->QueryInterface<IDWriteFactory2>(&fFactory2); | |
| 216 | |
| 217 SkTScopedComPtr<IDWriteFontFace2> fontFace2; | |
| 218 fTypeface->fDWriteFontFace->QueryInterface<IDWriteFontFace2>(&fontFace2); | |
| 219 fIsColorFont = fFactory2.get() && fontFace2.get() && fontFace2->IsColorFont( ); | |
| 220 #endif | |
| 221 | |
| 213 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC | 222 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC |
| 214 // except when bi-level rendering is requested or there are embedded | 223 // except when bi-level rendering is requested or there are embedded |
| 215 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). | 224 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). |
| 216 // | 225 // |
| 217 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do | 226 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do |
| 218 // this. As a result, determine the actual size of the text and then see if | 227 // this. As a result, determine the actual size of the text and then see if |
| 219 // there are any embedded bi-level bitmaps of that size. If there are, then | 228 // there are any embedded bi-level bitmaps of that size. If there are, then |
| 220 // force bitmaps by requesting bi-level rendering. | 229 // force bitmaps by requesting bi-level rendering. |
| 221 // | 230 // |
| 222 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes | 231 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { | 460 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { |
| 452 return false; | 461 return false; |
| 453 } | 462 } |
| 454 glyph->fWidth = SkToU16(bbox.right - bbox.left); | 463 glyph->fWidth = SkToU16(bbox.right - bbox.left); |
| 455 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); | 464 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); |
| 456 glyph->fLeft = SkToS16(bbox.left); | 465 glyph->fLeft = SkToS16(bbox.left); |
| 457 glyph->fTop = SkToS16(bbox.top); | 466 glyph->fTop = SkToS16(bbox.top); |
| 458 return true; | 467 return true; |
| 459 } | 468 } |
| 460 | 469 |
| 470 bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) { | |
| 471 #if SK_HAS_DWRITE_2_H | |
| 472 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayer; | |
| 473 if (getColorGlyphRun(glyph, &colorLayer)) { | |
| 474 return true; | |
| 475 } | |
| 476 #endif | |
| 477 return false; | |
| 478 } | |
| 479 | |
| 480 #if SK_HAS_DWRITE_2_H | |
| 481 bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, | |
| 482 IDWriteColorGlyphRunEnumerator** color Glyph) | |
| 483 { | |
| 484 FLOAT advance = 0; | |
| 485 UINT16 glyphId = glyph.getGlyphID(); | |
| 486 | |
| 487 DWRITE_GLYPH_OFFSET offset; | |
| 488 offset.advanceOffset = 0.0f; | |
| 489 offset.ascenderOffset = 0.0f; | |
| 490 | |
| 491 DWRITE_GLYPH_RUN run; | |
| 492 run.glyphCount = 1; | |
| 493 run.glyphAdvances = &advance; | |
| 494 run.fontFace = fTypeface->fDWriteFontFace.get(); | |
| 495 run.fontEmSize = SkScalarToFloat(fTextSizeRender); | |
| 496 run.bidiLevel = 0; | |
| 497 run.glyphIndices = &glyphId; | |
| 498 run.isSideways = FALSE; | |
| 499 run.glyphOffsets = &offset; | |
| 500 | |
| 501 HRESULT hr = fFactory2->TranslateColorGlyphRun( | |
| 502 0, 0, &run, nullptr, DWRITE_MEASURING_MODE_NATURAL, nullptr, 0, colorGly ph); | |
|
bungeman-skia
2016/05/18 14:50:55
Need to pass in fXform and fMeasuringMode.
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 503 if (SUCCEEDED(hr)) { | |
| 504 return true; | |
| 505 } else { | |
| 506 SkASSERT(hr == DWRITE_E_NOCOLOR); | |
| 507 } | |
| 508 return false; | |
|
bungeman-skia
2016/05/18 14:50:55
The return value handling here should be more like
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 509 } | |
| 510 #endif | |
| 511 | |
| 461 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { | 512 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { |
| 462 glyph->fWidth = 0; | 513 glyph->fWidth = 0; |
| 463 glyph->fHeight = 0; | 514 glyph->fHeight = 0; |
| 464 glyph->fLeft = 0; | 515 glyph->fLeft = 0; |
| 465 glyph->fTop = 0; | 516 glyph->fTop = 0; |
| 466 | 517 |
| 467 this->generateAdvance(glyph); | 518 this->generateAdvance(glyph); |
| 468 | 519 |
| 520 #if SK_HAS_DWRITE_2_H | |
| 521 if (fIsColorFont && isColorGlyph(*glyph)) { | |
| 522 glyph->fMaskFormat = SkMask::kARGB32_Format; | |
| 523 } | |
| 524 #endif | |
| 525 | |
| 469 RECT bbox; | 526 RECT bbox; |
| 470 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), | 527 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), |
| 471 "Requested bounding box could not be determined."); | 528 "Requested bounding box could not be determined."); |
| 472 | 529 |
| 473 if (glyph_check_and_set_bounds(glyph, bbox)) { | 530 if (glyph_check_and_set_bounds(glyph, bbox)) { |
| 474 return; | 531 return; |
| 475 } | 532 } |
| 476 | 533 |
| 477 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no | 534 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no |
| 478 // glyphs of the specified texture type. When this happens, try with the | 535 // glyphs of the specified texture type. When this happens, try with the |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 703 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, | 760 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, |
| 704 &bbox, | 761 &bbox, |
| 705 fBits.begin(), | 762 fBits.begin(), |
| 706 sizeNeeded), | 763 sizeNeeded), |
| 707 "Could not draw mask."); | 764 "Could not draw mask."); |
| 708 } | 765 } |
| 709 } | 766 } |
| 710 return fBits.begin(); | 767 return fBits.begin(); |
| 711 } | 768 } |
| 712 | 769 |
| 770 #if SK_HAS_DWRITE_2_H | |
| 771 void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { | |
| 772 SkASSERT(isColorGlyph(glyph)); | |
| 773 HRESULT hr = S_OK; | |
|
bungeman-skia
2016/05/18 14:50:55
Remove this.
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 774 | |
| 775 memset(glyph.fImage, 0, glyph.computeImageSize()); | |
| 776 | |
| 777 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; | |
| 778 getColorGlyphRun(glyph, &colorLayers); | |
| 779 SkASSERT(colorLayers.get()); | |
| 780 | |
| 781 int layerSize = glyph.fWidth * glyph.fHeight; // layers are drawn in monochr ome | |
| 782 SkASSERT_RELEASE(layerSize * sizeof(uint32_t) == glyph.computeImageSize()); | |
| 783 fBits.setCount(layerSize); | |
| 784 | |
| 785 RECT bbox; | |
| 786 bbox.left = glyph.fLeft; | |
| 787 bbox.top = glyph.fTop; | |
| 788 bbox.right = glyph.fLeft + glyph.fWidth; | |
| 789 bbox.bottom = glyph.fTop + glyph.fHeight; | |
| 790 | |
| 791 BOOL hasNextRun = FALSE; | |
| 792 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { | |
| 793 const DWRITE_COLOR_GLYPH_RUN* colorGlyph; | |
| 794 if (!SUCCEEDED(colorLayers->GetCurrentRun(&colorGlyph))) { | |
|
bungeman-skia
2016/05/18 14:50:55
Use the HRNM macro for proper logging and for cons
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 795 SkASSERT(false); | |
| 796 return; | |
| 797 } | |
| 798 | |
| 799 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; | |
| 800 { | |
| 801 Exclusive l(DWriteFactoryMutex); | |
| 802 hr = fTypeface->fFactory->CreateGlyphRunAnalysis(&colorGlyph->glyphR un, | |
|
bungeman-skia
2016/05/18 14:50:55
The result is never checked. Use the HRNM macro li
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 803 1.0f, // pixelsPerDip, | |
| 804 nullptr, | |
|
bungeman-skia
2016/05/18 14:50:55
If you don't pass the fXForm, how does this work f
Ilya Kulshin
2016/05/18 22:43:38
Added fXfrom, but I'm not sure when it will be som
bungeman-skia
2016/05/19 18:52:37
Any time there is skew/rotation.
| |
| 805 DWRITE_RENDERING_MODE_ALIASED, | |
| 806 DWRITE_MEASURING_MODE_NATURAL, | |
|
bungeman-skia
2016/05/18 14:50:55
fRenderingMode and fMeasuringMode
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 807 colorGlyph->baselineOriginX, | |
| 808 colorGlyph->baselineOriginY, | |
| 809 &glyphRunAnalysis); | |
| 810 } | |
| 811 //NOTE: this assumes that the glyph has already been measured | |
| 812 //with an exact same glyph run analysis. | |
| 813 { | |
| 814 Shared l(DWriteFactoryMutex); | |
| 815 hr = glyphRunAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_ALIASED_1x1 , | |
|
bungeman-skia
2016/05/18 14:50:55
HRNM, fRenderingMode
Ilya Kulshin
2016/05/18 22:43:38
Done.
| |
| 816 &bbox, | |
| 817 fBits.begin(), | |
| 818 layerSize); | |
| 819 } | |
| 820 | |
| 821 uint32_t* colorPixels = reinterpret_cast<uint32_t*>(glyph.fImage); | |
| 822 SkColor color = SkColorSetARGB(colorGlyph->runColor.a * 255, | |
|
bungeman-skia
2016/05/18 14:50:55
Note that if all components of runColor are 0 or (
Ilya Kulshin
2016/05/20 03:41:40
Changed to fRec.getLuminanceColor() and added a co
| |
| 823 colorGlyph->runColor.r * 255, | |
|
reed1
2016/05/18 00:42:53
is runColor premultiplied?
Ilya Kulshin
2016/05/18 00:56:46
I'm not actually sure. It's of type D3DCOLORVALUE.
| |
| 824 colorGlyph->runColor.g * 255, | |
| 825 colorGlyph->runColor.b * 255); | |
| 826 for (int pixel = 0; pixel < layerSize; pixel++) { | |
| 827 if (fBits[pixel] != 0) { | |
|
bungeman-skia
2016/05/18 14:50:54
This seems like a really bad blend, this should be
Ilya Kulshin
2016/05/18 22:43:38
Originally I thought antialiasing/subpixel renderi
| |
| 828 colorPixels[pixel] = color; | |
| 829 } | |
| 830 } | |
| 831 } | |
| 832 } | |
| 833 #endif | |
| 834 | |
| 713 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { | 835 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { |
| 714 //Create the mask. | 836 //Create the mask. |
| 715 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; | 837 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; |
| 716 DWRITE_TEXTURE_TYPE textureType = fTextureType; | 838 DWRITE_TEXTURE_TYPE textureType = fTextureType; |
| 717 if (glyph.fForceBW) { | 839 if (glyph.fForceBW) { |
| 718 renderingMode = DWRITE_RENDERING_MODE_ALIASED; | 840 renderingMode = DWRITE_RENDERING_MODE_ALIASED; |
| 719 textureType = DWRITE_TEXTURE_ALIASED_1x1; | 841 textureType = DWRITE_TEXTURE_ALIASED_1x1; |
| 720 } | 842 } |
| 843 | |
| 844 #if SK_HAS_DWRITE_2_H | |
| 845 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { | |
| 846 generateColorGlyphImage(glyph); | |
| 847 return; | |
| 848 } | |
| 849 #endif | |
| 850 | |
| 721 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); | 851 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); |
| 722 if (!bits) { | 852 if (!bits) { |
| 723 sk_bzero(glyph.fImage, glyph.computeImageSize()); | 853 sk_bzero(glyph.fImage, glyph.computeImageSize()); |
| 724 return; | 854 return; |
| 725 } | 855 } |
| 726 | 856 |
| 727 //Copy the mask into the glyph. | 857 //Copy the mask into the glyph. |
| 728 const uint8_t* src = (const uint8_t*)bits; | 858 const uint8_t* src = (const uint8_t*)bits; |
| 729 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { | 859 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { |
| 730 bilevel_to_bw(src, glyph); | 860 bilevel_to_bw(src, glyph); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 774 FALSE, //sideways | 904 FALSE, //sideways |
| 775 FALSE, //rtl | 905 FALSE, //rtl |
| 776 geometryToPath.get()), | 906 geometryToPath.get()), |
| 777 "Could not create glyph outline."); | 907 "Could not create glyph outline."); |
| 778 } | 908 } |
| 779 | 909 |
| 780 path->transform(fSkXform); | 910 path->transform(fSkXform); |
| 781 } | 911 } |
| 782 | 912 |
| 783 #endif//defined(SK_BUILD_FOR_WIN32) | 913 #endif//defined(SK_BUILD_FOR_WIN32) |
| OLD | NEW |