Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1256)

Side by Side Diff: src/ports/SkScalerContext_win_dw.cpp

Issue 1984943002: Implement support for rendering color emoji on Windows (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: Add check to respect aliased rendering mode Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ports/SkScalerContext_win_dw.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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)
OLDNEW
« no previous file with comments | « src/ports/SkScalerContext_win_dw.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698