OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |