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 "SkCanvas.h" | |
13 #include "SkDWrite.h" | 14 #include "SkDWrite.h" |
14 #include "SkDWriteGeometrySink.h" | 15 #include "SkDWriteGeometrySink.h" |
15 #include "SkEndian.h" | 16 #include "SkEndian.h" |
16 #include "SkGlyph.h" | 17 #include "SkGlyph.h" |
17 #include "SkHRESULT.h" | 18 #include "SkHRESULT.h" |
18 #include "SkMaskGamma.h" | 19 #include "SkMaskGamma.h" |
19 #include "SkMatrix22.h" | 20 #include "SkMatrix22.h" |
20 #include "SkMutex.h" | 21 #include "SkMutex.h" |
21 #include "SkOTTable_EBLC.h" | 22 #include "SkOTTable_EBLC.h" |
22 #include "SkOTTable_EBSC.h" | 23 #include "SkOTTable_EBSC.h" |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
203 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); | 204 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); |
204 } | 205 } |
205 | 206 |
206 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, | 207 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, |
207 const SkScalerContextEffects& effects, | 208 const SkScalerContextEffects& effects, |
208 const SkDescriptor* desc) | 209 const SkDescriptor* desc) |
209 : SkScalerContext(typeface, effects, desc) | 210 : SkScalerContext(typeface, effects, desc) |
210 , fTypeface(SkRef(typeface)) | 211 , fTypeface(SkRef(typeface)) |
211 , fGlyphCount(-1) { | 212 , fGlyphCount(-1) { |
212 | 213 |
214 #if SK_HAS_DWRITE_2_H | |
215 fTypeface->fFactory->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, fMeasuringMode, &fXform, 0, colorGlyph); | |
503 if (hr == DWRITE_E_NOCOLOR) { | |
504 return false; | |
505 } | |
506 HRBM(hr, "Failed to translate color glyph run"); | |
507 return true; | |
508 } | |
509 #endif | |
510 | |
461 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { | 511 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { |
462 glyph->fWidth = 0; | 512 glyph->fWidth = 0; |
463 glyph->fHeight = 0; | 513 glyph->fHeight = 0; |
464 glyph->fLeft = 0; | 514 glyph->fLeft = 0; |
465 glyph->fTop = 0; | 515 glyph->fTop = 0; |
466 | 516 |
467 this->generateAdvance(glyph); | 517 this->generateAdvance(glyph); |
468 | 518 |
519 #if SK_HAS_DWRITE_2_H | |
520 if (fIsColorFont && isColorGlyph(*glyph)) { | |
521 glyph->fMaskFormat = SkMask::kARGB32_Format; | |
522 } | |
523 #endif | |
524 | |
469 RECT bbox; | 525 RECT bbox; |
470 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), | 526 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), |
471 "Requested bounding box could not be determined."); | 527 "Requested bounding box could not be determined."); |
472 | 528 |
473 if (glyph_check_and_set_bounds(glyph, bbox)) { | 529 if (glyph_check_and_set_bounds(glyph, bbox)) { |
474 return; | 530 return; |
475 } | 531 } |
476 | 532 |
477 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no | 533 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no |
478 // glyphs of the specified texture type. When this happens, try with the | 534 // 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, | 759 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, |
704 &bbox, | 760 &bbox, |
705 fBits.begin(), | 761 fBits.begin(), |
706 sizeNeeded), | 762 sizeNeeded), |
707 "Could not draw mask."); | 763 "Could not draw mask."); |
708 } | 764 } |
709 } | 765 } |
710 return fBits.begin(); | 766 return fBits.begin(); |
711 } | 767 } |
712 | 768 |
769 #if SK_HAS_DWRITE_2_H | |
770 void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { | |
771 SkASSERT(isColorGlyph(glyph)); | |
772 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format); | |
773 | |
774 memset(glyph.fImage, 0, glyph.computeImageSize()); | |
775 | |
776 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; | |
777 getColorGlyphRun(glyph, &colorLayers); | |
778 SkASSERT(colorLayers.get()); | |
779 | |
780 SkAutoTUnref<SkCanvas> canvas( | |
reed1
2016/05/20 12:27:32
If this routine shows up in a profile, two ways to
Ilya Kulshin
2016/05/20 20:34:56
Haven't had a chance to profile this, but switched
| |
781 SkCanvas::NewRasterDirect( | |
782 SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaTyp e), | |
783 glyph.fImage, | |
784 glyph.ComputeRowBytes(glyph.fWidth, SkMask::Format::kARGB32_Format)) ); | |
785 | |
786 SkPaint paint; | |
787 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) { | |
788 paint.setFlags(SkPaint::Flags::kAntiAlias_Flag); | |
789 } | |
790 | |
791 BOOL hasNextRun = FALSE; | |
792 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { | |
793 const DWRITE_COLOR_GLYPH_RUN* colorGlyph; | |
794 HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current col or glyph run"); | |
795 | |
796 SkColor color; | |
797 if (colorGlyph->paletteIndex != 0xffff) { | |
798 color = SkColorSetARGB(colorGlyph->runColor.a * 255, | |
799 colorGlyph->runColor.r * 255, | |
800 colorGlyph->runColor.g * 255, | |
801 colorGlyph->runColor.b * 255); | |
802 } else { | |
803 // If all components of runColor are 0 or (equivalently) paletteInde x is 0xFFFF then | |
804 // the 'current brush' is used. fRec.getLuminanceColor() is kinda so rta what is wanted | |
805 // here, but not really, it will often be the wrong value because it wan't designed for | |
806 // this. | |
807 // In practice, I've not encountered a color glyph that uses the cur rent brush color, | |
808 // so I'm not sure it's even possible (it might be reserved for a ru n with a mix of | |
809 // color and non-color glyphs, which never happens here). If this as sert ever fires, we | |
810 // should verify that the color is rendered properly. | |
811 SkASSERT(false); | |
812 color = fRec.getLuminanceColor(); | |
813 } | |
814 paint.setColor(color); | |
815 | |
816 SkPath path; | |
817 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; | |
818 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), | |
819 "Could not create geometry to path converter."); | |
820 { | |
821 Exclusive l(DWriteFactoryMutex); | |
822 // If only DirectWrite had a "GetGlyphrunOutlineForThisGlyphRun" API ... | |
823 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( | |
824 colorGlyph->glyphRun.fontEmSize, | |
825 colorGlyph->glyphRun.glyphIndices, | |
826 colorGlyph->glyphRun.glyphAdvances, | |
827 colorGlyph->glyphRun.glyphOffsets, | |
828 colorGlyph->glyphRun.glyphCount, | |
829 colorGlyph->glyphRun.isSideways, | |
830 colorGlyph->glyphRun.bidiLevel % 2, //rtl | |
831 geometryToPath.get()), | |
832 "Could not create glyph outline."); | |
833 } | |
834 | |
835 path.transform(fSkXform); | |
836 path.offset(-glyph.fLeft, -glyph.fTop); | |
837 canvas->drawPath(path, paint); | |
838 } | |
839 canvas->flush(); | |
reed1
2016/05/20 12:27:32
not needed, since the canvas goes out of scope bef
Ilya Kulshin
2016/05/20 20:34:55
Acknowledged.
| |
840 } | |
841 #endif | |
842 | |
713 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { | 843 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { |
714 //Create the mask. | 844 //Create the mask. |
715 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; | 845 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; |
716 DWRITE_TEXTURE_TYPE textureType = fTextureType; | 846 DWRITE_TEXTURE_TYPE textureType = fTextureType; |
717 if (glyph.fForceBW) { | 847 if (glyph.fForceBW) { |
718 renderingMode = DWRITE_RENDERING_MODE_ALIASED; | 848 renderingMode = DWRITE_RENDERING_MODE_ALIASED; |
719 textureType = DWRITE_TEXTURE_ALIASED_1x1; | 849 textureType = DWRITE_TEXTURE_ALIASED_1x1; |
720 } | 850 } |
851 | |
852 #if SK_HAS_DWRITE_2_H | |
853 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { | |
854 generateColorGlyphImage(glyph); | |
855 return; | |
856 } | |
857 #endif | |
858 | |
721 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); | 859 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); |
722 if (!bits) { | 860 if (!bits) { |
723 sk_bzero(glyph.fImage, glyph.computeImageSize()); | 861 sk_bzero(glyph.fImage, glyph.computeImageSize()); |
724 return; | 862 return; |
725 } | 863 } |
726 | 864 |
727 //Copy the mask into the glyph. | 865 //Copy the mask into the glyph. |
728 const uint8_t* src = (const uint8_t*)bits; | 866 const uint8_t* src = (const uint8_t*)bits; |
729 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { | 867 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { |
730 bilevel_to_bw(src, glyph); | 868 bilevel_to_bw(src, glyph); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
774 FALSE, //sideways | 912 FALSE, //sideways |
775 FALSE, //rtl | 913 FALSE, //rtl |
776 geometryToPath.get()), | 914 geometryToPath.get()), |
777 "Could not create glyph outline."); | 915 "Could not create glyph outline."); |
778 } | 916 } |
779 | 917 |
780 path->transform(fSkXform); | 918 path->transform(fSkXform); |
781 } | 919 } |
782 | 920 |
783 #endif//defined(SK_BUILD_FOR_WIN32) | 921 #endif//defined(SK_BUILD_FOR_WIN32) |
OLD | NEW |