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

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

Issue 20585004: Fix metrics on Windows. (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « src/core/SkScalerContext.cpp ('k') | tools/generate_fir_coeff.py » ('j') | 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 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #include "SkAdvancedTypefaceMetrics.h" 9 #include "SkAdvancedTypefaceMetrics.h"
10 #include "SkBase64.h" 10 #include "SkBase64.h"
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS 73 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
74 // What we really want to catch is when GDI will ignore the AA request and g ive 74 // What we really want to catch is when GDI will ignore the AA request and g ive
75 // us BW instead. Smallish rotated text is one heuristic, so this code is ju st 75 // us BW instead. Smallish rotated text is one heuristic, so this code is ju st
76 // an approximation. We shouldn't need to do this for larger sizes, but at t hose 76 // an approximation. We shouldn't need to do this for larger sizes, but at t hose
77 // sizes, the quality difference gets less and less between our general 77 // sizes, the quality difference gets less and less between our general
78 // scanconverter and GDI's. 78 // scanconverter and GDI's.
79 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) { 79 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
80 return true; 80 return true;
81 } 81 }
82 #endif 82 #endif
83 // false means allow GDI to generate the bits 83 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPai nt::kSlight_Hinting;
84 return false;
85 } 84 }
86 85
87 using namespace skia_advanced_typeface_metrics_utils; 86 using namespace skia_advanced_typeface_metrics_utils;
88 87
89 /**
90 * Since LOGFONT wants its textsize as an int, and we support fractional sizes,
91 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the
92 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
93 * actual requested size.
94 *
95 * Not critical to match the font's upem, but we want it big enough to avoid
96 * precision loss for GDI calls that return ints (e.g. GetOutlineFontMetrics).
97 */
98 static const int gCanonicalTextSize = 2048;
99
100 static void tchar_to_skstring(const TCHAR t[], SkString* s) { 88 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
101 #ifdef UNICODE 89 #ifdef UNICODE
102 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL); 90 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL);
103 s->resize(sSize); 91 s->resize(sSize);
104 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL) ; 92 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL) ;
105 #else 93 #else
106 s->set(t); 94 s->set(t);
107 #endif 95 #endif
108 } 96 }
109 97
110 static void make_canonical(LOGFONT* lf) { 98 static void make_canonical(LOGFONT* lf) {
111 lf->lfHeight = -gCanonicalTextSize; 99 lf->lfHeight = -2048;
112 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; 100 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
113 lf->lfCharSet = DEFAULT_CHARSET; 101 lf->lfCharSet = DEFAULT_CHARSET;
114 // lf->lfClipPrecision = 64; 102 // lf->lfClipPrecision = 64;
115 } 103 }
116 104
117 static SkTypeface::Style get_style(const LOGFONT& lf) { 105 static SkTypeface::Style get_style(const LOGFONT& lf) {
118 unsigned style = 0; 106 unsigned style = 0;
119 if (lf.lfWeight >= FW_BOLD) { 107 if (lf.lfWeight >= FW_BOLD) {
120 style |= SkTypeface::kBold; 108 style |= SkTypeface::kBold;
121 } 109 }
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 434
447 private: 435 private:
448 HDC fDC; 436 HDC fDC;
449 HBITMAP fBM; 437 HBITMAP fBM;
450 HFONT fFont; 438 HFONT fFont;
451 XFORM fXform; 439 XFORM fXform;
452 void* fBits; // points into fBM 440 void* fBits; // points into fBM
453 int fWidth; 441 int fWidth;
454 int fHeight; 442 int fHeight;
455 bool fIsBW; 443 bool fIsBW;
456
457 enum {
458 // will always trigger us to reset the color, since we
459 // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F)
460 kInvalid_Color = 12345
461 };
462 }; 444 };
463 445
464 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, 446 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
465 size_t* srcRBPtr) { 447 size_t* srcRBPtr) {
466 // Can we share the scalercontext's fDDC, so we don't need to create 448 // Can we share the scalercontext's fDDC, so we don't need to create
467 // a separate fDC here? 449 // a separate fDC here?
468 if (0 == fDC) { 450 if (0 == fDC) {
469 fDC = CreateCompatibleDC(0); 451 fDC = CreateCompatibleDC(0);
470 if (0 == fDC) { 452 if (0 == fDC) {
471 return NULL; 453 return NULL;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 GdiFlush(); 513 GdiFlush();
532 if (0 == ret) { 514 if (0 == ret) {
533 return NULL; 515 return NULL;
534 } 516 }
535 *srcRBPtr = srcRB; 517 *srcRBPtr = srcRB;
536 // offset to the start of the image 518 // offset to the start of the image
537 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB; 519 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
538 } 520 }
539 521
540 ////////////////////////////////////////////////////////////////////////////// 522 //////////////////////////////////////////////////////////////////////////////
523 #define BUFFERSIZE (1 << 13)
541 524
542 class SkScalerContext_Windows : public SkScalerContext { 525 class SkScalerContext_Windows : public SkScalerContext {
543 public: 526 public:
544 SkScalerContext_Windows(SkTypeface*, const SkDescriptor* desc); 527 SkScalerContext_Windows(SkTypeface*, const SkDescriptor* desc);
545 virtual ~SkScalerContext_Windows(); 528 virtual ~SkScalerContext_Windows();
546 529
547 // Returns true if the constructor was able to complete all of its 530 // Returns true if the constructor was able to complete all of its
548 // initializations (which may include calling GDI). 531 // initializations (which may include calling GDI).
549 bool isValid() const; 532 bool isValid() const;
550 533
551 protected: 534 protected:
552 virtual unsigned generateGlyphCount() SK_OVERRIDE; 535 virtual unsigned generateGlyphCount() SK_OVERRIDE;
553 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; 536 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
554 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 537 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
555 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 538 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
556 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 539 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
557 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 540 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
558 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, 541 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
559 SkPaint::FontMetrics* mY) SK_OVERRIDE; 542 SkPaint::FontMetrics* mY) SK_OVERRIDE;
560 543
561 private: 544 private:
545 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
546 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
547
562 HDCOffscreen fOffscreen; 548 HDCOffscreen fOffscreen;
563 SkScalar fScale; // to get from canonical size to real size 549 /** fGsA is the non-rotational part of total matrix without the text height scale.
550 * Used to find the magnitude of advances.
551 */
552 MAT2 fGsA;
564 MAT2 fMat22; 553 MAT2 fMat22;
565 HDC fDDC; 554 HDC fDDC;
566 HFONT fSavefont; 555 HFONT fSavefont;
567 HFONT fFont; 556 HFONT fFont;
568 HFONT fHiResFont; 557 HFONT fHiResFont;
569 SCRIPT_CACHE fSC; 558 SCRIPT_CACHE fSC;
570 int fGlyphCount; 559 int fGlyphCount;
571 560
572 MAT2 fMat22Identity;
573 SkMatrix fHiResMatrix; 561 SkMatrix fHiResMatrix;
562 /** fG_inv is the inverse of the rotational part of the total matrix.
563 * Used to set the direction of advances.
564 */
565 SkMatrix fG_inv;
574 enum Type { 566 enum Type {
575 kTrueType_Type, kBitmap_Type, 567 kTrueType_Type, kBitmap_Type,
576 } fType; 568 } fType;
577 TEXTMETRIC fTM; 569 TEXTMETRIC fTM;
578 }; 570 };
579 571
580 static float mul2float(SkScalar a, SkScalar b) {
581 return SkScalarToFloat(SkScalarMul(a, b));
582 }
583
584 static FIXED float2FIXED(float x) { 572 static FIXED float2FIXED(float x) {
585 return SkFixedToFIXED(SkFloatToFixed(x)); 573 return SkFixedToFIXED(SkFloatToFixed(x));
586 } 574 }
587 575
588 #define HIRES_TEXTSIZE 2048
589 #define HIRES_SHIFT 11
590 static inline SkFixed HiResToFixed(int value) {
591 return value << (16 - HIRES_SHIFT);
592 }
593
594 static bool needHiResMetrics(const SkScalar mat[2][2]) {
595 return mat[1][0] || mat[0][1];
596 }
597
598 static BYTE compute_quality(const SkScalerContext::Rec& rec) { 576 static BYTE compute_quality(const SkScalerContext::Rec& rec) {
599 switch (rec.fMaskFormat) { 577 switch (rec.fMaskFormat) {
600 case SkMask::kBW_Format: 578 case SkMask::kBW_Format:
601 return NONANTIALIASED_QUALITY; 579 return NONANTIALIASED_QUALITY;
602 case SkMask::kLCD16_Format: 580 case SkMask::kLCD16_Format:
603 case SkMask::kLCD32_Format: 581 case SkMask::kLCD32_Format:
604 return CLEARTYPE_QUALITY; 582 return CLEARTYPE_QUALITY;
605 default: 583 default:
606 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) { 584 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
607 return CLEARTYPE_QUALITY; 585 return CLEARTYPE_QUALITY;
(...skipping 12 matching lines...) Expand all
620 , fHiResFont(0) 598 , fHiResFont(0)
621 , fSC(0) 599 , fSC(0)
622 , fGlyphCount(-1) 600 , fGlyphCount(-1)
623 { 601 {
624 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface); 602 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
625 603
626 fDDC = ::CreateCompatibleDC(NULL); 604 fDDC = ::CreateCompatibleDC(NULL);
627 if (!fDDC) { 605 if (!fDDC) {
628 return; 606 return;
629 } 607 }
630
631 SetGraphicsMode(fDDC, GM_ADVANCED); 608 SetGraphicsMode(fDDC, GM_ADVANCED);
632 SetBkMode(fDDC, TRANSPARENT); 609 SetBkMode(fDDC, TRANSPARENT);
610
611 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
612 // A is the total matrix.
613 SkMatrix A;
614 fRec.getSingleMatrix(&A);
615 A.mapPoints(&h, 1);
633 616
634 // Scaling by the DPI is inconsistent with how Skia draws elsewhere 617 // Find the Given's matrix [[c, -s],[s, c]] which rotates the baseline vecto r h
635 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72); 618 // (where the baseline is mapped to) to the positive horizontal axis.
619 const SkScalar& a = h.fX;
620 const SkScalar& b = h.fY;
621 SkScalar c, s;
622 if (0 == b) {
623 c = SkDoubleToScalar(_copysign(SK_Scalar1, a));
624 s = 0;
625 } else if (0 == a) {
626 c = 0;
627 s = SkDoubleToScalar(-_copysign(SK_Scalar1, b));
628 } else if (SkScalarAbs(b) > SkScalarAbs(a)) {
629 SkScalar t = a / b;
630 SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), b));
631 s = -1 / u;
632 c = -s * t;
633 } else {
634 SkScalar t = b / a;
635 SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), a));
636 c = 1 / u;
637 s = -c * t;
638 }
639
640 // G is the Given's Matrix for A (rotational matrix such that GA[0][1] == 0) .
641 SkMatrix G;
642 G.setAll(c, -s, 0,
643 s, c, 0,
644 0, 0, SkScalarToPersp(SK_Scalar1));
645
646 // GA is the matrix A with rotation removed.
647 SkMatrix GA(G);
648 GA.preConcat(A);
649
650 // textSize is the actual device size we want (as opposed to the size the us er requested).
651 // If the scale is negative, this means the matrix will do the flip anyway.
652 SkScalar textSize = SkScalarAbs(SkScalarRoundToScalar(GA.get(SkMatrix::kMSca leY)));
653 if (textSize == 0) {
654 textSize = SK_Scalar1;
655 }
656
657 // sA is the total matrix A without the textSize (so GDI knows the text size separately).
658 // When this matrix is used with GetGlyphOutline, no further processing is n eeded.
659 SkMatrix sA(A);
660 SkScalar scale = SkScalarInvert(textSize);
661 sA.preScale(scale, scale); //remove text size
662
663 // GsA is the non-rotational part of A without the text height scale.
664 // This is what is used to find the magnitude of advances.
665 SkMatrix GsA(GA);
666 GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale.
667
668 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
669 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
670 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
671 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
672
673 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
674 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(Sk Matrix::kMTransX),
675 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(Sk Matrix::kMTransY),
676 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(Sk Matrix::kMPersp2));
677
636 LOGFONT lf = typeface->fLogFont; 678 LOGFONT lf = typeface->fLogFont;
637 lf.lfHeight = -gCanonicalTextSize; 679 lf.lfHeight = -SkScalarTruncToInt(textSize);
638 lf.lfQuality = compute_quality(fRec); 680 lf.lfQuality = compute_quality(fRec);
639 fFont = CreateFontIndirect(&lf); 681 fFont = CreateFontIndirect(&lf);
640 if (!fFont) { 682 if (!fFont) {
641 return; 683 return;
642 } 684 }
643 685
644 // if we're rotated, or want fractional widths, create a hires font
645 if (needHiResMetrics(fRec.fPost2x2)) {
646 lf.lfHeight = -HIRES_TEXTSIZE;
647 fHiResFont = CreateFontIndirect(&lf);
648 if (!fHiResFont) {
649 return;
650 }
651
652 fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
653 fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
654
655 // construct a matrix to go from HIRES logical units to our device units
656 fRec.getSingleMatrix(&fHiResMatrix);
657 SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
658 fHiResMatrix.preScale(scale, scale);
659 }
660 fSavefont = (HFONT)SelectObject(fDDC, fFont); 686 fSavefont = (HFONT)SelectObject(fDDC, fFont);
661 687
662 if (0 == GetTextMetrics(fDDC, &fTM)) { 688 if (0 == GetTextMetrics(fDDC, &fTM)) {
663 call_ensure_accessible(lf); 689 call_ensure_accessible(lf);
664 if (0 == GetTextMetrics(fDDC, &fTM)) { 690 if (0 == GetTextMetrics(fDDC, &fTM)) {
665 fTM.tmPitchAndFamily = TMPF_TRUETYPE; 691 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
666 } 692 }
667 } 693 }
668 // Used a logfont on a memory context, should never get a device font. 694 // Used a logfont on a memory context, should never get a device font.
669 // Therefore all TMPF_DEVICE will be PostScript fonts. 695 // Therefore all TMPF_DEVICE will be PostScript fonts.
670 696
671 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE must be set, 697 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE must be set,
672 // otherwise we have a vector FON, which we don't support. 698 // otherwise we have a vector FON, which we don't support.
673 // This was determined by testing with Type1 PFM/PFB and OpenTypeCFF OTF, 699 // This was determined by testing with Type1 PFM/PFB and OpenTypeCFF OTF,
674 // as well as looking at Wine bugs and sources. 700 // as well as looking at Wine bugs and sources.
675 SkASSERT(!(fTM.tmPitchAndFamily & TMPF_VECTOR) || 701 SkASSERT(!(fTM.tmPitchAndFamily & TMPF_VECTOR) ||
676 (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE))); 702 (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)));
677 703
678 XFORM xform; 704 XFORM xform;
679 if (fTM.tmPitchAndFamily & TMPF_VECTOR) { 705 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
680 // Truetype or PostScript. 706 // Truetype or PostScript.
681 // Stroked FON also gets here (TMPF_VECTOR), but we don't handle it. 707 // Stroked FON also gets here (TMPF_VECTOR), but we don't handle it.
682 fType = SkScalerContext_Windows::kTrueType_Type; 708 fType = SkScalerContext_Windows::kTrueType_Type;
683 fScale = fRec.fTextSize / gCanonicalTextSize;
684 709
685 // fPost2x2 is column-major, left handed (y down). 710 // fPost2x2 is column-major, left handed (y down).
686 // XFORM 2x2 is row-major, left handed (y down). 711 // XFORM 2x2 is row-major, left handed (y down).
687 xform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]); 712 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
688 xform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]); 713 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
689 xform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]); 714 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
690 xform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]); 715 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
691 xform.eDx = 0; 716 xform.eDx = 0;
692 xform.eDy = 0; 717 xform.eDy = 0;
693 718
694 // MAT2 is row major, right handed (y up). 719 // MAT2 is row major, right handed (y up).
695 fMat22.eM11 = float2FIXED(xform.eM11); 720 fMat22.eM11 = float2FIXED(xform.eM11);
696 fMat22.eM12 = float2FIXED(-xform.eM12); 721 fMat22.eM12 = float2FIXED(-xform.eM12);
697 fMat22.eM21 = float2FIXED(-xform.eM21); 722 fMat22.eM21 = float2FIXED(-xform.eM21);
698 fMat22.eM22 = float2FIXED(xform.eM22); 723 fMat22.eM22 = float2FIXED(xform.eM22);
699 724
700 if (needToRenderWithSkia(fRec)) { 725 if (needToRenderWithSkia(fRec)) {
701 this->forceGenerateImageFromPath(); 726 this->forceGenerateImageFromPath();
702 } 727 }
703 728
729 // Create a hires font if we need linear metrics.
730 if (this->isSubpixel()) {
731 OUTLINETEXTMETRIC otm;
732 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
733 if (0 == success) {
734 call_ensure_accessible(lf);
735 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
736 }
737 if (0 != success) {
738 lf.lfHeight = -SkToS32(otm.otmEMSquare);
739 fHiResFont = CreateFontIndirect(&lf);
740 if (!fHiResFont) {
741 return;
742 }
743
744 // construct a matrix to go from HIRES logical units to our devi ce units
745 fRec.getSingleMatrix(&fHiResMatrix);
746 SkScalar scale = SkScalarInvert(SkIntToScalar(otm.otmEMSquare));
747 fHiResMatrix.preScale(scale, scale);
748 }
749 }
750
704 } else { 751 } else {
705 // Assume bitmap 752 // Assume bitmap
706 fType = SkScalerContext_Windows::kBitmap_Type; 753 fType = SkScalerContext_Windows::kBitmap_Type;
707 fScale = SK_Scalar1;
708 754
709 xform.eM11 = 1.0f; 755 xform.eM11 = 1.0f;
710 xform.eM12 = 0.0f; 756 xform.eM12 = 0.0f;
711 xform.eM21 = 0.0f; 757 xform.eM21 = 0.0f;
712 xform.eM22 = 1.0f; 758 xform.eM22 = 1.0f;
713 xform.eDx = 0.0f; 759 xform.eDx = 0.0f;
714 xform.eDy = 0.0f; 760 xform.eDy = 0.0f;
715 761
716 // fPost2x2 is column-major, left handed (y down). 762 // fPost2x2 is column-major, left handed (y down).
717 // MAT2 is row major, right handed (y up). 763 // MAT2 is row major, right handed (y up).
718 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]); 764 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
719 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]); 765 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
720 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]); 766 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
721 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]); 767 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
722
723 lf.lfHeight = -SkScalarCeilToInt(fRec.fTextSize);
724 HFONT bitmapFont = CreateFontIndirect(&lf);
725 SelectObject(fDDC, bitmapFont);
726 ::DeleteObject(fFont);
727 fFont = bitmapFont;
728
729 if (0 == GetTextMetrics(fDDC, &fTM)) {
730 call_ensure_accessible(lf);
731 //if the following fails, we'll just draw at gCanonicalTextSize.
732 GetTextMetrics(fDDC, &fTM);
733 }
734 } 768 }
735 769
736 fOffscreen.init(fFont, xform); 770 fOffscreen.init(fFont, xform);
737 } 771 }
738 772
739 SkScalerContext_Windows::~SkScalerContext_Windows() { 773 SkScalerContext_Windows::~SkScalerContext_Windows() {
740 if (fDDC) { 774 if (fDDC) {
741 ::SelectObject(fDDC, fSavefont); 775 ::SelectObject(fDDC, fSavefont);
742 ::DeleteDC(fDDC); 776 ::DeleteDC(fDDC);
743 } 777 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 SkAssertResult(SUCCEEDED(ScriptShape( 820 SkAssertResult(SUCCEEDED(ScriptShape(
787 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs))); 821 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
788 } 822 }
789 return index; 823 return index;
790 } 824 }
791 825
792 void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) { 826 void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
793 this->generateMetrics(glyph); 827 this->generateMetrics(glyph);
794 } 828 }
795 829
830 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
796 void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { 831 void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
797 SkASSERT(fDDC); 832 SkASSERT(fDDC);
798 833
799 if (fType == SkScalerContext_Windows::kBitmap_Type) { 834 if (fType == SkScalerContext_Windows::kBitmap_Type) {
800 SIZE size; 835 SIZE size;
801 WORD glyphs = glyph->getGlyphID(0); 836 WORD glyphs = glyph->getGlyphID(0);
802 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) { 837 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
803 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth); 838 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
804 } else { 839 } else {
805 glyph->fWidth = SkToS16(size.cx); 840 glyph->fWidth = SkToS16(size.cx);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 glyph->fLeft -= 2; 894 glyph->fLeft -= 2;
860 } 895 }
861 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); 896 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
862 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY); 897 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY);
863 glyph->fRsbDelta = 0; 898 glyph->fRsbDelta = 0;
864 glyph->fLsbDelta = 0; 899 glyph->fLsbDelta = 0;
865 900
866 if (fHiResFont) { 901 if (fHiResFont) {
867 SelectObject(fDDC, fHiResFont); 902 SelectObject(fDDC, fHiResFont);
868 sk_bzero(&gm, sizeof(gm)); 903 sk_bzero(&gm, sizeof(gm));
869 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity); 904 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &gMat2Identity);
870 if (GDI_ERROR != status) { 905 if (GDI_ERROR != status) {
871 SkPoint advance; 906 SkPoint advance;
872 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gm CellIncY), &advance); 907 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gm CellIncY), &advance);
873 glyph->fAdvanceX = SkScalarToFixed(advance.fX); 908 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
874 glyph->fAdvanceY = SkScalarToFixed(advance.fY); 909 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
875 } 910 }
876 SelectObject(fDDC, fFont); 911 SelectObject(fDDC, fFont);
912 } else if (!isAxisAligned(this->fRec)) {
913 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA);
914 if (GDI_ERROR != status) {
915 SkPoint advance;
916 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIn cY), &advance);
917 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
918 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
919 }
877 } 920 }
878 } 921 }
879 922
880 void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPa int::FontMetrics* my) { 923 void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPa int::FontMetrics* my) {
881 if (!(mx || my)) { 924 if (!(mx || my)) {
882 return; 925 return;
883 } 926 }
884 927
885 if (mx) { 928 if (mx) {
886 sk_bzero(mx, sizeof(*mx)); 929 sk_bzero(mx, sizeof(*mx));
887 } 930 }
888 if (my) { 931 if (my) {
889 sk_bzero(my, sizeof(*my)); 932 sk_bzero(my, sizeof(*my));
890 } 933 }
891 934
892 SkASSERT(fDDC); 935 SkASSERT(fDDC);
893 936
894 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS 937 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
895 if (fType == SkScalerContext_Windows::kBitmap_Type) { 938 if (fType == SkScalerContext_Windows::kBitmap_Type) {
896 #endif 939 #endif
897 if (mx) { 940 if (mx) {
898 mx->fTop = SkIntToScalar(-fTM.tmAscent); 941 mx->fTop = SkIntToScalar(-fTM.tmAscent);
899 mx->fAscent = SkIntToScalar(-fTM.tmAscent); 942 mx->fAscent = SkIntToScalar(-fTM.tmAscent);
900 mx->fDescent = -SkIntToScalar(fTM.tmDescent); 943 mx->fDescent = SkIntToScalar(fTM.tmDescent);
901 mx->fBottom = SkIntToScalar(fTM.tmDescent); 944 mx->fBottom = SkIntToScalar(fTM.tmDescent);
902 mx->fLeading = SkIntToScalar(fTM.tmExternalLeading); 945 mx->fLeading = SkIntToScalar(fTM.tmExternalLeading);
903 } 946 }
904 947
905 if (my) { 948 if (my) {
906 my->fTop = SkIntToScalar(-fTM.tmAscent); 949 my->fTop = SkIntToScalar(-fTM.tmAscent);
907 my->fAscent = SkIntToScalar(-fTM.tmAscent); 950 my->fAscent = SkIntToScalar(-fTM.tmAscent);
908 my->fDescent = SkIntToScalar(-fTM.tmDescent); 951 my->fDescent = SkIntToScalar(fTM.tmDescent);
909 my->fBottom = SkIntToScalar(fTM.tmDescent); 952 my->fBottom = SkIntToScalar(fTM.tmDescent);
910 my->fLeading = SkIntToScalar(fTM.tmExternalLeading); 953 my->fLeading = SkIntToScalar(fTM.tmExternalLeading);
911 my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth); 954 my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
912 my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth); 955 my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
913 my->fXMin = 0; 956 my->fXMin = 0;
914 my->fXMax = my->fMaxCharWidth; 957 my->fXMax = my->fMaxCharWidth;
915 //my->fXHeight = 0; 958 //my->fXHeight = 0;
916 } 959 }
917 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS 960 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
918 return; 961 return;
919 } 962 }
920 #endif 963 #endif
921 964
922 OUTLINETEXTMETRIC otm; 965 OUTLINETEXTMETRIC otm;
923 966
924 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 967 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
925 if (GDI_ERROR == ret) { 968 if (0 == ret) {
926 LogFontTypeface::EnsureAccessible(this->getTypeface()); 969 LogFontTypeface::EnsureAccessible(this->getTypeface());
927 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 970 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
928 } 971 }
929 if (sizeof(otm) != ret) { 972 if (0 == ret) {
930 return; 973 return;
931 } 974 }
932 975
933 if (mx) { 976 if (mx) {
934 mx->fTop = -fScale * otm.otmrcFontBox.left; 977 mx->fTop = SkIntToScalar(-otm.otmrcFontBox.left);
935 mx->fAscent = -fScale * otm.otmAscent; 978 mx->fAscent = SkIntToScalar(-otm.otmAscent);
936 mx->fDescent = -fScale * otm.otmDescent; 979 mx->fDescent = SkIntToScalar(-otm.otmDescent);
937 mx->fBottom = fScale * otm.otmrcFontBox.right; 980 mx->fBottom = SkIntToScalar(otm.otmrcFontBox.right);
938 mx->fLeading = fScale * otm.otmLineGap; 981 mx->fLeading = SkIntToScalar(otm.otmLineGap);
939 } 982 }
940 983
941 if (my) { 984 if (my) {
942 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS 985 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
943 my->fTop = -fScale * otm.otmrcFontBox.top; 986 my->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
944 my->fAscent = -fScale * otm.otmAscent; 987 my->fAscent = SkIntToScalar(-otm.otmAscent);
945 my->fDescent = -fScale * otm.otmDescent; 988 my->fDescent = SkIntToScalar(-otm.otmDescent);
946 my->fBottom = -fScale * otm.otmrcFontBox.bottom; 989 my->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
947 my->fLeading = fScale * otm.otmLineGap; 990 my->fLeading = SkIntToScalar(otm.otmLineGap);
948 my->fAvgCharWidth = fScale * otm.otmTextMetrics.tmAveCharWidth; 991 my->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
949 my->fMaxCharWidth = fScale * otm.otmTextMetrics.tmMaxCharWidth; 992 my->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
950 my->fXMin = fScale * otm.otmrcFontBox.left; 993 my->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
951 my->fXMax = fScale * otm.otmrcFontBox.right; 994 my->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
952 #endif 995 #endif
953 my->fXHeight = fScale * otm.otmsXHeight; 996 my->fXHeight = SkIntToScalar(otm.otmsXHeight);
997
998 GLYPHMETRICS gm;
999 sk_bzero(&gm, sizeof(gm));
1000 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Id entity);
1001 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1002 my->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
1003 }
954 } 1004 }
955 } 1005 }
956 1006
957 //////////////////////////////////////////////////////////////////////////////// //////// 1007 //////////////////////////////////////////////////////////////////////////////// ////////
958 1008
1009 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
1010
959 static void build_power_table(uint8_t table[], float ee) { 1011 static void build_power_table(uint8_t table[], float ee) {
960 for (int i = 0; i < 256; i++) { 1012 for (int i = 0; i < 256; i++) {
961 float x = i / 255.f; 1013 float x = i / 255.f;
962 x = sk_float_pow(x, ee); 1014 x = sk_float_pow(x, ee);
963 int xx = SkScalarRound(SkFloatToScalar(x * 255)); 1015 int xx = SkScalarRound(SkFloatToScalar(x * 255));
964 table[i] = SkToU8(xx); 1016 table[i] = SkToU8(xx);
965 } 1017 }
966 } 1018 }
967 1019
968 /** 1020 /**
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1043 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); 1095 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1044 } 1096 }
1045 1097
1046 template<bool APPLY_PREBLEND> 1098 template<bool APPLY_PREBLEND>
1047 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR, 1099 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1048 const uint8_t* tableG, 1100 const uint8_t* tableG,
1049 const uint8_t* tableB) { 1101 const uint8_t* tableB) {
1050 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1102 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1051 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1103 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1052 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1104 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1105 #if SK_SHOW_TEXT_BLIT_COVERAGE
1106 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1107 #endif
1053 return SkPack888ToRGB16(r, g, b); 1108 return SkPack888ToRGB16(r, g, b);
1054 } 1109 }
1055 1110
1056 template<bool APPLY_PREBLEND> 1111 template<bool APPLY_PREBLEND>
1057 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR, 1112 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
1058 const uint8_t* tableG, 1113 const uint8_t* tableG,
1059 const uint8_t* tableB) { 1114 const uint8_t* tableB) {
1060 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1115 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1061 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1116 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1062 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1117 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1118 #if SK_SHOW_TEXT_BLIT_COVERAGE
1119 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1120 #endif
1063 return SkPackARGB32(0xFF, r, g, b); 1121 return SkPackARGB32(0xFF, r, g, b);
1064 } 1122 }
1065 1123
1066 // Is this GDI color neither black nor white? If so, we have to keep this 1124 // Is this GDI color neither black nor white? If so, we have to keep this
1067 // image as is, rather than smashing it down to a BW mask. 1125 // image as is, rather than smashing it down to a BW mask.
1068 // 1126 //
1069 // returns int instead of bool, since we don't want/have to pay to convert 1127 // returns int instead of bool, since we don't want/have to pay to convert
1070 // the zero/non-zero value into a bool 1128 // the zero/non-zero value into a bool
1071 static int is_not_black_or_white(SkGdiRGB c) { 1129 static int is_not_black_or_white(SkGdiRGB c) {
1072 // same as (but faster than) 1130 // same as (but faster than)
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1123 unsigned mask = 0x80; 1181 unsigned mask = 0x80;
1124 for (int i = 0; i < bitCount; i++) { 1182 for (int i = 0; i < bitCount; i++) {
1125 byte |= src[i] & mask; 1183 byte |= src[i] & mask;
1126 mask >>= 1; 1184 mask >>= 1;
1127 } 1185 }
1128 dst[byteCount] = byte; 1186 dst[byteCount] = byte;
1129 } 1187 }
1130 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); 1188 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1131 dst -= dstRB; 1189 dst -= dstRB;
1132 } 1190 }
1191 #if SK_SHOW_TEXT_BLIT_COVERAGE
1192 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1193 uint8_t* first = (uint8_t*)glyph.fImage;
1194 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1195 *first |= 1 << 7;
1196 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1197 }
1198 #endif
1133 } 1199 }
1134 1200
1135 template<bool APPLY_PREBLEND> 1201 template<bool APPLY_PREBLEND>
1136 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 1202 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1137 const SkGlyph& glyph, const uint8_t* table8) { 1203 const SkGlyph& glyph, const uint8_t* table8) {
1138 const size_t dstRB = glyph.rowBytes(); 1204 const size_t dstRB = glyph.rowBytes();
1139 const int width = glyph.fWidth; 1205 const int width = glyph.fWidth;
1140 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1206 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1141 1207
1142 for (int y = 0; y < glyph.fHeight; y++) { 1208 for (int y = 0; y < glyph.fHeight; y++) {
1143 for (int i = 0; i < width; i++) { 1209 for (int i = 0; i < width; i++) {
1144 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8); 1210 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1211 #if SK_SHOW_TEXT_BLIT_COVERAGE
1212 dst[i] = SkMax32(dst[i], 10);
1213 #endif
1145 } 1214 }
1146 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); 1215 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1147 dst -= dstRB; 1216 dst -= dstRB;
1148 } 1217 }
1149 } 1218 }
1150 1219
1151 template<bool APPLY_PREBLEND> 1220 template<bool APPLY_PREBLEND>
1152 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const Sk Glyph& glyph, 1221 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const Sk Glyph& glyph,
1153 const uint8_t* tableR, const uint8_t* tableG, const uin t8_t* tableB) { 1222 const uint8_t* tableR, const uint8_t* tableG, const uin t8_t* tableB) {
1154 const size_t dstRB = glyph.rowBytes(); 1223 const size_t dstRB = glyph.rowBytes();
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1231 int width = glyph.fWidth; 1300 int width = glyph.fWidth;
1232 size_t dstRB = glyph.rowBytes(); 1301 size_t dstRB = glyph.rowBytes();
1233 if (isBW) { 1302 if (isBW) {
1234 const uint8_t* src = (const uint8_t*)bits; 1303 const uint8_t* src = (const uint8_t*)bits;
1235 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * ds tRB); 1304 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * ds tRB);
1236 for (int y = 0; y < glyph.fHeight; y++) { 1305 for (int y = 0; y < glyph.fHeight; y++) {
1237 memcpy(dst, src, dstRB); 1306 memcpy(dst, src, dstRB);
1238 src += srcRB; 1307 src += srcRB;
1239 dst -= dstRB; 1308 dst -= dstRB;
1240 } 1309 }
1310 #if SK_SHOW_TEXT_BLIT_COVERAGE
1311 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1312 int bitCount = width & 7;
1313 uint8_t* first = (uint8_t*)glyph.fImage;
1314 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1315 *first |= 1 << 7;
1316 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1317 }
1318 #endif
1241 } else if (isAA) { 1319 } else if (isAA) {
1242 // since the caller may require A8 for maskfilters, we can't check for B W 1320 // since the caller may require A8 for maskfilters, we can't check for B W
1243 // ... until we have the caller tell us that explicitly 1321 // ... until we have the caller tell us that explicitly
1244 const SkGdiRGB* src = (const SkGdiRGB*)bits; 1322 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1245 if (fPreBlend.isApplicable()) { 1323 if (fPreBlend.isApplicable()) {
1246 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG); 1324 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
1247 } else { 1325 } else {
1248 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG); 1326 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
1249 } 1327 }
1250 } else { // LCD16 1328 } else { // LCD16
(...skipping 17 matching lines...) Expand all
1268 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ; 1346 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB) ;
1269 } else { 1347 } else {
1270 rgb_to_lcd32<false>(src, srcRB, glyph, 1348 rgb_to_lcd32<false>(src, srcRB, glyph,
1271 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB ); 1349 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB );
1272 } 1350 }
1273 } 1351 }
1274 } 1352 }
1275 } 1353 }
1276 } 1354 }
1277 1355
1278 void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { 1356 class GDIGlyphbufferPointIter {
1279 SkASSERT(&glyph && path); 1357 public:
1280 SkASSERT(fDDC); 1358 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1359 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1360 { }
1281 1361
1282 path->reset(); 1362 POINTFX next() {
1283 1363 nextHeader:
1284 GLYPHMETRICS gm; 1364 if (!fCurveIter.isSet()) {
1285 1365 const TTPOLYGONHEADER* header = fHeaderIter.next();
1286 // Out of all the fonts on a typical Windows box, 1366 SkASSERT(header);
1287 // 25% of glyphs require more than 2KB. 1367 fCurveIter.set(header);
1288 // 1% of glyphs require more than 4KB. 1368 const TTPOLYCURVE* curve = fCurveIter.next();
1289 // 0.01% of glyphs require more than 8KB. 1369 SkASSERT(curve);
1290 // 8KB is less than 1% of the normal 1MB stack on Windows. 1370 fPointIter.set(curve);
1291 // Note that some web fonts glyphs require more than 20KB. 1371 return header->pfxStart;
1292 static const DWORD BUFFERSIZE = (1 << 13);
1293 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1294
1295 const UINT flags = GGO_NATIVE | GGO_GLYPH_INDEX;
1296 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf, &fMat22);
1297 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even i f BUFFERSIZE > 0.
1298 // It has been verified that this does not involve a buffer overrun.
1299 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1300 // GDI_ERROR because the BUFFERSIZE was too small, or because the data w as not accessible.
1301 // When the data is not accessable GetGlyphOutlineW fails rather quickly ,
1302 // so just try to get the size. If that fails then ensure the data is ac cessible.
1303 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMa t22);
1304 if (GDI_ERROR == total_size) {
1305 LogFontTypeface::EnsureAccessible(this->getTypeface());
1306 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1307 if (GDI_ERROR == total_size) {
1308 SkASSERT(false);
1309 return;
1310 }
1311 } 1372 }
1312 1373
1313 glyphbuf.reset(total_size); 1374 const POINTFX* nextPoint = fPointIter.next();
1314 1375 if (NULL == nextPoint) {
1315 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, gl yphbuf, &fMat22); 1376 const TTPOLYCURVE* curve = fCurveIter.next();
1316 if (GDI_ERROR == ret) { 1377 if (NULL == curve) {
1317 LogFontTypeface::EnsureAccessible(this->getTypeface()); 1378 fCurveIter.set();
1318 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyp hbuf, &fMat22); 1379 goto nextHeader;
1319 if (GDI_ERROR == ret) { 1380 } else {
1320 SkASSERT(false); 1381 fPointIter.set(curve);
1321 return;
1322 } 1382 }
1383 nextPoint = fPointIter.next();
1384 SkASSERT(nextPoint);
1323 } 1385 }
1386 return *nextPoint;
1324 } 1387 }
1325 1388
1389 WORD currentCurveType() {
1390 return fPointIter.fCurveType;
1391 }
1392
1393 private:
1394 /** Iterates over all of the polygon headers in a glyphbuf. */
1395 class GDIPolygonHeaderIter {
1396 public:
1397 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1398 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1399 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_si ze))
1400 { }
1401
1402 const TTPOLYGONHEADER* next() {
1403 if (fCurPolygon >= fEndPolygon) {
1404 return NULL;
1405 }
1406 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1407 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurP olygon->cb);
1408 return thisPolygon;
1409 }
1410 private:
1411 const TTPOLYGONHEADER* fCurPolygon;
1412 const TTPOLYGONHEADER* fEndPolygon;
1413 };
1414
1415 /** Iterates over all of the polygon curves in a polygon header. */
1416 class GDIPolygonCurveIter {
1417 public:
1418 GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { }
1419
1420 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1421 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOL YGONHEADER)))
1422 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon-> cb))
1423 { }
1424
1425 bool isSet() { return fCurCurve != NULL; }
1426
1427 void set(const TTPOLYGONHEADER* curPolygon) {
1428 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOL YGONHEADER));
1429 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon-> cb);
1430 }
1431 void set() {
1432 fCurCurve = NULL;
1433 fEndCurve = NULL;
1434 }
1435
1436 const TTPOLYCURVE* next() {
1437 if (fCurCurve >= fEndCurve) {
1438 return NULL;
1439 }
1440 const TTPOLYCURVE* thisCurve = fCurCurve;
1441 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOL YCURVE(*fCurCurve));
1442 return thisCurve;
1443 }
1444 private:
1445 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1446 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1447 }
1448 const TTPOLYCURVE* fCurCurve;
1449 const TTPOLYCURVE* fEndCurve;
1450 };
1451
1452 /** Iterates over all of the polygon points in a polygon curve. */
1453 class GDIPolygonCurvePointIter {
1454 public:
1455 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(N ULL) { }
1456
1457 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1458 : fCurveType(curPolygon->wType)
1459 , fCurPoint(&curPolygon->apfx[0])
1460 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1461 { }
1462
1463 bool isSet() { return fCurPoint != NULL; }
1464
1465 void set(const TTPOLYCURVE* curPolygon) {
1466 fCurveType = curPolygon->wType;
1467 fCurPoint = &curPolygon->apfx[0];
1468 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1469 }
1470 void set() {
1471 fCurPoint = NULL;
1472 fEndPoint = NULL;
1473 }
1474
1475 const POINTFX* next() {
1476 if (fCurPoint >= fEndPoint) {
1477 return NULL;
1478 }
1479 const POINTFX* thisPoint = fCurPoint;
1480 ++fCurPoint;
1481 return thisPoint;
1482 }
1483
1484 WORD fCurveType;
1485 private:
1486 const POINTFX* fCurPoint;
1487 const POINTFX* fEndPoint;
1488 };
1489
1490 GDIPolygonHeaderIter fHeaderIter;
1491 GDIPolygonCurveIter fCurveIter;
1492 GDIPolygonCurvePointIter fPointIter;
1493 };
1494
1495 static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD t otal_size) {
1326 const uint8_t* cur_glyph = glyphbuf; 1496 const uint8_t* cur_glyph = glyphbuf;
1327 const uint8_t* end_glyph = glyphbuf + total_size; 1497 const uint8_t* end_glyph = glyphbuf + total_size;
1328 1498
1329 while (cur_glyph < end_glyph) { 1499 while (cur_glyph < end_glyph) {
1330 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; 1500 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1331 1501
1332 const uint8_t* end_poly = cur_glyph + th->cb; 1502 const uint8_t* end_poly = cur_glyph + th->cb;
1333 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); 1503 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1334 1504
1335 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)), 1505 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
(...skipping 28 matching lines...) Expand all
1364 } 1534 }
1365 } 1535 }
1366 // Advance past this TTPOLYCURVE. 1536 // Advance past this TTPOLYCURVE.
1367 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; 1537 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1368 } 1538 }
1369 cur_glyph += th->cb; 1539 cur_glyph += th->cb;
1370 path->close(); 1540 path->close();
1371 } 1541 }
1372 } 1542 }
1373 1543
1544 static void sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
1545 GDIGlyphbufferPointIter hintedYs) {
1546 const uint8_t* cur_glyph = glyphbuf;
1547 const uint8_t* end_glyph = glyphbuf + total_size;
1548
1549 while (cur_glyph < end_glyph) {
1550 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1551
1552 const uint8_t* end_poly = cur_glyph + th->cb;
1553 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1554
1555 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1556 SkFixedToScalar(-SkFIXEDToFixed(hintedYs.next().y)));
1557
1558 while (cur_poly < end_poly) {
1559 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1560
1561 if (pc->wType == TT_PRIM_LINE) {
1562 for (uint16_t i = 0; i < pc->cpfx; i++) {
1563 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)) ,
1564 SkFixedToScalar(-SkFIXEDToFixed(hintedYs.next() .y)));
1565 }
1566 }
1567
1568 if (pc->wType == TT_PRIM_QSPLINE) {
1569 POINTFX currentPoint = pc->apfx[0];
1570 POINTFX hintedY = hintedYs.next();
1571 // only take the hinted y if it wasn't flipped
1572 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1573 currentPoint.y = hintedY.y;
1574 }
1575 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through po ints in spline
1576 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always t he current point
1577 POINTFX pnt_c = pc->apfx[u+1];
1578 POINTFX hintedY = hintedYs.next();
1579 // only take the hinted y if it wasn't flipped
1580 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1581 pnt_c.y = hintedY.y;
1582 }
1583 currentPoint.x = pnt_c.x;
1584 currentPoint.y = pnt_c.y;
1585
1586 if (u < pc->cpfx - 2) { // If not on last spline, c ompute C
1587 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b .x),
1588 SkFIXEDToFixed(pnt_c .x)));
1589 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b .y),
1590 SkFIXEDToFixed(pnt_c .y)));
1591 }
1592
1593 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1594 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1595 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1596 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1597 }
1598 }
1599 // Advance past this TTPOLYCURVE.
1600 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1601 }
1602 cur_glyph += th->cb;
1603 path->close();
1604 }
1605 }
1606
1607 DWORD SkScalerContext_Windows::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
1608 SkAutoSTMalloc<BUFFERSIZE, uint8_ t>* glyphbuf)
1609 {
1610 GLYPHMETRICS gm;
1611
1612 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1613 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even i f BUFFERSIZE > 0.
1614 // It has been verified that this does not involve a buffer overrun.
1615 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1616 // GDI_ERROR because the BUFFERSIZE was too small, or because the data w as not accessible.
1617 // When the data is not accessable GetGlyphOutlineW fails rather quickly ,
1618 // so just try to get the size. If that fails then ensure the data is ac cessible.
1619 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMa t22);
1620 if (GDI_ERROR == total_size) {
1621 LogFontTypeface::EnsureAccessible(this->getTypeface());
1622 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1623 if (GDI_ERROR == total_size) {
1624 SkASSERT(false);
1625 return 0;
1626 }
1627 }
1628
1629 glyphbuf->reset(total_size);
1630
1631 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, gl yphbuf->get(), &fMat22);
1632 if (GDI_ERROR == ret) {
1633 LogFontTypeface::EnsureAccessible(this->getTypeface());
1634 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyp hbuf->get(), &fMat22);
1635 if (GDI_ERROR == ret) {
1636 SkASSERT(false);
1637 return 0;
1638 }
1639 }
1640 }
1641 return total_size;
1642 }
1643
1644 void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
1645 SkASSERT(&glyph && path);
1646 SkASSERT(fDDC);
1647
1648 path->reset();
1649
1650 // Out of all the fonts on a typical Windows box,
1651 // 25% of glyphs require more than 2KB.
1652 // 1% of glyphs require more than 4KB.
1653 // 0.01% of glyphs require more than 8KB.
1654 // 8KB is less than 1% of the normal 1MB stack on Windows.
1655 // Note that some web fonts glyphs require more than 20KB.
1656 //static const DWORD BUFFERSIZE = (1 << 13);
1657
1658 //GDI only uses hinted outlines when axis aligned.
1659 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1660 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPain t::kSlight_Hinting){
1661 format |= GGO_UNHINTED;
1662 }
1663 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1664 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1665 if (0 == total_size) {
1666 return;
1667 }
1668
1669 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1670 sk_path_from_gdi_path(path, glyphbuf, total_size);
1671 } else {
1672 //GDI only uses hinted outlines when axis aligned.
1673 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1674
1675 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1676 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf );
1677 if (0 == hinted_total_size) {
1678 return;
1679 }
1680
1681 sk_path_from_gdi_paths(path, glyphbuf, total_size,
1682 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_to tal_size));
1683 }
1684 }
1685
1374 static void logfont_for_name(const char* familyName, LOGFONT* lf) { 1686 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1375 sk_bzero(lf, sizeof(LOGFONT)); 1687 sk_bzero(lf, sizeof(LOGFONT));
1376 #ifdef UNICODE 1688 #ifdef UNICODE
1377 // Get the buffer size needed first. 1689 // Get the buffer size needed first.
1378 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, 1690 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1379 -1, NULL, 0); 1691 -1, NULL, 0);
1380 // Allocate a buffer (str_len already has terminating null 1692 // Allocate a buffer (str_len already has terminating null
1381 // accounted for). 1693 // accounted for).
1382 wchar_t *wideFamilyName = new wchar_t[str_len]; 1694 wchar_t *wideFamilyName = new wchar_t[str_len];
1383 // Now actually convert the string. 1695 // Now actually convert the string.
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
1788 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) 2100 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
1789 { 2101 {
1790 rec->fMaskFormat = SkMask::kA8_Format; 2102 rec->fMaskFormat = SkMask::kA8_Format;
1791 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag; 2103 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
1792 } 2104 }
1793 2105
1794 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | 2106 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1795 SkScalerContext::kAutohinting_Flag | 2107 SkScalerContext::kAutohinting_Flag |
1796 SkScalerContext::kEmbeddedBitmapText_Flag | 2108 SkScalerContext::kEmbeddedBitmapText_Flag |
1797 SkScalerContext::kEmbolden_Flag | 2109 SkScalerContext::kEmbolden_Flag |
1798 SkScalerContext::kSubpixelPositioning_Flag |
1799 SkScalerContext::kLCD_BGROrder_Flag | 2110 SkScalerContext::kLCD_BGROrder_Flag |
1800 SkScalerContext::kLCD_Vertical_Flag; 2111 SkScalerContext::kLCD_Vertical_Flag;
1801 rec->fFlags &= ~flagsWeDontSupport; 2112 rec->fFlags &= ~flagsWeDontSupport;
1802 2113
1803 SkPaint::Hinting h = rec->getHinting(); 2114 SkPaint::Hinting h = rec->getHinting();
1804
1805 // I think we can support no-hinting, if we get hires outlines and just
1806 // use skia to rasterize into a gray-scale mask...
1807 #if 0
1808 switch (h) { 2115 switch (h) {
1809 case SkPaint::kNo_Hinting: 2116 case SkPaint::kNo_Hinting:
2117 break;
1810 case SkPaint::kSlight_Hinting: 2118 case SkPaint::kSlight_Hinting:
1811 h = SkPaint::kNo_Hinting; 2119 // Only do slight hinting when axis aligned.
2120 if (!isAxisAligned(*rec)) {
2121 h = SkPaint::kNo_Hinting;
2122 }
1812 break; 2123 break;
1813 case SkPaint::kNormal_Hinting: 2124 case SkPaint::kNormal_Hinting:
1814 case SkPaint::kFull_Hinting: 2125 case SkPaint::kFull_Hinting:
1815 h = SkPaint::kNormal_Hinting; 2126 h = SkPaint::kNormal_Hinting;
1816 break; 2127 break;
1817 default: 2128 default:
1818 SkDEBUGFAIL("unknown hinting"); 2129 SkDEBUGFAIL("unknown hinting");
1819 } 2130 }
1820 #else 2131 //TODO: if this is a bitmap font, squash hinting and subpixel.
1821 h = SkPaint::kNormal_Hinting;
1822 #endif
1823 rec->setHinting(h); 2132 rec->setHinting(h);
1824 2133
1825 // turn this off since GDI might turn A8 into BW! Need a bigger fix. 2134 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
1826 #if 0 2135 #if 0
1827 // Disable LCD when rotated, since GDI's output is ugly 2136 // Disable LCD when rotated, since GDI's output is ugly
1828 if (isLCD(*rec) && !isAxisAligned(*rec)) { 2137 if (isLCD(*rec) && !isAxisAligned(*rec)) {
1829 rec->fMaskFormat = SkMask::kA8_Format; 2138 rec->fMaskFormat = SkMask::kA8_Format;
1830 } 2139 }
1831 #endif 2140 #endif
1832 2141
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
2003 return this->createFromStream(stream); 2312 return this->createFromStream(stream);
2004 } 2313 }
2005 2314
2006 private: 2315 private:
2007 SkTDArray<ENUMLOGFONTEX> fLogFontArray; 2316 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2008 }; 2317 };
2009 2318
2010 SkFontMgr* SkFontMgr::Factory() { 2319 SkFontMgr* SkFontMgr::Factory() {
2011 return SkNEW(SkFontMgrGDI); 2320 return SkNEW(SkFontMgrGDI);
2012 } 2321 }
OLDNEW
« no previous file with comments | « src/core/SkScalerContext.cpp ('k') | tools/generate_fir_coeff.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698